mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-09 14:32:53 +00:00
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:
committed by
Andreas Rumpf
parent
71b1377be9
commit
88a5e9d88c
@@ -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 = @[]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
34
tests/vm/tstring_openarray.nim
Normal file
34
tests/vm/tstring_openarray.nim
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
# tests various bug when passing string to openArray argument in VM.
|
||||
# bug #6086
|
||||
proc map*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}):
|
||||
seq[S]{.inline.} =
|
||||
# map inlined from sequtils
|
||||
newSeq(result, data.len)
|
||||
for i in 0..data.len-1: result[i] = op(data[i])
|
||||
|
||||
|
||||
proc set_all[T](s: var openArray[T]; val: T) =
|
||||
for i in 0..<s.len:
|
||||
s[i] = val
|
||||
|
||||
proc test() =
|
||||
var a0 = "hello_world"
|
||||
var a1 = [1,2,3,4,5,6,7,8,9]
|
||||
var a2 = @[1,2,3,4,5,6,7,8,9]
|
||||
a0.set_all('i')
|
||||
a1.set_all(4)
|
||||
a2.set_all(4)
|
||||
doAssert a0 == "iiiiiiiiiii"
|
||||
doAssert a1 == [4,4,4,4,4,4,4,4,4]
|
||||
doAssert a2 == @[4,4,4,4,4,4,4,4,4]
|
||||
|
||||
const constval0 = "hello".map(proc(x: char): char = x)
|
||||
const constval1 = [1,2,3,4].map(proc(x: int): int = x)
|
||||
|
||||
doAssert("hello".map(proc(x: char): char = x) == constval0)
|
||||
doAssert([1,2,3,4].map(proc(x: int): int = x) == constval1)
|
||||
|
||||
test()
|
||||
static:
|
||||
test()
|
||||
Reference in New Issue
Block a user