fixes #15939, fixes #15464, fixes #16169, fixes #16226 VM now supports addr(mystring[ind]) (index + index assignment) (#15987)
* fix #15939, fix #15464 VM now supports `addr(mystring[ind])` (index + index assignment), var char return etc * cleanups * cstring tests * add test for bug #15464 * improve test coverage
This commit is contained in:
parent
b1554cfeb5
commit
c731f7ab14
5 changed files with 94 additions and 5 deletions
|
|
@ -69,6 +69,7 @@
|
||||||
|
|
||||||
- Added `nim --eval:cmd` to evaluate a command directly, see `nim --help`.
|
- Added `nim --eval:cmd` to evaluate a command directly, see `nim --help`.
|
||||||
|
|
||||||
|
- VM now supports `addr(mystring[ind])` (index + index assignment)
|
||||||
|
|
||||||
|
|
||||||
## Tool changes
|
## Tool changes
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import
|
||||||
|
|
||||||
from semfold import leValueConv, ordinalValToString
|
from semfold import leValueConv, ordinalValToString
|
||||||
from evaltempl import evalTemplate
|
from evaltempl import evalTemplate
|
||||||
|
from magicsys import getSysType
|
||||||
|
|
||||||
const
|
const
|
||||||
traceCode = defined(nimVMDebug)
|
traceCode = defined(nimVMDebug)
|
||||||
|
|
@ -123,7 +124,7 @@ proc derefPtrToReg(address: BiggestInt, typ: PType, r: var TFullReg, isAssign: b
|
||||||
else:
|
else:
|
||||||
r.ensureKind(rkind)
|
r.ensureKind(rkind)
|
||||||
let val = cast[ptr T](address)[]
|
let val = cast[ptr T](address)[]
|
||||||
when T is SomeInteger:
|
when T is SomeInteger | char:
|
||||||
r.field = BiggestInt(val)
|
r.field = BiggestInt(val)
|
||||||
else:
|
else:
|
||||||
r.field = val
|
r.field = val
|
||||||
|
|
@ -131,6 +132,7 @@ proc derefPtrToReg(address: BiggestInt, typ: PType, r: var TFullReg, isAssign: b
|
||||||
|
|
||||||
## see also typeinfo.getBiggestInt
|
## see also typeinfo.getBiggestInt
|
||||||
case typ.kind
|
case typ.kind
|
||||||
|
of tyChar: fun(intVal, char, rkInt)
|
||||||
of tyInt: fun(intVal, int, rkInt)
|
of tyInt: fun(intVal, int, rkInt)
|
||||||
of tyInt8: fun(intVal, int8, rkInt)
|
of tyInt8: fun(intVal, int8, rkInt)
|
||||||
of tyInt16: fun(intVal, int16, rkInt)
|
of tyInt16: fun(intVal, int16, rkInt)
|
||||||
|
|
@ -677,6 +679,23 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
regs[ra].intVal = s[idx].ord
|
regs[ra].intVal = s[idx].ord
|
||||||
else:
|
else:
|
||||||
stackTrace(c, tos, pc, formatErrorIndexBound(idx, s.len-1))
|
stackTrace(c, tos, pc, formatErrorIndexBound(idx, s.len-1))
|
||||||
|
of opcLdStrIdxAddr:
|
||||||
|
# a = addr(b[c]); similar to opcLdArrAddr
|
||||||
|
decodeBC(rkNode)
|
||||||
|
if regs[rc].intVal > high(int):
|
||||||
|
stackTrace(c, tos, pc, formatErrorIndexBound(regs[rc].intVal, high(int)))
|
||||||
|
let idx = regs[rc].intVal.int
|
||||||
|
let s = regs[rb].node.strVal.addr # or `byaddr`
|
||||||
|
if idx <% s[].len:
|
||||||
|
# `makePtrType` not accessible from vm.nim
|
||||||
|
let typ = newType(tyPtr, nextId c.idgen, c.module.owner)
|
||||||
|
typ.add getSysType(c.graph, c.debug[pc], tyChar)
|
||||||
|
let node = newNodeIT(nkIntLit, c.debug[pc], typ) # xxx nkPtrLit
|
||||||
|
node.intVal = cast[int](s[][idx].addr)
|
||||||
|
node.flags.incl nfIsPtr
|
||||||
|
regs[ra].node = node
|
||||||
|
else:
|
||||||
|
stackTrace(c, tos, pc, formatErrorIndexBound(idx, s[].len-1))
|
||||||
of opcWrArr:
|
of opcWrArr:
|
||||||
# a[b] = c
|
# a[b] = c
|
||||||
decodeBC(rkNode)
|
decodeBC(rkNode)
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,7 @@ type
|
||||||
opcWrDeref,
|
opcWrDeref,
|
||||||
opcWrStrIdx,
|
opcWrStrIdx,
|
||||||
opcLdStrIdx, # a = b[c]
|
opcLdStrIdx, # a = b[c]
|
||||||
|
opcLdStrIdxAddr, # a = addr(b[c])
|
||||||
|
|
||||||
opcAddInt,
|
opcAddInt,
|
||||||
opcAddImmInt,
|
opcAddImmInt,
|
||||||
|
|
|
||||||
|
|
@ -1654,8 +1654,8 @@ proc genArrAccessOpcode(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
|
||||||
let a = c.genx(n[0], flags)
|
let a = c.genx(n[0], flags)
|
||||||
let b = c.genIndex(n[1], n[0].typ)
|
let b = c.genIndex(n[1], n[0].typ)
|
||||||
if dest < 0: dest = c.getTemp(n.typ)
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
if opc == opcLdArr and {gfNodeAddr} * flags != {}:
|
if opc in {opcLdArrAddr, opcLdStrIdxAddr} and gfNodeAddr in flags:
|
||||||
c.gABC(n, opcLdArrAddr, dest, a, b)
|
c.gABC(n, opc, dest, a, b)
|
||||||
elif needsRegLoad():
|
elif needsRegLoad():
|
||||||
var cc = c.getTemp(n.typ)
|
var cc = c.getTemp(n.typ)
|
||||||
c.gABC(n, opc, cc, a, b)
|
c.gABC(n, opc, cc, a, b)
|
||||||
|
|
@ -1749,11 +1749,13 @@ proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||||
proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||||
let arrayType = n[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind
|
let arrayType = n[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind
|
||||||
if arrayType in {tyString, tyCString}:
|
if arrayType in {tyString, tyCString}:
|
||||||
genArrAccessOpcode(c, n, dest, opcLdStrIdx, {})
|
let opc = if gfNodeAddr in flags: opcLdStrIdxAddr else: opcLdStrIdx
|
||||||
|
genArrAccessOpcode(c, n, dest, opc, flags)
|
||||||
elif arrayType == tyTypeDesc:
|
elif arrayType == tyTypeDesc:
|
||||||
c.genTypeLit(n.typ, dest)
|
c.genTypeLit(n.typ, dest)
|
||||||
else:
|
else:
|
||||||
genArrAccessOpcode(c, n, dest, opcLdArr, flags)
|
let opc = if gfNodeAddr in flags: opcLdArrAddr else: opcLdArr
|
||||||
|
genArrAccessOpcode(c, n, dest, opc, flags)
|
||||||
|
|
||||||
proc getNullValueAux(t: PType; obj: PNode, result: PNode; conf: ConfigRef; currPosition: var int) =
|
proc getNullValueAux(t: PType; obj: PNode, result: PNode; conf: ConfigRef; currPosition: var int) =
|
||||||
if t != nil and t.len > 0 and t[0] != nil:
|
if t != nil and t.len > 0 and t[0] != nil:
|
||||||
|
|
|
||||||
|
|
@ -196,10 +196,76 @@ template test14339() = # bug #14339
|
||||||
when not defined(js): # pending bug #16003
|
when not defined(js): # pending bug #16003
|
||||||
doAssert a.val == 5
|
doAssert a.val == 5
|
||||||
|
|
||||||
|
template testStatic15464() = # bug #15464
|
||||||
|
proc access(s: var seq[char], i: int): var char = s[i]
|
||||||
|
proc access(s: var string, i: int): var char = s[i]
|
||||||
|
static:
|
||||||
|
var s = @['a', 'b', 'c']
|
||||||
|
access(s, 2) = 'C'
|
||||||
|
doAssert access(s, 2) == 'C'
|
||||||
|
static:
|
||||||
|
var s = "abc"
|
||||||
|
access(s, 2) = 'C'
|
||||||
|
doAssert access(s, 2) == 'C'
|
||||||
|
|
||||||
|
proc test15464() = # bug #15464 (v2)
|
||||||
|
proc access(s: var seq[char], i: int): var char = s[i]
|
||||||
|
proc access(s: var string, i: int): var char = s[i]
|
||||||
|
block:
|
||||||
|
var s = @['a', 'b', 'c']
|
||||||
|
access(s, 2) = 'C'
|
||||||
|
doAssert access(s, 2) == 'C'
|
||||||
|
block:
|
||||||
|
var s = "abc"
|
||||||
|
access(s, 2) = 'C'
|
||||||
|
doAssert access(s, 2) == 'C'
|
||||||
|
|
||||||
|
block: # bug #15939
|
||||||
|
block:
|
||||||
|
const foo = "foo"
|
||||||
|
proc proc1(s: var string) =
|
||||||
|
if s[^1] notin {'a'..'z'}:
|
||||||
|
s = ""
|
||||||
|
proc proc2(f: string): string =
|
||||||
|
result = f
|
||||||
|
proc1(result)
|
||||||
|
const bar = proc2(foo)
|
||||||
|
doAssert bar == "foo"
|
||||||
|
|
||||||
|
proc test15939() = # bug #15939 (v2)
|
||||||
|
template fn(a) =
|
||||||
|
let pa = a[0].addr
|
||||||
|
doAssert pa != nil
|
||||||
|
doAssert pa[] == 'a'
|
||||||
|
pa[] = 'x'
|
||||||
|
doAssert pa[] == 'x'
|
||||||
|
doAssert a == "xbc"
|
||||||
|
when not defined js: # otherwise overflows
|
||||||
|
let pa2 = cast[ptr char](cast[int](pa) + 1)
|
||||||
|
doAssert pa2[] == 'b'
|
||||||
|
pa2[] = 'B'
|
||||||
|
doAssert a == "xBc"
|
||||||
|
|
||||||
|
# mystring[ind].addr
|
||||||
|
var a = "abc"
|
||||||
|
fn(a)
|
||||||
|
|
||||||
|
# mycstring[ind].addr
|
||||||
|
template cstringTest =
|
||||||
|
var a2 = "abc"
|
||||||
|
var b2 = a2.cstring
|
||||||
|
fn(b2)
|
||||||
|
when nimvm: cstringTest()
|
||||||
|
else: # can't take address of cstring element in js
|
||||||
|
when not defined(js): cstringTest()
|
||||||
|
|
||||||
template main =
|
template main =
|
||||||
# xxx wrap all other tests here like that so they're also tested in VM
|
# xxx wrap all other tests here like that so they're also tested in VM
|
||||||
test14420()
|
test14420()
|
||||||
test14339()
|
test14339()
|
||||||
|
test15464()
|
||||||
|
test15939()
|
||||||
|
|
||||||
|
testStatic15464()
|
||||||
static: main()
|
static: main()
|
||||||
main()
|
main()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue