diff options
author | Parashurama <Rhagdamaziel@ymail.com> | 2017-09-15 13:35:57 +0200 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2017-09-15 13:35:57 +0200 |
commit | 88a5e9d88ccc0a48daa2710e88d2efb8a7ae6468 (patch) | |
tree | fc9a16fad9b80cf34257d286e90f003f22630ae9 /compiler | |
parent | 71b1377be918e10e9a279764747adbab73310688 (diff) | |
download | Nim-88a5e9d88ccc0a48daa2710e88d2efb8a7ae6468.tar.gz |
Fix operations on string as openarray in VM. (#6257)
* fix openarray.len for string as openArray in VM. * fix openarray[idx] for string as openArray in VM. * fix openarray[idx]=val for string as openArray in VM. * add tests for passing string as openArray in VM. * fix issue with NimNode.len NimNode.len was also returning len for string literals. also fix logic bug in if/elif chain.
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 6 | ||||
-rw-r--r-- | compiler/vm.nim | 28 | ||||
-rw-r--r-- | compiler/vmdef.nim | 3 | ||||
-rw-r--r-- | compiler/vmgen.nim | 6 |
4 files changed, 35 insertions, 8 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 2e6da06c6..92abbb0ab 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1006,6 +1006,12 @@ proc safeLen*(n: PNode): int {.inline.} = if n.kind in {nkNone..nkNilLit} or isNil(n.sons): result = 0 else: result = len(n.sons) +proc safeArrLen*(n: PNode): int {.inline.} = + ## works for array-like objects (strings passed as openArray in VM). + if n.kind in {nkStrLit..nkTripleStrLit}:result = len(n.strVal) + elif n.kind in {nkNone..nkFloat128Lit}: result = 0 + else: result = len(n) + proc add*(father, son: PNode) = assert son != nil if isNil(father.sons): father.sons = @[] diff --git a/compiler/vm.nim b/compiler/vm.nim index 93cf66c05..8d4359db9 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -508,7 +508,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = stackTrace(c, tos, pc, errIndexOutOfBounds) let idx = regs[rc].intVal.int let src = regs[rb].node - if src.kind notin {nkEmpty..nkNilLit} and idx <% src.len: + if src.kind in {nkStrLit..nkTripleStrLit}: + if idx <% src.strVal.len: + regs[ra].node = newNodeI(nkCharLit, c.debug[pc]) + regs[ra].node.intVal = src.strVal[idx].ord + else: + stackTrace(c, tos, pc, errIndexOutOfBounds) + elif src.kind notin {nkEmpty..nkFloat128Lit} and idx <% src.len: regs[ra].node = src.sons[idx] else: stackTrace(c, tos, pc, errIndexOutOfBounds) @@ -526,8 +532,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = # a[b] = c decodeBC(rkNode) let idx = regs[rb].intVal.int - if idx <% regs[ra].node.len: - putIntoNode(regs[ra].node.sons[idx], regs[rc]) + let arr = regs[ra].node + if arr.kind in {nkStrLit..nkTripleStrLit}: + if idx <% arr.strVal.len: + arr.strVal[idx] = chr(regs[rc].intVal) + else: + stackTrace(c, tos, pc, errIndexOutOfBounds) + elif idx <% arr.len: + putIntoNode(arr.sons[idx], regs[rc]) else: stackTrace(c, tos, pc, errIndexOutOfBounds) of opcLdObj: @@ -641,8 +653,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcLenSeq: decodeBImm(rkInt) #assert regs[rb].kind == nkBracket - # also used by mNLen: - regs[ra].intVal = regs[rb].node.safeLen - imm + let high = (imm and 1) # discard flags + if (imm and nimNodeFlag) != 0: + # used by mNLen (NimNode.len) + regs[ra].intVal = regs[rb].node.safeLen - high + else: + # safeArrLen also return string node len + # used when string is passed as openArray in VM + regs[ra].intVal = regs[rb].node.safeArrLen - high of opcLenStr: decodeBImm(rkInt) assert regs[rb].kind == rkNode diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 7e1309e0a..5395d4bad 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -234,6 +234,9 @@ const slotSomeTemp* = slotTempUnknown relativeJumps* = {opcTJmp, opcFJmp, opcJmp, opcJmpBack} +# flag is used to signal opcSeqLen if node is NimNode. +const nimNodeFlag* = 16 + template opcode*(x: TInstr): TOpcode = TOpcode(x.uint32 and 0xff'u32) template regA*(x: TInstr): TRegister = TRegister(x.uint32 shr 8'u32 and 0xff'u32) template regB*(x: TInstr): TRegister = TRegister(x.uint32 shr 16'u32 and 0xff'u32) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index dbb8c9dcd..3d291d8a2 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -625,10 +625,10 @@ proc genUnaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = c.gABC(n, opc, dest, tmp) c.freeTemp(tmp) -proc genUnaryABI(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = +proc genUnaryABI(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; imm: BiggestInt=0) = let tmp = c.genx(n.sons[1]) if dest < 0: dest = c.getTemp(n.typ) - c.gABI(n, opc, dest, tmp, 0) + c.gABI(n, opc, dest, tmp, imm) c.freeTemp(tmp) proc genBinaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = @@ -1021,7 +1021,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = c.freeTemp(tmp) of mSlurp: genUnaryABC(c, n, dest, opcSlurp) of mStaticExec: genBinaryABCD(c, n, dest, opcGorge) - of mNLen: genUnaryABI(c, n, dest, opcLenSeq) + of mNLen: genUnaryABI(c, n, dest, opcLenSeq, nimNodeFlag) of mGetImpl: genUnaryABC(c, n, dest, opcGetImpl) of mNChild: genBinaryABC(c, n, dest, opcNChild) of mNSetChild, mNDel: |