summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorParashurama <Rhagdamaziel@ymail.com>2017-09-15 13:35:57 +0200
committerAndreas Rumpf <rumpf_a@web.de>2017-09-15 13:35:57 +0200
commit88a5e9d88ccc0a48daa2710e88d2efb8a7ae6468 (patch)
treefc9a16fad9b80cf34257d286e90f003f22630ae9 /compiler
parent71b1377be918e10e9a279764747adbab73310688 (diff)
downloadNim-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.nim6
-rw-r--r--compiler/vm.nim28
-rw-r--r--compiler/vmdef.nim3
-rw-r--r--compiler/vmgen.nim6
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: