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.
This commit is contained in:
Parashurama 2017-09-15 13:35:57 +02:00 • committed by Andreas Rumpf
commit 88a5e9d88c
5 changed files with 69 additions and 8 deletions

View file

@ -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 = @[]

View file

@ -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

View file

@ -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)

View file

@ -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: