diff options
Diffstat (limited to 'tests/vm')
104 files changed, 5077 insertions, 0 deletions
diff --git a/tests/vm/meta.nim b/tests/vm/meta.nim new file mode 100644 index 000000000..32a441f27 --- /dev/null +++ b/tests/vm/meta.nim @@ -0,0 +1,240 @@ +# +# meta.nim +# + +import tables +import macros + +type + NodeSeq* = seq[NimNode] + Ident* = tuple[name: string, exported: bool] + Bracket* = seq[Ident] + Field* = tuple[identifier: Ident, type_name: string, default: string] + FieldSeq* = seq[Field] + TypeDef* = object + identifier*: Ident + fields*: FieldSeq + is_ref*: bool + object_type*: string + base_type*: string + TypeDefSeq* = seq[TypeDef] + Proc* = tuple[identifier: Ident, params: FieldSeq, + returns: Ident, generics: FieldSeq, body: NimNode] + ProcSeq* = seq[Proc] + +# Ident procs +proc newIdent*(name: string, exported = false): Ident = + result.name = name + result.exported = exported + +proc newIdent*(node: NimNode): Ident = + case node.kind: + of nnkPostfix: + result = newIdent(node[1]) + result.exported = true + of nnkIdent, nnkSym: + result.name = $(node) + else: + let msg = "newIdent cannot initialize from node kind: " & $(node.kind) + raise newException(ValueError, msg) + +proc render*(i: Ident): NimNode {.compileTime.} = + if i.name == "": + return newNimNode(nnkEmpty) + + if i.exported: + result = newNimNode(nnkPostfix) + result.add(ident "*") + result.add(ident i.name) + else: + result = ident i.name + +proc `$`*(identifier: Ident): string = identifier.name + +converter toString*(x: Ident): string = x.name + +proc newBracket*(node: NimNode): Bracket = + result = @[] + case node.kind: + of nnkBracket: + for child in node: + if child.kind != nnkIdent: + let msg = "Bracket members can only be nnkIdent not kind: " & $(node.kind) + raise newException(ValueError, msg) + result.add(newIdent(child)) + else: + let msg = "newBracket must initialize from node kind nnkBracket not: " & $(node.kind) + raise newException(ValueError, msg) + +# Field procs +proc newField*(identifier: Ident, type_name: string, default: string = ""): Field = + result.identifier = identifier + result.type_name = type_name + result.default = default + +proc newField*(node: NimNode): Field = + case node.kind: + of nnkIdentDefs: + if node.len > 3: + let msg = "newField cannot initialize from nnkIdentDefs with multiple names" + raise newException(ValueError, msg) + result.identifier = newIdent(node[0]) + result.type_name = $(node[1]) + case node[2].kind: + of nnkIdent: + result.default = $(node[2]) + else: + result.default = "" + else: + let msg = "newField cannot initialize from node kind: " & $(node.kind) + raise newException(ValueError, msg) + +# FieldSeq procs +proc newFieldSeq*(node: NimNode): FieldSeq = + result = @[] + case node.kind: + of nnkIdentDefs: + let + type_name = $(node[node.len - 2]) + default_node = node[node.len - 1] + var default: string + case default_node.kind: + of nnkIdent: + default = $(default_node) + else: + default = "" + for i in 0..node.len - 3: + let name = newIdent(node[i]) + result.add(newField(name, type_name, default)) + of nnkRecList, nnkVarSection, nnkGenericParams: + for child in node: + result = result & newFieldSeq(child) + else: + let msg = "newFieldSeq cannot initialize from node kind: " & $(node.kind) + raise newException(ValueError, msg) + +proc render*(f: Field): NimNode {.compileTime.} = + let identifier = f.identifier.render() + let type_name = if f.type_name != "": ident(f.type_name) else: newEmptyNode() + let default = if f.default != "": ident(f.default) else: newEmptyNode() + newIdentDefs(identifier, type_name, default) + +proc render*(fs: FieldSeq): NimNode {.compileTime.} = + result = newNimNode(nnkRecList) + for field in fs: + result.add(field.render()) + +# TypeDef procs +proc newTypeDef*(identifier: Ident, is_ref = false, + object_type = "object", + base_type: string = ""): TypeDef {.compileTime.} = + result.identifier = identifier + result.fields = @[] + result.is_ref = is_ref + result.object_type = "object" + result.base_type = base_type + +proc newTypeDef*(node: NimNode): TypeDef {.compileTime.} = + case node.kind: + of nnkTypeDef: + result.identifier = newIdent($(node[0])) + var object_node: NimNode + case node[2].kind: + of nnkRefTy: + object_node = node[2][0] + result.is_ref = true + of nnkObjectTy: + object_node = node[2] + result.is_ref = false + else: + let msg = "newTypeDef could not parse RefTy/ObjectTy, found: " & $(node[2].kind) + raise newException(ValueError, msg) + case object_node[1].kind: + of nnkOfInherit: + result.base_type = $(object_node[1][0]) + else: + result.base_type = "object" + result.fields = newFieldSeq(object_node[2]) + else: + let msg = "newTypeDef cannot initialize from node kind: " & $(node.kind) + raise newException(ValueError, msg) + +proc render*(typedef: TypeDef): NimNode {.compileTime.} = + result = newNimNode(nnkTypeDef) + result.add(typedef.identifier.render) + result.add(newEmptyNode()) + let object_node = newNimNode(nnkObjectTy) + object_node.add(newEmptyNode()) + if typedef.base_type == "": + object_node.add(newEmptyNode()) + else: + var base_type = newNimNode(nnkOfInherit) + base_type.add(ident(typedef.base_type)) + object_node.add(base_type) + let fields = typedef.fields.render() + object_node.add(fields) + if typedef.is_ref: + let ref_node = newNimNode(nnkRefTy) + ref_node.add(object_node) + result.add(ref_node) + else: + result.add(object_node) + +proc newTypeDefSeq*(node: NimNode): TypeDefSeq = + result = @[] + case node.kind: + of nnkTypeSection: + for child in node: + result.add(newTypeDef(child)) + else: + let msg = "newTypeSection could not parse TypeDef, found: " & $(node.kind) + raise newException(ValueError, msg) + +proc render*(typeseq: TypeDefSeq): NimNode {.compileTime.} = + result = newNimNode(nnkTypeSection) + for typedef in typeseq: + result.add(typedef.render()) + +proc newProc*(identifier: Ident, params: FieldSeq = @[], + returns: Ident, generics: FieldSeq = @[]): Proc = + result.identifier = identifier + result.params = params + result.returns = returns + result.generics = generics + +proc newProc*(node: NimNode): Proc = + case node.kind: + of nnkProcDef, nnkMethodDef: + result.identifier = newIdent(node[0]) + case node[2].kind: + of nnkGenericParams: + result.generics = newFieldSeq(node[2]) + else: result.generics = @[] + let formal_params = node[3] + case formal_params[0].kind: + of nnkIdent: + result.returns = newIdent(formal_params[0]) + else: discard + result.params = @[] + for i in 1..formal_params.len - 1: + let param = formal_params[i] + for field in newFieldSeq(param): + result.params.add(field) + result.body = node[6] + else: + let msg = "newProc cannot initialize from node kind: " & $(node.kind) + raise newException(ValueError, msg) + +proc render*(procdef: Proc): NimNode {.compileTime.} = + result = newNimNode(nnkProcDef) + result.add(procdef.identifier.render()) + result.add(newEmptyNode()) + result.add(newEmptyNode()) + let formal_params = newNimNode(nnkFormalParams) + formal_params.add(procdef.returns.render()) + for param in procdef.params: + formal_params.add(param.render()) + result.add(formal_params) + result.add(newEmptyNode()) + result.add(newEmptyNode()) + result.add(procdef.body) diff --git a/tests/vm/mevalffi.nim b/tests/vm/mevalffi.nim new file mode 100644 index 000000000..ad8f8b62b --- /dev/null +++ b/tests/vm/mevalffi.nim @@ -0,0 +1,71 @@ +# re-enable for windows once libffi can be installed in koch.nim +# With win32 (not yet win64), libffi on windows works and this test passes. + +when defined(linux) or defined(bsd): + {.passL: "-lm".} # for exp +proc c_exp(a: float64): float64 {.importc: "exp", header: "<math.h>".} + +proc c_printf(frmt: cstring): cint {.importc: "printf", header: "<stdio.h>", varargs, discardable.} + +const snprintfName = when defined(windows): "_snprintf" else: "snprintf" +proc c_snprintf*(str: cstring, size: csize_t, format: cstring): cint {.importc: snprintfName, header: "<stdio.h>", varargs .} + +proc c_malloc(size: csize_t): pointer {.importc:"malloc", header: "<stdlib.h>".} +proc c_free(p: pointer) {.importc:"free", header: "<stdlib.h>".} + +proc fun() = + block: # c_exp + var x = 0.3 + let b = c_exp(x) + let b2 = int(b*1_000_000) # avoids floating point equality + doAssert b2 == 1349858 + doAssert c_exp(0.3) == c_exp(x) + const x2 = 0.3 + doAssert c_exp(x2) == c_exp(x) + + block: # c_printf + c_printf("foo\n") + c_printf("foo:%d\n", 100) + c_printf("foo:%d\n", 101.cint) + c_printf("foo:%d:%d\n", 102.cint, 103.cint) + let temp = 104.cint + c_printf("foo:%d:%d:%d\n", 102.cint, 103.cint, temp) + var temp2 = 105.cint + c_printf("foo:%g:%s:%d:%d\n", 0.03, "asdf", 103.cint, temp2) + + block: # c_snprintf, c_malloc, c_free + let n: uint = 50 + var buffer2 = cstring(cast[ptr char](c_malloc(n))) + + var s: cstring = "foobar" + var age: cint = 25 + let num = c_snprintf(buffer2, n, "s1:%s s2:%s age:%d pi:%g", s, s, age, 3.14) + let numExp = 34 + doAssert num == numExp + c_printf("ret=[%s]\n", buffer2) + c_free(buffer2) + + block: # c_printf bug + var a = 123 + var a2 = a.addr + #[ + bug: different behavior between CT RT in this case: + at CT, shows foo2:a=123 + at RT, shows foo2:a=<address as int> + ]# + if false: + c_printf("foo2:a=%d\n", a2) + + +static: + fun() +fun() + +when not defined nimEvalffiStderrWorkaround: + import system/ansi_c + block: + proc fun2()= + c_fprintf(cstderr, "hello world stderr\n") + write(stderr, "hi stderr\n") + static: fun2() + fun2() diff --git a/tests/vm/mscriptcompiletime.nim b/tests/vm/mscriptcompiletime.nim new file mode 100644 index 000000000..ed7e7c029 --- /dev/null +++ b/tests/vm/mscriptcompiletime.nim @@ -0,0 +1,7 @@ +# bug.nim +var bar* {.compileTime.} = 1 + +proc dummy = discard + +static: + inc bar \ No newline at end of file diff --git a/tests/vm/t11637.nim b/tests/vm/t11637.nim new file mode 100644 index 000000000..c061c6641 --- /dev/null +++ b/tests/vm/t11637.nim @@ -0,0 +1,52 @@ +type Foo = ref object + val: int + +proc `+`(a, b: Foo): Foo = + Foo(val: a.val + b.val) + +proc `*`(a: Foo, b: int): Foo = + Foo(val: a.val * b) + +proc `+=`(a: var Foo, b: Foo) = + a = Foo( + val: a.val + b.val + ) + +proc foobar(a, b, c: Foo): tuple[bar, baz, buzz: Foo] = + + let foo = a + b + c + result.bar = foo * 2 + + result.baz = foo * 3 + result.buzz = result.baz + + result.buzz += a * 10000 + result.baz += b + result.buzz += b + + +block: # Compile-Time + let + a {.compileTime.} = Foo(val: 1) + b {.compileTime.} = Foo(val: 2) + c {.compileTime.} = Foo(val: 3) + r {.compileTime.} = foobar(a, b, c) + + static: + doAssert r.bar.val == 12 + doAssert r.baz.val == 20 + doAssert r.buzz.val == 10020 + +#################################### + +block: # Run-time + let + a = Foo(val: 1) + b = Foo(val: 2) + c = Foo(val: 3) + r = foobar(a, b, c) + + # Expected values + doAssert r.bar.val == 12 + doAssert r.baz.val == 20 + doAssert r.buzz.val == 10020 diff --git a/tests/vm/t17039.nim b/tests/vm/t17039.nim new file mode 100644 index 000000000..f92c93f30 --- /dev/null +++ b/tests/vm/t17039.nim @@ -0,0 +1,10 @@ +type + Obj1 = object + case kind: bool + of false: + field: seq[int] + else: discard + +static: + var obj1 = Obj1() + obj1.field.add(@[]) diff --git a/tests/vm/t17121.nim b/tests/vm/t17121.nim new file mode 100644 index 000000000..bf2d6423f --- /dev/null +++ b/tests/vm/t17121.nim @@ -0,0 +1,9 @@ +discard """ + errormsg: "cannot 'importc' variable at compile time; c_printf" +""" + +proc c_printf*(frmt: cstring): cint {.importc: "printf", header: "<stdio.h>", varargs, discardable.} = + ## foo bar + runnableExamples: discard +static: + let a = c_printf("abc\n") diff --git a/tests/vm/t18103.nim b/tests/vm/t18103.nim new file mode 100644 index 000000000..8622ab290 --- /dev/null +++ b/tests/vm/t18103.nim @@ -0,0 +1,35 @@ +discard """ + targets: "c cpp" + matrix: "--mm:refc; --mm:arc" +""" + +import base64, complex, sequtils, math, sugar + +type + + FP = float + T = object + index: int + arg: FP + val: Complex[FP] + M = object + alpha, beta: FP + +func a(s: openArray[T], model: M): seq[T] = + let f = (tn: int) => model.alpha + FP(tn) * model.beta; + return mapIt s: + block: + let s = it.val * rect(1.0, - f(it.index)) + T(index: it.index, arg: phase(s), val: s) + +proc b(): float64 = + var s = toSeq(0..10).mapIt(T(index: it, arg: 1.0, val: complex.complex(1.0))) + discard a(s, M(alpha: 1, beta: 1)) + return 1.0 + +func cc(str: cstring, offset: ptr[cdouble]): cint {.exportc.} = + offset[] = b() + return 0 + +static: + echo b() diff --git a/tests/vm/t19075.nim b/tests/vm/t19075.nim new file mode 100644 index 000000000..89ca9cb19 --- /dev/null +++ b/tests/vm/t19075.nim @@ -0,0 +1,19 @@ +discard """ + timeout: 10 + joinable: false +""" + +# bug #19075 +const size = 50_000 + +const stuff = block: + var a: array[size, int] + a + +const zeugs = block: + var zeugs: array[size, int] + for i in 0..<size: + zeugs[i] = stuff[i] + zeugs + +doAssert zeugs[0] == 0 \ No newline at end of file diff --git a/tests/vm/t19199.nim b/tests/vm/t19199.nim new file mode 100644 index 000000000..6ae48cb54 --- /dev/null +++ b/tests/vm/t19199.nim @@ -0,0 +1,6 @@ +# bug #19199 +proc mikasa(x: float) = doAssert x == 42 + +static: + mikasa 42.uint.float +mikasa 42.uint.float diff --git a/tests/vm/t20746.nim b/tests/vm/t20746.nim new file mode 100644 index 000000000..bfad269ef --- /dev/null +++ b/tests/vm/t20746.nim @@ -0,0 +1,13 @@ +discard """ + timeout: 10 + joinable: false + output: "fine" +""" + +func addString(): string = + let x = newString(1000000) + for i in 0..<1000000: + discard x[i] + +const translationTable = addString() +echo "fine" diff --git a/tests/vm/t21704.nim b/tests/vm/t21704.nim new file mode 100644 index 000000000..27f4f5b06 --- /dev/null +++ b/tests/vm/t21704.nim @@ -0,0 +1,69 @@ +discard """ +matrix: "--hints:off" +nimout: ''' +Found 2 tests to run. +Found 3 benches to compile. + + --passC:-Wno-stringop-overflow --passL:-Wno-stringop-overflow + + --passC:-Wno-stringop-overflow --passL:-Wno-stringop-overflow + + --passC:-Wno-stringop-overflow --passL:-Wno-stringop-overflow +''' +""" +# bug #21704 +import std/strformat + +const testDesc: seq[string] = @[ + "tests/t_hash_sha256_vs_openssl.nim", + "tests/t_cipher_chacha20.nim" +] +const benchDesc = [ + "bench_sha256", + "bench_hash_to_curve", + "bench_ethereum_bls_signatures" +] + +proc setupTestCommand(flags, path: string): string = + return "nim c -r " & + flags & + &" --nimcache:nimcache/{path} " & # Commenting this out also solves the issue + path + +proc testBatch(commands: var string, flags, path: string) = + commands &= setupTestCommand(flags, path) & '\n' + +proc setupBench(benchName: string): string = + var runFlags = if false: " -r " + else: " " # taking this branch is needed to trigger the bug + + echo runFlags # Somehow runflags isn't reset in corner cases + runFlags &= " --passC:-Wno-stringop-overflow --passL:-Wno-stringop-overflow " + echo runFlags + + return "nim c " & + runFlags & + &" benchmarks/{benchName}.nim" + +proc buildBenchBatch(commands: var string, benchName: string) = + let command = setupBench(benchName) + commands &= command & '\n' + +proc addTestSet(cmdFile: var string) = + echo "Found " & $testDesc.len & " tests to run." + + for path in testDesc: + var flags = "" # This is important + cmdFile.testBatch(flags, path) + +proc addBenchSet(cmdFile: var string) = + echo "Found " & $benchDesc.len & " benches to compile." + for bd in benchDesc: + cmdFile.buildBenchBatch(bd) + +proc task_bug() = + var cmdFile: string + cmdFile.addTestSet() # Comment this out and there is no bug + cmdFile.addBenchSet() + +static: task_bug() diff --git a/tests/vm/t2574.nim b/tests/vm/t2574.nim new file mode 100644 index 000000000..4332667b4 --- /dev/null +++ b/tests/vm/t2574.nim @@ -0,0 +1,14 @@ +discard """ + errormsg: "cannot call method eval at compile time" + line: 14 +""" + +type + PExpr = ref object of RootObj + +method eval(e: PExpr): int = + discard + +static: + let x = PExpr() + discard x.eval diff --git a/tests/vm/t9622.nim b/tests/vm/t9622.nim new file mode 100644 index 000000000..fada8fe59 --- /dev/null +++ b/tests/vm/t9622.nim @@ -0,0 +1,30 @@ +discard """ + targets: "c cpp" + matrix: "--mm:refc; --mm:arc" +""" + +type + GlobNodeKind = enum + LiteralIdent, + Group + + GlobNode = object + case kind: GlobNodeKind + of LiteralIdent: + value: string + of Group: + values: seq[string] + + PathSegment = object + children: seq[GlobNode] + + GlobPattern = seq[PathSegment] + +proc parseImpl(): GlobPattern = + if result.len == 0: + result.add PathSegment() + result[^1].children.add GlobNode(kind: LiteralIdent) + +block: + const pattern = parseImpl() + doAssert $pattern == """@[(children: @[(kind: LiteralIdent, value: "")])]""" diff --git a/tests/vm/tableinstatic.nim b/tests/vm/tableinstatic.nim new file mode 100644 index 000000000..934c3a8dd --- /dev/null +++ b/tests/vm/tableinstatic.nim @@ -0,0 +1,38 @@ +discard """ + nimout: '''0 +0 +0 +''' +""" + +import tables + +# bug #5327 + +type + MyType* = object + counter: int + +proc foo(t: var MyType) = + echo t.counter + +proc bar(t: MyType) = + echo t.counter + +static: + var myValue: MyType + myValue.foo # works nicely + + var refValue: ref MyType + refValue.new + + refValue[].foo # fails to compile + refValue[].bar # works again nicely + +static: + var otherTable = newTable[string, string]() + + otherTable["hallo"] = "123" + otherTable["welt"] = "456" + + doAssert otherTable == {"hallo": "123", "welt": "456"}.newTable diff --git a/tests/vm/taddrof.nim b/tests/vm/taddrof.nim new file mode 100644 index 000000000..bbe9345d2 --- /dev/null +++ b/tests/vm/taddrof.nim @@ -0,0 +1,110 @@ +discard """ +nimout: ''' +true +true +[nil, nil, nil, nil] +[MyObjectRef(123, 321), nil, nil, nil] +['A', '\x00', '\x00', '\x00'] +MyObjectRef(123, 321) +(key: 8, val: 0) +''' +output: ''' +true +true +[nil, nil, nil, nil] +[MyObjectRef(123, 321), nil, nil, nil] +['A', '\x00', '\x00', '\x00'] +MyObjectRef(123, 321) +''' +""" + +type + MyObjectRef = ref object + a,b: int + + MyContainerObject = ref object + member: MyObjectRef + + MySuperContainerObject = ref object + member: MyContainerObject + arr: array[4, MyObjectRef] + + MyOtherObject = ref object + case kind: bool + of true: + member: MyObjectRef + else: + discard + +proc `$`(arg: MyObjectRef): string = + result = "MyObjectRef(" + result.addInt arg.a + result.add ", " + result.addInt arg.b + result.add ")" + +proc foobar(dst: var MyObjectRef) = + dst = new(MyObjectRef) + dst.a = 123 + dst.b = 321 + +proc changeChar(c: var char) = + c = 'A' + +proc test() = + # when it comes from a var, it works + var y: MyObjectRef + foobar(y) + echo y != nil + # when it comes from a member, it fails on VM + var x = new(MyContainerObject) + foobar(x.member) + echo x.member != nil + + # when it comes from an array, it fails on VM + var arr: array[4, MyObjectRef] + echo arr + foobar(arr[0]) + echo arr + + var arr2: array[4, char] + changeChar(arr2[0]) + echo arr2 + + + var z = MyOtherObject(kind: true) + foobar(z.member) + echo z.member + + # this still doesn't work + # var sc = new(MySuperContainerObject) + # sc.member = new(MyContainerObject) + # foobar(sc.member.member) + # echo sc.member.member + # foobar(sc.arr[1]) + # echo sc.arr + + #var str = "---" + #changeChar(str[1]) + #echo str + +test() +static: + test() + +type T = object + f: seq[tuple[key, val: int]] + +proc foo(s: var seq[tuple[key, val: int]]; i: int) = + s[i].key = 4*i + # r4 = addr(s[i]) + # r4[0] = 4*i + +proc bar() = + var s: T + s.f = newSeq[tuple[key, val: int]](3) + foo(s.f, 2) + echo s.f[2] + +static: + bar() diff --git a/tests/vm/tanonproc.nim b/tests/vm/tanonproc.nim new file mode 100644 index 000000000..1176c104e --- /dev/null +++ b/tests/vm/tanonproc.nim @@ -0,0 +1,52 @@ +discard """ + output: '''`Test`''' +""" + +# bug #3561 + +import macros, sugar, strutils + +type + Option[T] = ref object + case valid: bool + of true: + data: T + else: + discard + +proc some[T](v: T): Option[T] = Option[T](valid: true, data: v) +proc none[T](v: T): Option[T] = Option[T](valid: false) +proc none(T: typedesc): Option[T] = Option[T](valid: false) + +proc map[T,U](o: Option[T], f: T -> U): Option[U] = + case o.valid + of true: + f(o.data).some + else: + U.none + +proc notEmpty(o: Option[string]): Option[string] = + case o.valid + of true: + if o.data.strip == "": string.none else: o.data.strip.some + else: + o + +proc getOrElse[T](o: Option[T], def: T): T = + case o.valid + of true: + o.data + else: + def + +proc quoteStr(s: string): Option[string] = + s.some.notEmpty.map(v => "`" & v & "`") + +macro str(s: string): void = + let x = s.strVal + let y = quoteStr(x) + let sn = newStrLitNode(y.getOrElse("NONE")) + result = quote do: + echo `sn` + +str"Test" diff --git a/tests/vm/tarrayboundeval.nim b/tests/vm/tarrayboundeval.nim new file mode 100644 index 000000000..dc8c7ebdc --- /dev/null +++ b/tests/vm/tarrayboundeval.nim @@ -0,0 +1,31 @@ +discard """ + output: '''7 +8 8 +-2''' +""" + +#bug 1063 + +const + KeyMax = 227 + myconst = int((KeyMax + 31) / 32) + +type + FU = array[int((KeyMax + 31) / 32), cuint] + +echo FU.high + +type + PKeyboard* = ptr object + TKeyboardState* = object + display*: pointer + internal: array[int((KeyMax + 31)/32), cuint] + +echo myconst, " ", int((KeyMax + 31) / 32) + +#bug 1304 or something: + +const constArray: array[-3..2, int] = [-3, -2, -1, 0, 1, 2] + +echo constArray[-2] + diff --git a/tests/vm/tasmparser.nim b/tests/vm/tasmparser.nim new file mode 100644 index 000000000..d70c629b6 --- /dev/null +++ b/tests/vm/tasmparser.nim @@ -0,0 +1,174 @@ + +# bug #1513 + +import os, parseutils, strutils, ropes, macros + +var + code {.compileTime.} = "" + start {.compileTime.} = 0 + line {.compileTime.} = 1 + cpp {.compileTime.} = "" + token {.compileTime.} = "" + +proc log(msg: string) {.compileTime.} = + echo msg + +proc asmx64() {.compileTime} = + + #log "code = $1" % code + + const asmx64pre = "{.emit: \"\"\"{x64asm& x= *x64asm_ptr(`asm0`); try {" + const asmx64post = "} catch (Xbyak::Error e) { printf (\"asmx64 error: %s\\n\", e.what ()); }}\"\"\".} " + + const xp = "x." + + const symbolStart = { '_', 'a'..'z', 'A' .. 'Z' } + const symbol = { '0'..'9' } + symbolStart + const eolComment = { ';' } + const endOfLine = { '\l', '\r' } + const leadingWhiteSpace = { ' ' } + + const end_or_comment = endOfLine + eolComment + { '\0' } + + const passthrough_start = { '{', '`' } + const passthrough_end = { '}', '`', '\0' } + + const end_or_symbol_or_comment_or_passthrough = symbolStart + end_or_comment + passthrough_start + + + proc abortAsmParse(err:string) = + discard + + let codeLen = code.len + #let codeEnd = codeLen-1 + cpp.add asmx64pre + + #log "{$1}\n" % [code] + + type asmParseState = enum leading, mnemonic, betweenArguments, arguments, endCmd, skipToEndOfLine + + var state:asmParseState = leading + + proc checkEnd(err:string) = + let ch = code[start] + if int(ch) == 0: + abortAsmParse(err) + + proc get_passthrough() = + inc start + let prev_start = start + let prev_token = token + start += code.parseUntil(token, passthrough_end, start) + checkEnd("Failed to find passthrough end delimiter from offset $1 for:$2\n$3" % [$prev_start, $(code[prev_start-prev_token.len..prev_start]), token[1..token.len-1]]) + inc start + cpp.add "`" + cpp.add token + cpp.add "`" + + var inparse = true + + proc checkCmdEnd() = + if codeLen == start: + state = endCmd + inparse = false + + while inparse: + checkCmdEnd() + + log("state=$1 start=$2" % [$state, $start]) + + case state: + of leading: + + echo "b100 ", start + start += code.skipWhile(leadingWhiteSpace, start) + echo "b200 ", start + let ch = code[start] + if ch in endOfLine: + inc(line) + #echo "c100 ", start, ' ', code + start += code.skipWhile(endOfline, start) + #echo "c200 ", start, ' ', code + continue + elif ch in symbolStart: + state = mnemonic + elif ch in eolComment: + state = skipToEndOfLine + elif ch in passthrough_start: + get_passthrough() + echo "d100 ", start + start += code.parseUntil(token, end_or_symbol_or_comment_or_passthrough, start) + echo "d200 ", start + cpp.add token + state = mnemonic + elif int(ch) == 0: + break + else: + abortAsmParse("after '$3' illegal character at offset $1: $2" % [$start, $(int(ch)), token]) + + of mnemonic: + echo "e100 ", start + start += code.parseWhile(token, symbol, start) + echo "e200 ", start + cpp.add xp + cpp.add token + cpp.add "(" + state = betweenArguments + + of betweenArguments: + let tmp = start + let rcode = code + start += rcode.parseUntil(token, end_or_symbol_or_comment_or_passthrough, tmp) + cpp.add token + + if codeLen <= start: + state = endCmd + continue + + let ch = code[start] + if ch in passthrough_start: + get_passthrough() + continue + if(ch in {'x', 'X'}) and('0' == code[start-1]): + token = $(code[start]) + cpp.add token + inc start + continue + state = arguments + + of arguments: + if code[start] in end_or_comment: + state = endCmd + continue + start += code.parseWhile(token, symbol, start) + cpp.add xp + cpp.add token + state = betweenArguments + + of endCmd: + cpp.add ");\n" + state = skipToEndOfLine + + of skipToEndOfLine: + echo "a100 ", start + start += code.skipUntil(endOfLine, start) + echo "a200 ", start + start += code.skipWhile(endOfline, start) + echo "a300 ", start + inc line + state = leading + + cpp.add asmx64post + + echo($cpp) + +macro asmx64x(code_in:untyped) : typed = + code = $code_in + echo("code.len = $1, code = >>>$2<<<" % [$code.len, code]) + asmx64() + discard result + +asmx64x """ + mov rax, {m} + ret +""" diff --git a/tests/vm/tbitops.nim b/tests/vm/tbitops.nim new file mode 100644 index 000000000..90d463ec9 --- /dev/null +++ b/tests/vm/tbitops.nim @@ -0,0 +1,45 @@ +discard """ +output: "" +""" + +import strutils + +const x = [1'i32, -1, -10, 10, -10, 10, -20, 30, -40, 50, 7 shl 28, -(7 shl 28), 7 shl 28, -(7 shl 28)] +const y = [-1'i32, 1, -10, -10, 10, 10, -20, -30, 40, 50, 1 shl 30, 1 shl 30, -(1 shl 30), -(1 shl 30)] + +const res_xor = block: + var tmp: seq[int64] + for i in 0 ..< x.len: + tmp.add(int64(x[i] xor y[i])) + tmp + +const res_and = block: + var tmp: seq[int64] + for i in 0 ..< x.len: + tmp.add(int64(x[i] and y[i])) + tmp + +const res_or = block: + var tmp: seq[int64] + for i in 0 ..< x.len: + tmp.add(int64(x[i] or y[i])) + tmp + +const res_not = block: + var tmp: seq[int64] + for i in 0 ..< x.len: + tmp.add(not x[i]) + tmp + +let xx = x +let yy = y + +for i in 0..<xx.len: + let z_xor = int64(xx[i] xor yy[i]) + let z_and = int64(xx[i] and yy[i]) + let z_or = int64(xx[i] or yy[i]) + let z_not = int64(not xx[i]) + doAssert(z_xor == res_xor[i], $i & ": " & $res_xor[i] & " " & $z_xor) + doAssert(z_and == res_and[i], $i & ": " & $res_and[i] & " " & $z_and) + doAssert(z_or == res_or[i], $i & ": " & $res_or[i] & " " & $z_or) + doAssert(z_not == res_not[i], $i & ": " & $res_not[i] & " " & $z_not) diff --git a/tests/vm/tcastint.nim b/tests/vm/tcastint.nim new file mode 100644 index 000000000..c306e4a31 --- /dev/null +++ b/tests/vm/tcastint.nim @@ -0,0 +1,309 @@ +import macros +from stdtest/testutils import disableVM +type + Dollar = distinct int + XCoord = distinct int32 + Digit = range[-9..0] + +# those are necessary for comparisons below. +proc `==`(x, y: Dollar): bool {.borrow.} +proc `==`(x, y: XCoord): bool {.borrow.} + +proc dummy[T](x: T): T = x + +template roundTrip(a, T) = + let a2 = a # sideeffect safe + let b = cast[T](a2) + let c = cast[type(a2)](b) + doAssert c == a2 + +proc test() = + let U8 = 0b1011_0010'u8 + let I8 = 0b1011_0010'i8 + let C8 = 0b1011_0010'u8.char + let C8_1 = 0b1011_0011'u8.char + let U16 = 0b10100111_00101000'u16 + let I16 = 0b10100111_00101000'i16 + let U32 = 0b11010101_10011100_11011010_01010000'u32 + let I32 = 0b11010101_10011100_11011010_01010000'i32 + let U64A = 0b11000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'u64 + let I64A = 0b11000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'i64 + let U64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'u64 + let I64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'i64 + when sizeof(int) == 8: + let UX = U64A.uint + let IX = I64A.int + elif sizeof(int) == 4: + let UX = U32.uint + let IX = I32.int + elif sizeof(int) == 2: + let UX = U16.uint + let IX = I16.int + else: + let UX = U8.uint + let IX = I8.int + + doAssert(cast[char](I8) == C8) + doAssert(cast[uint8](I8) == U8) + doAssert(cast[uint16](I16) == U16) + doAssert(cast[uint32](I32) == U32) + doAssert(cast[uint64](I64A) == U64A) + doAssert(cast[uint64](I64B) == U64B) + doAssert(cast[int8](U8) == I8) + doAssert(cast[int16](U16) == I16) + doAssert(cast[int32](U32) == I32) + doAssert(cast[int64](U64A) == I64A) + doAssert(cast[int64](U64B) == I64B) + doAssert(cast[uint](IX) == UX) + doAssert(cast[int](UX) == IX) + + doAssert(cast[char](I8 + 1) == C8_1) + doAssert(cast[uint8](I8 + 1) == U8 + 1) + doAssert(cast[uint16](I16 + 1) == U16 + 1) + doAssert(cast[uint32](I32 + 1) == U32 + 1) + doAssert(cast[uint64](I64A + 1) == U64A + 1) + doAssert(cast[uint64](I64B + 1) == U64B + 1) + doAssert(cast[int8](U8 + 1) == I8 + 1) + doAssert(cast[int16](U16 + 1) == I16 + 1) + doAssert(cast[int32](U32 + 1) == I32 + 1) + doAssert(cast[int64](U64A + 1) == I64A + 1) + doAssert(cast[int64](U64B + 1) == I64B + 1) + doAssert(cast[uint](IX + 1) == UX + 1) + doAssert(cast[int](UX + 1) == IX + 1) + + doAssert(cast[char](I8.dummy) == C8.dummy) + doAssert(cast[uint8](I8.dummy) == U8.dummy) + doAssert(cast[uint16](I16.dummy) == U16.dummy) + doAssert(cast[uint32](I32.dummy) == U32.dummy) + doAssert(cast[uint64](I64A.dummy) == U64A.dummy) + doAssert(cast[uint64](I64B.dummy) == U64B.dummy) + doAssert(cast[int8](U8.dummy) == I8.dummy) + doAssert(cast[int16](U16.dummy) == I16.dummy) + doAssert(cast[int32](U32.dummy) == I32.dummy) + doAssert(cast[int64](U64A.dummy) == I64A.dummy) + doAssert(cast[int64](U64B.dummy) == I64B.dummy) + doAssert(cast[uint](IX.dummy) == UX.dummy) + doAssert(cast[int](UX.dummy) == IX.dummy) + + + doAssert(cast[int64](if false: U64B else: 0'u64) == (if false: I64B else: 0'i64)) + + block: + let raw = 3 + let money = Dollar(raw) # this must be a variable, is otherwise constant folded. + doAssert(cast[int](money) == raw) + doAssert(cast[Dollar](raw) == money) + block: + let raw = 150'i32 + let position = XCoord(raw) # this must be a variable, is otherwise constant folded. + doAssert(cast[int32](position) == raw) + doAssert(cast[XCoord](raw) == position) + block: + let raw = -2 + let digit = Digit(raw) + doAssert(cast[int](digit) == raw) + doAssert(cast[Digit](raw) == digit) + + block: + roundTrip(I64A, float) + roundTrip(I8, uint16) + roundTrip(I8, uint32) + roundTrip(I8, uint64) + doAssert cast[uint16](I8) == 65458'u16 + doAssert cast[uint32](I8) == 4294967218'u32 + doAssert cast[uint64](I8) == 18446744073709551538'u64 + doAssert cast[uint32](I64A) == 2571663889'u32 + doAssert cast[uint16](I64A) == 31249 + doAssert cast[char](I64A).ord == 17 + doAssert compiles(cast[float32](I64A)) + + disableVM: # xxx Error: VM does not support 'cast' from tyInt64 to tyFloat32 + doAssert cast[uint32](cast[float32](I64A)) == 2571663889'u32 + +const prerecordedResults = [ + # cast to char + "\0", "\255", + "\0", "\255", + "\0", "\255", + "\0", "\255", + "\0", "\255", + "\128", "\127", + "\0", "\255", + "\0", "\255", + "\0", "\255", + # cast to uint8 + "0", "255", + "0", "255", + "0", "255", + "0", "255", + "0", "255", + "128", "127", + "0", "255", + "0", "255", + "0", "255", + # cast to uint16 + "0", "255", + "0", "255", + "0", "65535", + "0", "65535", + "0", "65535", + "65408", "127", + "32768", "32767", + "0", "65535", + "0", "65535", + # cast to uint32 + "0", "255", + "0", "255", + "0", "65535", + "0", "4294967295", + "0", "4294967295", + "4294967168", "127", + "4294934528", "32767", + "2147483648", "2147483647", + "0", "4294967295", + # cast to uint64 + "0", "255", + "0", "255", + "0", "65535", + "0", "4294967295", + "0", "18446744073709551615", + "18446744073709551488", "127", + "18446744073709518848", "32767", + "18446744071562067968", "2147483647", + "9223372036854775808", "9223372036854775807", + # cast to int8 + "0", "-1", + "0", "-1", + "0", "-1", + "0", "-1", + "0", "-1", + "-128", "127", + "0", "-1", + "0", "-1", + "0", "-1", + # cast to int16 + "0", "255", + "0", "255", + "0", "-1", + "0", "-1", + "0", "-1", + "-128", "127", + "-32768", "32767", + "0", "-1", + "0", "-1", + # cast to int32 + "0", "255", + "0", "255", + "0", "65535", + "0", "-1", + "0", "-1", + "-128", "127", + "-32768", "32767", + "-2147483648", "2147483647", + "0", "-1", + # cast to int64 + "0", "255", + "0", "255", + "0", "65535", + "0", "4294967295", + "0", "-1", + "-128", "127", + "-32768", "32767", + "-2147483648", "2147483647", + "-9223372036854775808", "9223372036854775807", +] + +proc free_integer_casting() = + # cast from every integer type to every type and ensure same + # behavior in vm and execution time. + macro bar(arg: untyped) = + result = newStmtList() + var i = 0 + for it1 in arg: + let typA = it1[0] + for it2 in arg: + let lowB = it2[1] + let highB = it2[2] + let castExpr1 = nnkCast.newTree(typA, lowB) + let castExpr2 = nnkCast.newTree(typA, highB) + let lit1 = newLit(prerecordedResults[i*2]) + let lit2 = newLit(prerecordedResults[i*2+1]) + result.add quote do: + doAssert($(`castExpr1`) == `lit1`) + doAssert($(`castExpr2`) == `lit2`) + i += 1 + + bar([ + (char, '\0', '\255'), + (uint8, 0'u8, 0xff'u8), + (uint16, 0'u16, 0xffff'u16), + (uint32, 0'u32, 0xffffffff'u32), + (uint64, 0'u64, 0xffffffffffffffff'u64), + (int8, 0x80'i8, 0x7f'i8), + (int16, 0x8000'i16, 0x7fff'i16), + (int32, 0x80000000'i32, 0x7fffffff'i32), + (int64, 0x8000000000000000'i64, 0x7fffffffffffffff'i64) + ]) + +proc test_float_cast = + + const + exp_bias = 1023'i64 + exp_shift = 52 + exp_mask = 0x7ff'i64 shl exp_shift + mantissa_mask = 0xfffffffffffff'i64 + + let f = 8.0 + let fx = cast[int64](f) + let exponent = ((fx and exp_mask) shr exp_shift) - exp_bias + let mantissa = fx and mantissa_mask + doAssert(exponent == 3, $exponent) + doAssert(mantissa == 0, $mantissa) + + # construct 2^N float, where N is integer + let x = -2'i64 + let xx = (x + exp_bias) shl exp_shift + let xf = cast[float](xx) + doAssert(xf == 0.25, $xf) + +proc test_float32_cast = + + const + exp_bias = 127'i32 + exp_shift = 23 + exp_mask = 0x7f800000'i32 + mantissa_mask = 0x007ffff'i32 + + let f = -0.5'f32 + let fx = cast[int32](f) + let exponent = ((fx and exp_mask) shr exp_shift) - exp_bias + let mantissa = fx and mantissa_mask + doAssert(exponent == -1, $exponent) + doAssert(mantissa == 0, $mantissa) + + # construct 2^N float32 where N is integer + let x = 4'i32 + let xx = (x + exp_bias) shl exp_shift + let xf = cast[float32](xx) + doAssert(xf == 16.0'f32, $xf) + +proc test_float32_castB() = + let a: float32 = -123.125 + let b = cast[int32](a) + let c = cast[uint32](a) + doAssert b == -1024049152 + doAssert cast[uint64](b) == 18446744072685502464'u64 + doAssert c == 3270918144'u32 + # ensure the unused bits in the internal representation don't have + # any surprising content. + doAssert cast[uint64](c) == 3270918144'u64 + +template main() = + test() + test_float_cast() + test_float32_cast() + free_integer_casting() + test_float32_castB() + +static: main() +main() diff --git a/tests/vm/tcgemptycallarg.nim b/tests/vm/tcgemptycallarg.nim new file mode 100644 index 000000000..1bedb5070 --- /dev/null +++ b/tests/vm/tcgemptycallarg.nim @@ -0,0 +1,3 @@ +static: + doAssertRaises(ValueError): + raise newException(ValueError, "Yes") diff --git a/tests/vm/tclosureiterator.nim b/tests/vm/tclosureiterator.nim new file mode 100644 index 000000000..c909392d5 --- /dev/null +++ b/tests/vm/tclosureiterator.nim @@ -0,0 +1,9 @@ +discard """ + errormsg: "Closure iterators are not supported by VM!" +""" + +iterator iter*(): int {.closure.} = + yield 3 + +static: + var x = iter diff --git a/tests/vm/tcnstseq.nim b/tests/vm/tcnstseq.nim new file mode 100644 index 000000000..5679a6e37 --- /dev/null +++ b/tests/vm/tcnstseq.nim @@ -0,0 +1,68 @@ +discard """ +output: ''' +AngelikaAnneAnnaAnkaAnja +AngelikaAnneAnnaAnkaAnja +AngelikaAnneAnnaAnkaAnja +onetwothree +onetwothree +onetwothree +one1two2three3 +''' +""" +# Test the new implicit conversion from sequences to arrays in a constant +# context. + +import strutils + + +block t1: + const + myWords = "Angelika Anne Anna Anka Anja".split() + + for x in items(myWords): + write(stdout, x) #OUT AngelikaAnneAnnaAnkaAnja + echo "" + + +block t2: + const + myWords = @["Angelika", "Anne", "Anna", "Anka", "Anja"] + + for i in 0 .. high(myWords): + write(stdout, myWords[i]) #OUT AngelikaAnneAnnaAnkaAnja + echo "" + + +block t3: + for w in items(["Angelika", "Anne", "Anna", "Anka", "Anja"]): + write(stdout, w) #OUT AngelikaAnneAnnaAnkaAnja + echo "" + + +block t2656: + iterator it1(args: seq[string]): string = + for s in args: yield s + iterator it2(args: seq[string]): string {.closure.} = + for s in args: yield s + iterator it3(args: openArray[string]): string {.closure.} = + for s in args: yield s + iterator it4(args: openArray[(string, string)]): string {.closure.} = + for s1, s2 in items(args): yield s1 & s2 + + block: + const myConstSeq = @["one", "two", "three"] + for s in it1(myConstSeq): + stdout.write s + echo "" + for s in it2(myConstSeq): + stdout.write s + echo "" + for s in it3(myConstSeq): + stdout.write s + echo "" + + block: + const myConstSeq = @[("one", "1"), ("two", "2"), ("three", "3")] + for s in it4(myConstSeq): + stdout.write s + echo "" diff --git a/tests/vm/tcompilesetting.nim b/tests/vm/tcompilesetting.nim new file mode 100644 index 000000000..d6c08e70f --- /dev/null +++ b/tests/vm/tcompilesetting.nim @@ -0,0 +1,18 @@ +discard """ +cmd: "nim c --nimcache:build/myNimCache --nimblePath:myNimblePath --gc:arc $file" +joinable: false +""" + +import std/[strutils,compilesettings] +from std/os import fileExists, `/` + +template main = + doAssert querySetting(nimcacheDir) == nimcacheDir.querySetting + doAssert "myNimCache" in nimcacheDir.querySetting + doAssert "myNimblePath" in nimblePaths.querySettingSeq[0] + doAssert querySetting(backend) == "c" + doAssert fileExists(libPath.querySetting / "system.nim") + doAssert querySetting(mm) == "arc" + +static: main() +main() diff --git a/tests/vm/tcompiletimerange.nim b/tests/vm/tcompiletimerange.nim new file mode 100644 index 000000000..cd675b4a3 --- /dev/null +++ b/tests/vm/tcompiletimerange.nim @@ -0,0 +1,28 @@ +discard """ +""" + +# issue #8199 + +const rangesGCHoldEnabled = true # not defined(rangesDisableGCHold) + +type + # A view into immutable array + Range*[T] {.shallow.} = object + when rangesGCHoldEnabled: + gcHold: seq[T] # 0 + start: ptr T # 1 + mLen: int32 # 2 + +type + BytesRange* = Range[byte] + NibblesRange* = object + bytes: BytesRange + +const + zeroBytesRange* = BytesRange() + +proc initNibbleRange*(bytes: BytesRange): NibblesRange = + result.bytes = bytes + +const + zeroNibblesRange* = initNibbleRange(zeroBytesRange) diff --git a/tests/vm/tcompiletimesideeffects.nim b/tests/vm/tcompiletimesideeffects.nim new file mode 100644 index 000000000..4cd57b3bd --- /dev/null +++ b/tests/vm/tcompiletimesideeffects.nim @@ -0,0 +1,42 @@ +discard """ + output: +''' +@[0, 1, 2] +@[3, 4, 5] +@[0, 1, 2] +3 +4 +''' +""" + +template runNTimes(n: int, f : untyped) : untyped = + var accum: seq[type(f)] + for i in 0..n-1: + accum.add(f) + accum + +var state {.compileTime.} : int = 0 +proc fill(): int {.compileTime.} = + result = state + inc state + +# invoke fill() at compile time as a compile time expression +const C1 = runNTimes(3, fill()) +echo C1 + +# invoke fill() at compile time as a set of compile time statements +const C2 = + block: + runNTimes(3, fill()) +echo C2 + +# invoke fill() at compile time after a compile time reset of state +const C3 = + block: + state = 0 + runNTimes(3, fill()) +echo C3 + +# evaluate fill() at compile time and use the results at runtime +echo fill() +echo fill() diff --git a/tests/vm/tcompiletimetable.nim b/tests/vm/tcompiletimetable.nim new file mode 100644 index 000000000..1db490f1a --- /dev/null +++ b/tests/vm/tcompiletimetable.nim @@ -0,0 +1,62 @@ +discard """ + nimout: ''' +2 +3 +4:2 +Got Hi +Got Hey +''' + output:''' +a +b +c +''' +""" + +# bug #404 + +import macros, tables, strtabs + +var ZOOT{.compileTime.} = initTable[int, int](2) +var iii {.compiletime.} = 1 + +macro zoo: untyped = + ZOOT[iii] = iii*2 + inc iii + echo iii + +zoo +zoo + + +macro tupleUnpack: untyped = + var (y,z) = (4, 2) + echo y, ":", z + +tupleUnpack + +# bug #903 + +var x {.compileTime.}: StringTableRef + +macro addStuff(stuff, body: untyped): untyped = + result = newNimNode(nnkStmtList) + + if x.isNil: + x = newStringTable(modeStyleInsensitive) + x[$stuff] = "" + +macro dump(): untyped = + result = newNimNode(nnkStmtList) + for y in x.keys: echo "Got ", y + +addStuff("Hey"): echo "Hey" +addStuff("Hi"): echo "Hi" +dump() + +# ensure .compileTime vars can be used at runtime: +import macros + +var xzzzz {.compileTime.}: array[3, string] = ["a", "b", "c"] + +for i in 0..high(xzzzz): echo xzzzz[i] diff --git a/tests/vm/tcomponent.nim b/tests/vm/tcomponent.nim new file mode 100644 index 000000000..b509bc5d7 --- /dev/null +++ b/tests/vm/tcomponent.nim @@ -0,0 +1,132 @@ +discard """ + output: '''`:)` @ 0,0 +FOO: blah''' +""" + +# +# magic.nim +# + +# bug #3729 + +import macros, sequtils, tables +import strutils +import sugar, meta + +type + Component = object + fields: FieldSeq + field_index: seq[string] + procs: ProcSeq + procs_index: seq[string] + + Registry = object + field_index: seq[string] + procs_index: seq[string] + components: Table[string, Component] + builtin: Component + +proc newRegistry(): Registry = + result.field_index = @[] + result.procs_index = @[] + result.components = initTable[string, Component]() + +var registry {.compileTime.} = newRegistry() + +proc validateComponent(r: var Registry, name: string, c: Component) = + if r.components.hasKey(name): + let msg = "`component` macro cannot consume duplicated identifier: " & name + raise newException(ValueError, msg) + + for field_name in c.field_index: + if r.field_index.contains(field_name): + let msg = "`component` macro cannot delcare duplicated field: " & field_name + raise newException(ValueError, msg) + r.field_index.add(field_name) + + for proc_name in c.procs_index: + if r.procs_index.contains(proc_name): + let msg = "`component` macro cannot delcare duplicated proc: " & proc_name + raise newException(ValueError, msg) + r.procs_index.add(proc_name) + +proc addComponent(r: var Registry, name: string, c: Component) = + r.validateComponent(name, c) + r.components.add(name, c) + +proc parse_component(body: NimNode): Component = + result.field_index = @[] + result.procs_index = @[] + for node in body: + case node.kind: + of nnkVarSection: + result.fields = newFieldSeq(node) + for field in result.fields: + result.field_index.add(field.identifier.name) + of nnkMethodDef, nnkProcDef: + let new_proc = meta.newProc(node) + result.procs = result.procs & @[new_proc] + for procdef in result.procs: + result.procs_index.add(procdef.identifier.name) + else: discard + +macro component*(name, body: untyped): typed = + let component = parse_component(body) + registry.addComponent($name, component) + parseStmt("discard") + +macro component_builtins(body: untyped): typed = + let builtin = parse_component(body) + registry.field_index = builtin.field_index + registry.procs_index = builtin.procs_index + registry.builtin = builtin + +proc bind_methods*(component: var Component, identifier: Ident): seq[NimNode] = + result = @[] + for procdef in component.procs.mitems: + let this_field = newField(newIdent("this"), identifier) + procdef.params.insert(this_field, 0) + result.add(procdef.render()) + +macro bind_components*(type_name, component_names: untyped): typed = + result = newStmtList() + let identifier = newIdent(type_name) + let components = newBracket(component_names) + var entity_type = newTypeDef(identifier, true, "object", "RootObj") + entity_type.fields = registry.builtin.fields + for component_name, component in registry.components: + if components.contains(newIdent(component_name)): + entity_type.fields = entity_type.fields & component.fields + # TODO why doesn't the following snippet work instead of the one above? + # for name in components: + # echo "Registering $1 to $2" % [name.name, identifier.name] + # let component = registry.components[name.name] + # entity_type.fields = entity_type.fields & component.fields + let type_section: TypeDefSeq = @[entity_type] + result.add type_section.render + var builtin = registry.builtin + let builtin_methods = bind_methods(builtin, identifier) + for builtin_proc in builtin_methods: + result.add(builtin_proc) + echo "SIGSEV here" + for component in registry.components.mvalues(): + for method_proc in bind_methods(component, identifier): + result.add(method_proc) + +component_builtins: + proc foo(msg: string) = + echo "FOO: $1" % msg + +component position: + var x*, y*: int + +component name: + var name*: string + proc render*(x, y: int) = echo "`$1` @ $2,$3" % [this.name, $x, $y] + +bind_components(Entity, [position, name]) + +var e = new(Entity) +e.name = ":)" +e.render(e.x, e.y) +e.foo("blah") diff --git a/tests/vm/tconst.nim b/tests/vm/tconst.nim new file mode 100644 index 000000000..5cfe7533e --- /dev/null +++ b/tests/vm/tconst.nim @@ -0,0 +1,58 @@ +discard """ + targets: "c cpp js" +""" + +import std/strutils + +template forceConst(a: untyped): untyped = + ## Force evaluation at CT, but `static(a)` is simpler + const ret = a + ret + +proc isNimVm(): bool = + when nimvm: result = true + else: result = false + +block: + doAssert forceConst(isNimVm()) + doAssert not isNimVm() + doAssert forceConst(isNimVm()) == static(isNimVm()) + doAssert forceConst(isNimVm()) == isNimVm().static + +template main() = + # xxx merge more const related tests here + const ct = CompileTime + # refs https://github.com/timotheecour/Nim/issues/718, apparently `CompileTime` + # isn't cached, which seems surprising. + block: + const + a = """ + Version $1| + Compiled at: $2, $3 + """ % [NimVersion & spaces(44-len(NimVersion)), CompileDate, ct] + let b = $a + doAssert ct in b, $(b, ct) + doAssert NimVersion in b + + block: # Test for fix on broken const unpacking + template mytemp() = + const + (x, increment) = (4, true) + a = 100 + discard (x, increment, a) + mytemp() + + block: # bug #12334 + block: + const b: cstring = "foo" + var c = b + doAssert c == "foo" + block: + const a = "foo" + const b: cstring = a + var c = b + doAssert c == "foo" + + +static: main() +main() diff --git a/tests/vm/tconst_float_as_int.nim b/tests/vm/tconst_float_as_int.nim new file mode 100644 index 000000000..ed84ec194 --- /dev/null +++ b/tests/vm/tconst_float_as_int.nim @@ -0,0 +1,3 @@ + +# bug #4619 +const x: float = 0 diff --git a/tests/vm/tconstarrayresem.nim b/tests/vm/tconstarrayresem.nim new file mode 100644 index 000000000..6701cfe4d --- /dev/null +++ b/tests/vm/tconstarrayresem.nim @@ -0,0 +1,29 @@ +# issue #23010 + +type + Result[T, E] = object + case oResult: bool + of false: + discard + of true: + vResult: T + + Opt[T] = Result[T, void] + +template ok[T, E](R: type Result[T, E], x: untyped): R = + R(oResult: true, vResult: x) + +template c[T](v: T): Opt[T] = Opt[T].ok(v) + +type + FixedBytes[N: static[int]] = distinct array[N, byte] + + H = object + d: FixedBytes[2] + +const b = default(H) +template g(): untyped = + const t = default(H) + b + +discard c(g()) diff --git a/tests/vm/tconstobj.nim b/tests/vm/tconstobj.nim new file mode 100644 index 000000000..7dc20a0ba --- /dev/null +++ b/tests/vm/tconstobj.nim @@ -0,0 +1,95 @@ +discard """ + output: ''' +(name: "hello") +(-1, 0) +(FirstName: "James", LastName: "Franco") +[1, 2, 3] +''' +""" + +# bug #2774, bug #3195 +type Foo = object + name: string + +const fooArray = [ + Foo(name: "hello") +] + +echo fooArray[0] + +type + Position = object + x, y: int + +proc `$`(pos: Position): string = + result = "(" & $pos.x & ", " & $pos.y & ")" + +proc newPos(x, y: int): Position = + result = Position(x: x, y: y) + +const + offset: array[1..4, Position] = [ + newPos(-1, 0), + newPos(1, 0), + newPos(0, -1), + newPos(0, 1) + ] + +echo offset[1] + +# bug #1547 +import tables + +type Person* = object + FirstName*: string + LastName*: string + +let people = { + "001": Person(FirstName: "James", LastName: "Franco") +}.toTable() + +echo people["001"] + +# Object downconversion should not copy + +type + SomeBaseObj {.inheritable.} = object of RootObj + txt : string + InheritedFromBase = object of SomeBaseObj + other : string + +proc initBase(sbo: var SomeBaseObj) = + sbo.txt = "Initialized string from base" + +static: + var ifb2: InheritedFromBase + initBase(SomeBaseObj(ifb2)) + echo repr(ifb2) + doAssert(ifb2.txt == "Initialized string from base") + +static: # issue #11861 + var ifb2: InheritedFromBase + initBase(ifb2) + doAssert(ifb2.txt == "Initialized string from base") + + +static: # issue #15662 + proc a(T: typedesc) = echo T.type + a((int, int)) + +# bug #16069 +type + E = enum + val1, val2 + Obj = object + case k: E + of val1: + x: array[3, int] + of val2: + y: uint32 + +const + foo = [1, 2, 3] + arr = Obj(k: val1, x: foo) + +echo arr.x diff --git a/tests/vm/tconstprocassignments.nim b/tests/vm/tconstprocassignments.nim new file mode 100644 index 000000000..0e2d2ed16 --- /dev/null +++ b/tests/vm/tconstprocassignments.nim @@ -0,0 +1,18 @@ +discard """ + output: ''' +100 +100 +''' +""" + +proc f():int {.compileTime.} = 100 + +const F = f +echo F() + +const G = proc ():int = + let x = f + let y = x + y() + +echo G() diff --git a/tests/vm/tconstresem.nim b/tests/vm/tconstresem.nim new file mode 100644 index 000000000..4526cb891 --- /dev/null +++ b/tests/vm/tconstresem.nim @@ -0,0 +1,10 @@ +block: # issue #19849 + type + Vec2[T] = object + x, y: T + Vec2i = Vec2[int] + template getX(p: Vec2i): int = p.x + let x = getX: + const t = Vec2i(x: 1, y: 2) + t + doAssert x == 1 diff --git a/tests/vm/tconstscope1.nim b/tests/vm/tconstscope1.nim new file mode 100644 index 000000000..41c45a28f --- /dev/null +++ b/tests/vm/tconstscope1.nim @@ -0,0 +1,5 @@ +# issue #5395 + +const a = (var b = 3; b) +echo b #[tt.Error + ^ undeclared identifier: 'b']# diff --git a/tests/vm/tconstscope2.nim b/tests/vm/tconstscope2.nim new file mode 100644 index 000000000..d858e96c2 --- /dev/null +++ b/tests/vm/tconstscope2.nim @@ -0,0 +1,5 @@ +const + a = (var x = 3; x) + # should we allow this? + b = x #[tt.Error + ^ undeclared identifier: 'x']# diff --git a/tests/vm/tconsttable.nim b/tests/vm/tconsttable.nim new file mode 100644 index 000000000..152a33cba --- /dev/null +++ b/tests/vm/tconsttable.nim @@ -0,0 +1,34 @@ +discard """ + output: '''is +finally +nice!''' +""" + +import tables + +const + foo = {"ah": "finally", "this": "is", "possible.": "nice!"}.toTable() + +# protect against overly smart compiler: +var x = "this" + +echo foo[x] +x = "ah" +echo foo[x] +x = "possible." +echo foo[x] + +block: # bug #19840 + const testBytes = [byte 0xD8, 0x08, 0xDF, 0x45, 0x00, 0x3D, 0x00, 0x52, 0x00, 0x61] + var tempStr = "__________________" + + tempStr.prepareMutation + copyMem(addr tempStr[0], addr testBytes[0], testBytes.len) + +block: # bug #22389 + func foo(): ptr UncheckedArray[byte] = + const bar = [77.byte] + cast[ptr UncheckedArray[byte]](addr bar[0]) + + doAssert foo()[0] == 77 + diff --git a/tests/vm/tconsttable2.nim b/tests/vm/tconsttable2.nim new file mode 100644 index 000000000..5a392fb66 --- /dev/null +++ b/tests/vm/tconsttable2.nim @@ -0,0 +1,81 @@ +discard """ + nimout: '''61''' +""" + +# bug #2297 + +import tables + +proc html5tags*(): TableRef[string, string] = + var html5tagsCache: Table[string,string] + if true: + new(result) + html5tagsCache = initTable[string, string]() + html5tagsCache["a"] = "a" + html5tagsCache["abbr"] = "abbr" + html5tagsCache["b"] = "b" + html5tagsCache["element"] = "element" + html5tagsCache["embed"] = "embed" + html5tagsCache["fieldset"] = "fieldset" + html5tagsCache["figcaption"] = "figcaption" + html5tagsCache["figure"] = "figure" + html5tagsCache["footer"] = "footer" + html5tagsCache["header"] = "header" + html5tagsCache["form"] = "form" + html5tagsCache["head"] = "head" + html5tagsCache["hr"] = "hr" + html5tagsCache["html"] = "html" + html5tagsCache["iframe"] = "iframe" + html5tagsCache["img"] = "img" + html5tagsCache["input"] = "input" + html5tagsCache["keygen"] = "keygen" + html5tagsCache["label"] = "label" + html5tagsCache["legend"] = "legend" + html5tagsCache["li"] = "li" + html5tagsCache["link"] = "link" + html5tagsCache["main"] = "main" + html5tagsCache["map"] = "map" + html5tagsCache["menu"] = "menu" + html5tagsCache["menuitem"] = "menuitem" + html5tagsCache["meta"] = "meta" + html5tagsCache["meter"] = "master" + html5tagsCache["noscript"] = "noscript" + html5tagsCache["object"] = "object" + html5tagsCache["ol"] = "ol" + html5tagsCache["optgroup"] = "optgroup" + html5tagsCache["option"] = "option" + html5tagsCache["output"] = "output" + html5tagsCache["p"] = "p" + html5tagsCache["pre"] = "pre" + html5tagsCache["param"] = "param" + html5tagsCache["progress"] = "progress" + html5tagsCache["q"] = "q" + html5tagsCache["rp"] = "rp" + html5tagsCache["rt"] = "rt" + html5tagsCache["ruby"] = "ruby" + html5tagsCache["s"] = "s" + html5tagsCache["script"] = "script" + html5tagsCache["select"] = "select" + html5tagsCache["source"] = "source" + html5tagsCache["style"] = "style" + html5tagsCache["summary"] = "summary" + html5tagsCache["table"] = "table" + html5tagsCache["tbody"] = "tbody" + html5tagsCache["thead"] = "thead" + html5tagsCache["td"] = "td" + html5tagsCache["th"] = "th" + html5tagsCache["template"] = "template" + html5tagsCache["textarea"] = "textarea" + html5tagsCache["time"] = "time" + html5tagsCache["title"] = "title" + html5tagsCache["tr"] = "tr" + html5tagsCache["track"] = "track" + html5tagsCache["ul"] = "ul" + html5tagsCache["video"] = "video" + result[] = html5tagsCache + +static: + var i = 0 + for key, value in html5tags().pairs(): + inc i + echo i diff --git a/tests/vm/tconvaddr.nim b/tests/vm/tconvaddr.nim new file mode 100644 index 000000000..9762a9e59 --- /dev/null +++ b/tests/vm/tconvaddr.nim @@ -0,0 +1,49 @@ +block: # issue #24097 + type Foo = distinct int + proc foo(x: var Foo) = + int(x) += 1 + proc bar(x: var int) = + x += 1 + static: + var x = Foo(1) + int(x) = int(x) + 1 + doAssert x.int == 2 + int(x) += 1 + doAssert x.int == 3 + foo(x) + doAssert x.int == 4 + bar(int(x)) # need vmgen flags propagated for this + doAssert x.int == 5 + type Bar = object + x: Foo + static: + var obj = Bar(x: Foo(1)) + int(obj.x) = int(obj.x) + 1 + doAssert obj.x.int == 2 + int(obj.x) += 1 + doAssert obj.x.int == 3 + foo(obj.x) + doAssert obj.x.int == 4 + bar(int(obj.x)) # need vmgen flags propagated for this + doAssert obj.x.int == 5 + static: + var arr = @[Foo(1)] + int(arr[0]) = int(arr[0]) + 1 + doAssert arr[0].int == 2 + int(arr[0]) += 1 + doAssert arr[0].int == 3 + foo(arr[0]) + doAssert arr[0].int == 4 + bar(int(arr[0])) # need vmgen flags propagated for this + doAssert arr[0].int == 5 + proc testResult(): Foo = + result = Foo(1) + int(result) = int(result) + 1 + doAssert result.int == 2 + int(result) += 1 + doAssert result.int == 3 + foo(result) + doAssert result.int == 4 + bar(int(result)) # need vmgen flags propagated for this + doAssert result.int == 5 + doAssert testResult().int == 5 diff --git a/tests/vm/tcopy_global_var.nim b/tests/vm/tcopy_global_var.nim new file mode 100644 index 000000000..eadd27b9a --- /dev/null +++ b/tests/vm/tcopy_global_var.nim @@ -0,0 +1,30 @@ +discard """ + nimout: "static done" +""" + +# bug #5269 + +proc assertEq[T](arg0, arg1: T): void = + assert arg0 == arg1, $arg0 & " == " & $arg1 + +type + MyType = object + str: string + a: int + +block: + var localValue = MyType(str: "Original strning, (OK)", a: 0) + var valueCopy = localValue + valueCopy.a = 123 + valueCopy.str = "Modified strning, (not OK when in localValue)" + assertEq(localValue.str, "Original strning, (OK)") + assertEq(localValue.a, 0) + +static: + var localValue = MyType(str: "Original strning, (OK)", a: 0) + var valueCopy = localValue + valueCopy.a = 123 + valueCopy.str = "Modified strning, (not OK when in localValue)" + assertEq(localValue.str, "Original strning, (OK)") + assertEq(localValue.a, 0) + echo "static done" diff --git a/tests/vm/teval1.nim b/tests/vm/teval1.nim new file mode 100644 index 000000000..0316ea238 --- /dev/null +++ b/tests/vm/teval1.nim @@ -0,0 +1,42 @@ + +discard """ +nimout: "##" +""" + +import macros + +proc testProc: string {.compileTime.} = + result = "" + result = result & "" + +when true: + macro test(n: untyped): untyped = + result = newNimNode(nnkStmtList) + echo "#", testProc(), "#" + test: + "hi" + +const + x = testProc() + +doAssert x == "" + +# bug #1310 +static: + var i, j: set[int8] = {} + var k = i + j + +type + Obj = object + x: int + +converter toObj(x: int): Obj = Obj(x: x) + +# bug #10514 +block: + const + b: Obj = 42 + bar = [b] + + let i_runtime = 0 + doAssert bar[i_runtime] == b diff --git a/tests/vm/texception.nim b/tests/vm/texception.nim new file mode 100644 index 000000000..65a781281 --- /dev/null +++ b/tests/vm/texception.nim @@ -0,0 +1,14 @@ +proc someFunc() = + try: + raise newException(ValueError, "message") + except ValueError as err: + doAssert err.name == "ValueError" + doAssert err.msg == "message" + raise + +static: + try: + someFunc() + except: + discard + \ No newline at end of file diff --git a/tests/vm/texcl.nim b/tests/vm/texcl.nim new file mode 100644 index 000000000..41975f27b --- /dev/null +++ b/tests/vm/texcl.nim @@ -0,0 +1,27 @@ +discard """ + output: '''false''' +""" + +import macros + +type + nlOptions = enum + nloNone + nloDebug + +var nlOpts {.compileTime.} = {nloDebug} + +proc initOpts(): set[nlOptions] = + result.incl nloDebug + result.incl nloNone + result.excl nloDebug + +const cOpts = initOpts() + +macro nlo() = + nlOpts.incl(nloNone) + nlOpts.excl(nloDebug) + result = newEmptyNode() + +nlo() +echo nloDebug in cOpts diff --git a/tests/vm/textensionmap.nim b/tests/vm/textensionmap.nim new file mode 100644 index 000000000..7ada1880d --- /dev/null +++ b/tests/vm/textensionmap.nim @@ -0,0 +1,13 @@ + +# bug #5237 + +import tables +import sets +import sequtils + + +const EXTENSIONMAP = { + "c": @["*.c", "*.h"], +}.toTable() + +const EXTENSIONS = toHashSet(concat(toSeq(EXTENSIONMAP.values()))) diff --git a/tests/vm/tfarjump.nim b/tests/vm/tfarjump.nim new file mode 100644 index 000000000..f5798b8d2 --- /dev/null +++ b/tests/vm/tfarjump.nim @@ -0,0 +1,14 @@ +# Test a VM relative jump with an offset larger then 32767 instructions. + +import macros + +static: + var a = 0 + macro foo(): untyped = + let s = newStmtList() + for i in 1..6554: + s.add nnkCommand.newTree(ident("inc"), ident("a")) + quote do: + if true: + `s` + foo() diff --git a/tests/vm/tfibconst.nim b/tests/vm/tfibconst.nim new file mode 100644 index 000000000..cca6dd84f --- /dev/null +++ b/tests/vm/tfibconst.nim @@ -0,0 +1,43 @@ +discard """ + nimout: ''' +Fibonacci sequence: 0, 1, 1, 2, 3 +Sequence continues: 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610 +''' +""" + + +import strformat + +var fib_n {.compileTime.}: int +var fib_prev {.compileTime.}: int +var fib_prev_prev {.compileTime.}: int + +proc next_fib(): int {.compileTime.} = + let fib = if fib_n < 2: + fib_n + else: + fib_prev_prev + fib_prev + inc(fib_n) + fib_prev_prev = fib_prev + fib_prev = fib + fib + +const f0 = next_fib() +const f1 = next_fib() +const f2 = next_fib() +const f3 = next_fib() +const f4 = next_fib() + +static: + echo fmt"Fibonacci sequence: {f0}, {f1}, {f2}, {f3}, {f4}" + +const fib_continues = block: + var result = fmt"Sequence continues: " + for i in 0..10: + if i > 0: + add(result, ", ") + add(result, $next_fib()) + result + +static: + echo fib_continues \ No newline at end of file diff --git a/tests/vm/tfile_rw.nim b/tests/vm/tfile_rw.nim new file mode 100644 index 000000000..439886e49 --- /dev/null +++ b/tests/vm/tfile_rw.nim @@ -0,0 +1,22 @@ +# test file read write in vm + +import os, strutils + +const filename = splitFile(currentSourcePath).dir / "tfile_rw.txt" + +const mytext = "line1\nline2\nline3" +static: + writeFile(filename, mytext) +const myfile_str = staticRead(filename) +const myfile_str2 = readFile(filename) +const myfile_str_seq = readLines(filename, 3) + +static: + doAssert myfile_str == mytext + doAssert myfile_str2 == mytext + doAssert myfile_str_seq[0] == "line1" + doAssert myfile_str_seq[1] == "line2" + doAssert myfile_str_seq.join("\n") == mytext + + +removeFile(filename) diff --git a/tests/vm/tforwardproc.nim b/tests/vm/tforwardproc.nim new file mode 100644 index 000000000..bcd929f0e --- /dev/null +++ b/tests/vm/tforwardproc.nim @@ -0,0 +1,17 @@ +discard """ + errormsg: "cannot evaluate at compile time: initArray" + line: 11 +""" + +# bug #3066 + +proc initArray(): array[10, int] + +const + someTable = initArray() + +proc initArray(): array[10, int] = + for f in 0..<10: + result[f] = 3 + +when true: echo repr(someTable) diff --git a/tests/vm/tgenericcompiletimeproc.nim b/tests/vm/tgenericcompiletimeproc.nim new file mode 100644 index 000000000..08099ebbe --- /dev/null +++ b/tests/vm/tgenericcompiletimeproc.nim @@ -0,0 +1,36 @@ +block: # issue #10753 + proc foo(x: int): int {.compileTime.} = x + const a = foo(123) + doAssert foo(123) == a + + proc bar[T](x: T): T {.compileTime.} = x + const b = bar(123) + doAssert bar(123) == b + const c = bar("abc") + doAssert bar("abc") == c + +block: # issue #22021 + proc foo(x: static int): int {.compileTime.} = x + 1 + doAssert foo(123) == 124 + +block: # issue #19365 + proc f[T](x: static T): T {.compileTime.} = x + x + doAssert f(123) == 246 + doAssert f(1.0) == 2.0 + +block: + # don't fold compile time procs in typeof + proc fail[T](x: T): T {.compileTime.} = + doAssert false + x + doAssert typeof(fail(123)) is typeof(123) + proc p(x: int): int = x + + type Foo = typeof(p(fail(123))) + +block: # issue #24150, related regression + proc w(T: type): T {.compileTime.} = default(ptr T)[] + template y(v: auto): auto = typeof(v) is int + discard compiles(y(w int)) + proc s(): int {.compileTime.} = discard + discard s() diff --git a/tests/vm/tgloballetfrommacro.nim b/tests/vm/tgloballetfrommacro.nim new file mode 100644 index 000000000..4be09b56e --- /dev/null +++ b/tests/vm/tgloballetfrommacro.nim @@ -0,0 +1,13 @@ +discard """ +errormsg: "cannot evaluate at compile time: BUILTIN_NAMES" +line: 11 +""" + +import sets + +let BUILTIN_NAMES = toHashSet(["int8", "int16", "int32", "int64"]) + +macro test*(): bool = + echo "int64" notin BUILTIN_NAMES + +echo test() diff --git a/tests/vm/tgorge.bat b/tests/vm/tgorge.bat new file mode 100644 index 000000000..24d365842 --- /dev/null +++ b/tests/vm/tgorge.bat @@ -0,0 +1 @@ +@echo gorge test \ No newline at end of file diff --git a/tests/vm/tgorge.nim b/tests/vm/tgorge.nim new file mode 100644 index 000000000..1f77d2c95 --- /dev/null +++ b/tests/vm/tgorge.nim @@ -0,0 +1,29 @@ +discard """ +disabled: "windows" +""" + +# If your os is windows and this test fails for you locally, please +# check what is going wrong. + +import os + +template getScriptDir(): string = + parentDir(instantiationInfo(-1, true).filename) + +# See also simpler test in Nim/tests/vm/tvmops.nim for a simpler +# cross platform way. +block gorge: + const + execName = when defined(windows): "tgorge.bat" else: "./tgorge.sh" + relOutput = gorge(execName) + absOutput = gorge(getScriptDir() / execName) + + doAssert relOutput == "gorge test" + doAssert absOutput == "gorge test" + +block gorgeEx: + const + execName = when defined(windows): "tgorgeex.bat" else: "./tgorgeex.sh" + res = gorgeEx(execName) + doAssert res.output == "gorgeex test" + doAssert res.exitCode == 1 diff --git a/tests/vm/tgorge.sh b/tests/vm/tgorge.sh new file mode 100755 index 000000000..ba47afeae --- /dev/null +++ b/tests/vm/tgorge.sh @@ -0,0 +1,2 @@ +#!/bin/sh +echo "gorge test" \ No newline at end of file diff --git a/tests/vm/tgorgeex.bat b/tests/vm/tgorgeex.bat new file mode 100644 index 000000000..57f11fdd1 --- /dev/null +++ b/tests/vm/tgorgeex.bat @@ -0,0 +1,2 @@ +@echo gorgeex test +@exit /b 1 diff --git a/tests/vm/tgorgeex.sh b/tests/vm/tgorgeex.sh new file mode 100755 index 000000000..36ba0a02f --- /dev/null +++ b/tests/vm/tgorgeex.sh @@ -0,0 +1,3 @@ +#!/bin/sh +echo "gorgeex test" +exit 1 diff --git a/tests/vm/tinheritance.nim b/tests/vm/tinheritance.nim new file mode 100644 index 000000000..2a98ed923 --- /dev/null +++ b/tests/vm/tinheritance.nim @@ -0,0 +1,94 @@ +discard """ + nimout: '''Hello fred, managed by sally +Hello sally, managed by bob +0''' +""" +# bug #3973 + +type + EmployeeCode = enum + ecCode1, + ecCode2 + + Person* = object of RootObj + name*: string + last_name*: string + + Employee* = object of Person + empl_code*: EmployeeCode + mgr_name*: string + +proc test() = + var + empl1 = Employee(name: "fred", last_name: "smith", mgr_name: "sally", empl_code: ecCode1) + empl2 = Employee(name: "sally", last_name: "jones", mgr_name: "bob", empl_code: ecCode2) + + echo "Hello ", empl1.name, ", managed by ", empl1.mgr_name + echo "Hello ", empl2.name, ", managed by ", empl2.mgr_name + +static: + test() + +#---------------------------------------------- +# Bugs #9701 and #9702 +type + MyKind = enum + kA, kB, kC + + Base = ref object of RootObj + x: string + + A = ref object of Base + a: string + + B = ref object of Base + b: string + + C = ref object of B + c: string + +template check_templ(n: Base, k: MyKind) = + if k == kA: doAssert(n of A) else: doAssert(not (n of A)) + if k in {kB, kC}: doAssert(n of B) else: doAssert(not (n of B)) + if k == kC: doAssert(n of C) else: doAssert(not (n of C)) + doAssert(n of Base) + +proc check_proc(n: Base, k: MyKind) = + if k == kA: doAssert(n of A) else: doAssert(not (n of A)) + if k in {kB, kC}: doAssert(n of B) else: doAssert(not (n of B)) + if k == kC: doAssert(n of C) else: doAssert(not (n of C)) + doAssert(n of Base) + +static: + let aa = new(A) + check_templ(aa, kA) + check_proc(aa, kA) + let bb = new(B) + check_templ(bb, kB) + check_proc(bb, kB) + let cc = new(C) + check_templ(cc, kC) + check_proc(cc, kC) + +let aa = new(A) +check_templ(aa, kA) +check_proc(aa, kA) +let bb = new(B) +check_templ(bb, kB) +check_proc(bb, kB) +let cc = new(C) +check_templ(cc, kC) +check_proc(cc, kC) + +type + BBar = object of RootObj + bbarField: set[char] + xbarField: string + d, e: int + FooBar = object of BBar + a: int + b: string + +static: + var fb: FooBar + echo fb.a diff --git a/tests/vm/tissues.nim b/tests/vm/tissues.nim new file mode 100644 index 000000000..f0ae6c296 --- /dev/null +++ b/tests/vm/tissues.nim @@ -0,0 +1,76 @@ +import macros + +block t9043: # bug #9043 + proc foo[N: static[int]](dims: array[N, int]): string = + const N1 = N + const N2 = dims.len + const ret = $(N, dims.len, N1, N2) + static: doAssert ret == $(N, dims.len, N1, N2) + ret + + doAssert foo([1, 2]) == "(2, 2, 2, 2)" + +block t4952: + proc doCheck(tree: NimNode) = + let res: tuple[n: NimNode] = (n: tree) + assert: tree.kind == res.n.kind + for sub in tree: + doCheck(sub) + + macro id(body: untyped): untyped = + doCheck(body) + + id(foo((i: int))) + + static: + let tree = newTree(nnkExprColonExpr) + let t = (n: tree) + doAssert: t.n.kind == tree.kind + + +# bug #19909 +type + SinglyLinkedList[T] = ref object + SinglyLinkedListObj[T] = ref object + + +proc addMoved[T](a, b: var SinglyLinkedList[T]) = + if a.addr != b.addr: discard + +proc addMoved[T](a, b: var SinglyLinkedListObj[T]) = + if a.addr != b.addr: discard + +proc main = + var a: SinglyLinkedList[int]; new a + var b: SinglyLinkedList[int]; new b + a.addMoved b + + var a0: SinglyLinkedListObj[int] + var b0: SinglyLinkedListObj[int] + a0.addMoved b0 + +static: main() + + +# bug #18641 + +type A = object + ha1: int +static: + var a = A() + var a2 = a.addr + a2.ha1 = 11 + doAssert a2.ha1 == 11 + a.ha1 = 12 + doAssert a.ha1 == 12 + doAssert a2.ha1 == 12 # ok +static: + proc fn() = + var a = A() + var a2 = a.addr + a2.ha1 = 11 + doAssert a2.ha1 == 11 + a.ha1 = 12 + doAssert a.ha1 == 12 + doAssert a2.ha1 == 12 # fails + fn() diff --git a/tests/vm/tldconst.nim b/tests/vm/tldconst.nim new file mode 100644 index 000000000..7df3143c9 --- /dev/null +++ b/tests/vm/tldconst.nim @@ -0,0 +1,14 @@ +# Passes if it compiles +# From issue #1946 + +type + Part = object + index: int ## array index of argument to be accessed + +proc foobar(): int = + var x: Part + if x.index < high(int): + discard + 0 + +const x = foobar() diff --git a/tests/vm/tmanyregs.nim b/tests/vm/tmanyregs.nim new file mode 100644 index 000000000..711c69285 --- /dev/null +++ b/tests/vm/tmanyregs.nim @@ -0,0 +1,16 @@ +import macros + +# Generate a proc with more then 255 registers. Should not generate an error at +# compile time + +static: + macro mkFoo() = + let ss = newStmtList() + for i in 1..256: + ss.add parseStmt "var x" & $i & " = " & $i + ss.add parseStmt "inc x" & $i + quote do: + proc foo() = + `ss` + mkFoo() + foo() diff --git a/tests/vm/tmaxloopiterations.nim b/tests/vm/tmaxloopiterations.nim new file mode 100644 index 000000000..c256df518 --- /dev/null +++ b/tests/vm/tmaxloopiterations.nim @@ -0,0 +1,15 @@ +discard """ +errormsg: "interpretation requires too many iterations; if you are sure this is not a bug in your code" +""" + +# issue #9829 + +macro foo(): untyped = + let lines = ["123", "5423"] + var idx = 0 + while idx < lines.len(): + if lines[idx].len() < 1: + inc(idx) + continue + +foo() diff --git a/tests/vm/tmisc_vm.nim b/tests/vm/tmisc_vm.nim new file mode 100644 index 000000000..1ad830b5f --- /dev/null +++ b/tests/vm/tmisc_vm.nim @@ -0,0 +1,459 @@ +discard """ + targets: "c js" + output: ''' +[127, 127, 0, 255][127, 127, 0, 255] +(data: 1) +(2, 1) +(2, 1) +(2, 1) +(f0: 5) +''' + + nimout: '''caught Exception +main:begin +main:end +@[{0}] +(width: 0, height: 0, path: "") +@[(width: 0, height: 0, path: ""), (width: 0, height: 0, path: "")] +Done! +foo4 +foo4 +foo4 +(a: 0, b: 0) +(a: 0, b: 0) +(a: 0, b: 0) +z1 m: (lo: 12) +z2 a: (lo: 3) +x1 a: (lo: 3) +x2 a: (lo: 6) +x3 a: (lo: 0) +z3 a: (lo: 3) +x1 a: (lo: 3) +x2 a: (lo: 6) +x3 a: (lo: 0) +(2, 1) +(2, 1) +(2, 1) +(f0: 5) +''' +""" +import std/sets + +#bug #1009 +type + TAggRgba8* = array[4, byte] + +template R*(self: TAggRgba8): byte = self[0] +template G*(self: TAggRgba8): byte = self[1] +template B*(self: TAggRgba8): byte = self[2] +template A*(self: TAggRgba8): byte = self[3] + +template `R=`*(self: TAggRgba8, val: byte) = + self[0] = val +template `G=`*(self: TAggRgba8, val: byte) = + self[1] = val +template `B=`*(self: TAggRgba8, val: byte) = + self[2] = val +template `A=`*(self: TAggRgba8, val: byte) = + self[3] = val + +proc ABGR*(val: int | int64): TAggRgba8 = + var V = val + result.R = byte(V and 0xFF) + V = V shr 8 + result.G = byte(V and 0xFF) + V = V shr 8 + result.B = byte(V and 0xFF) + result.A = byte((V shr 8) and 0xFF) + +const + c1 = ABGR(0xFF007F7F) +echo ABGR(0xFF007F7F).repr, c1.repr + + +# bug 8740 + +static: + try: + raise newException(ValueError, "foo") + except Exception: + echo "caught Exception" + except Defect: + echo "caught Defect" + except ValueError: + echo "caught ValueError" + +# bug #10538 + +block: + proc fun1(): seq[int] = + try: + try: + result.add(1) + return + except: + result.add(-1) + finally: + result.add(2) + finally: + result.add(3) + result.add(4) + + let x1 = fun1() + const x2 = fun1() + doAssert(x1 == x2) + +# bug #11610 +proc simpleTryFinally()= + try: + echo "main:begin" + finally: + echo "main:end" + +static: simpleTryFinally() + +# bug #10981 + +proc main = + for i in 0..<15: + var someSets = @[initHashSet[int]()] + someSets[^1].incl(0) # <-- segfaults + if i == 0: + echo someSets + +static: + main() + +# bug #7261 +const file = """ +sprites.png +size: 1024,1024 +format: RGBA8888 +filter: Linear,Linear +repeat: none +char/slide_down + rotate: false + xy: 730, 810 + size: 204, 116 + orig: 204, 116 + offset: 0, 0 + index: -1 +""" + +type + AtlasPage = object + width, height: int + path: string + + CtsStream = object + data: string + pos: int + +proc atEnd(stream: CtsStream): bool = + stream.pos >= stream.data.len + +proc readChar(stream: var CtsStream): char = + if stream.atEnd: + result = '\0' + else: + result = stream.data[stream.pos] + inc stream.pos + +proc readLine(s: var CtsStream, line: var string): bool = + # This is pretty much copied from the standard library: + line.setLen(0) + while true: + var c = readChar(s) + if c == '\c': + c = readChar(s) + break + elif c == '\L': break + elif c == '\0': + if line.len > 0: break + else: return false + line.add(c) + result = true + +proc peekLine(s: var CtsStream, line: var string): bool = + let oldPos = s.pos + result = s.readLine(line) + s.pos = oldPos + +proc initCtsStream(data: string): CtsStream = + CtsStream( + pos: 0, + data: data + ) + +# ******************** +# Interesting stuff happens here: +# ******************** + +proc parseAtlas(stream: var CtsStream) = + var pages = @[AtlasPage(), AtlasPage()] + var line = "" + + block: + let page = addr pages[^1] + discard stream.peekLine(line) + discard stream.peekLine(line) + echo page[] + echo pages + +static: + var stream = initCtsStream(file) + parseAtlas(stream) + echo "Done!" + + +# bug #12244 + +type + Apple = object + data: int + +func what(x: var Apple) = + x = Apple(data: 1) + +func oh_no(): Apple = + what(result) + +const + vmCrash = oh_no() + +debugEcho vmCrash + + +# bug #12310 + +proc someTransform(s: var array[8, uint64]) = + var s1 = 5982491417506315008'u64 + s[1] += s1 + +static: + var state: array[8, uint64] + state[1] = 7105036623409894663'u64 + someTransform(state) + + doAssert state[1] == 13087528040916209671'u64 + +import macros +# bug #12670 + +macro fooImpl(arg: untyped) = + result = quote do: + `arg` + +proc foo(): string {.compileTime.} = + fooImpl: + result = "foo" + result.addInt 4 + +static: + echo foo() + echo foo() + echo foo() + +# bug #12488 +type + MyObject = object + a,b: int + MyObjectRef = ref MyObject + +static: + let x1 = new(MyObject) + echo x1[] + let x2 = new(MyObjectRef) + echo x2[] + let x3 = new(ref MyObject) # cannot generate VM code for ref MyObject + echo x3[] + +# bug #19464 +type + Wrapper = object + inner: int + +proc assign(r: var Wrapper, a: Wrapper) = + r = a + +proc myEcho(a: Wrapper) = + var tmp = a + assign(tmp, Wrapper(inner: 0)) # this shouldn't modify `a` + doAssert a.inner == 1 + +static: + var result: Wrapper + assign(result, Wrapper(inner: 1)) + myEcho(result) + +when true: + # bug #15974 + type Foo = object + f0: int + + proc fn(a: var Foo) = + var s: Foo + a = Foo(f0: 2) + s = a + doAssert s.f0 == 2 + a = Foo(f0: 3) + doAssert s.f0 == 2 + + proc test2()= + var a = Foo(f0: 1) + fn(a) + + static: test2() + test2() + +# bug #12551 +type + StUint = object + lo: uint64 + +func `+=`(x: var Stuint, y: Stuint) = + x.lo += y.lo + +func `-`(x, y: Stuint): Stuint = + result.lo = x.lo - y.lo + +func `+`(x, y: Stuint): Stuint = + result.lo = x.lo + y.lo + +func `-=`(x: var Stuint, y: Stuint) = + x = x - y + +func `<`(x, y: Stuint): bool= + x.lo < y.lo + +func `==`(x, y: Stuint): bool = + x.lo == y.lo + +func `<=`(x, y: Stuint): bool = + x.lo <= y.lo + +proc div3n2n(r: var Stuint, b: Stuint) = + var d: Stuint + r = d + r += b + +func div2n1n(r: var Stuint, b: Stuint) = + div3n2n(r, b) + +func divmodBZ(x, y: Stuint, r: var Stuint)= + div2n1n(r, y) + r.lo = 3 + +func `mod`(x, y: Stuint): Stuint = + divmodBZ(x, y, result) + +func doublemod_internal(a, m: Stuint): Stuint = + result = a + if a >= m - a: + result -= m + result += a + +func mulmod_internal(a, b, m: Stuint): Stuint = + var (a, b) = (a, b) + swap(a, b) + debugEcho "x1 a: ", a + a = doublemod_internal(a, m) + debugEcho "x2 a: ", a + a = doublemod_internal(a, m) + debugEcho "x3 a: ", a + +func powmod_internal(a, m: Stuint): Stuint = + var a = a + debugEcho "z1 m: ", m + debugEcho "z2 a: ", a + result = mulmod_internal(result, a, m) + debugEcho "z3 a: ", a + a = mulmod_internal(a, a, m) + +func powmod*(a, m: Stuint) = + discard powmod_internal(a mod m, m) + +static: + var x = Stuint(lo: high(uint64)) + var y = Stuint(lo: 12) + + powmod(x, y) + +# bug #16780 +when true: + template swap*[T](a, b: var T) = + var a2 = addr(a) + var b2 = addr(b) + var aOld = a2[] + a2[] = b2[] + b2[] = aOld + + proc rather = + block: + var a = 1 + var b = 2 + swap(a, b) + echo (a,b) + + block: + type Foo = ref object + x: int + var a = Foo(x:1) + var b = Foo(x:2) + swap(a, b) + echo (a.x, b.x) + + block: + type Foo = object + x: int + var a = Foo(x:1) + var b = Foo(x:2) + swap(a, b) + echo (a.x,b.x) + + static: rather() + rather() + +# bug #16020 +when true: + block: + type Foo = object + f0: int + proc main= + var f = Foo(f0: 3) + var f2 = f.addr + f2[].f0 += 1 + f2.f0 += 1 + echo f + static: main() + main() + +import tables, strutils + +# bug #14553 +const PpcPatterns = @[("aaaa", "bbbb"), ("aaaaa", "bbbbb"), ("aaaaaa", "bbbbbb"), ("aaaaaaa", "bbbbbbb"), ("aaaaaaaa", "bbbbb")] + +static: + var + needSecondIdentifier = initTable[uint32, seq[(string, string)]]() + + for (name, pattern) in PpcPatterns: + let + firstPart = 0'u32 + lastPart = "test" + + needSecondIdentifier.mgetOrPut(firstPart, @[]).add((name, pattern)) + + doAssert needSecondIdentifier[0] == @[("aaaa", "bbbb"), ("aaaaa", "bbbbb"), ("aaaaaa", "bbbbbb"), ("aaaaaaa", "bbbbbbb"), ("aaaaaaaa", "bbbbb")] + +# bug #17864 +macro transform*(fn: typed) = + quote do: + `fn` + +var map: Table[string, HashSet[string]] +proc publish*(): void {.transform.} = + map["k"] = init_hash_set[string]() + map["k"].incl "d" + +publish() diff --git a/tests/vm/tmitems_vm.nim b/tests/vm/tmitems_vm.nim new file mode 100644 index 000000000..787d52cc6 --- /dev/null +++ b/tests/vm/tmitems_vm.nim @@ -0,0 +1,45 @@ +discard """ + nimout: '''13''' + output: '''3 +3 +3''' +""" +# bug #3731 +var list {.compileTime.} = newSeq[int]() + +macro calc*(): void = + list.add(1) + for c in list.mitems: + c = 13 + + for c in list: + echo c + +calc() + +# bug #3859 +import macros +macro m: void = + var s = newseq[NimNode](3) + # var s: array[3,NimNode] # not working either + for i in 0..<s.len: s[i] = newLit(3) # works + #for x in s.mitems: x = newLit(3) + result = newStmtList() + for i in s: + result.add newCall(bindsym"echo", i) + +m() + +# bug 4741 & 5013 +proc test() = + var s = [("baz", 42), ("bath", 42)] + for i in s.mitems: + i[1] = 3 + doAssert(s == [("baz", 3), ("bath", 3)]) + +static: + test() + var s = [("baz", 42), ("bath", 42)] + for i in s.mitems: + i[1] = 3 + doAssert(s == [("baz", 3), ("bath", 3)]) diff --git a/tests/vm/tnewseqofcap.nim b/tests/vm/tnewseqofcap.nim new file mode 100644 index 000000000..a7dc07aa6 --- /dev/null +++ b/tests/vm/tnewseqofcap.nim @@ -0,0 +1,14 @@ +const + foo = @["aaa", "bbb", "ccc"] + +proc myTuple: tuple[n: int, bar: seq[string]] = + result.n = 42 + result.bar = newSeqOfCap[string](foo.len) + for f in foo: + result.bar.add(f) + +# It works if you change the below `const` to `let` +const + (n, bar) = myTuple() + +doAssert bar == @["aaa", "bbb", "ccc"] \ No newline at end of file diff --git a/tests/vm/tnilclosurecall.nim b/tests/vm/tnilclosurecall.nim new file mode 100644 index 000000000..449865b9c --- /dev/null +++ b/tests/vm/tnilclosurecall.nim @@ -0,0 +1,8 @@ +discard """ + errormsg: "attempt to call nil closure" + line: 8 +""" + +static: + let x: proc () = nil + x() diff --git a/tests/vm/tnilclosurecallstacktrace.nim b/tests/vm/tnilclosurecallstacktrace.nim new file mode 100644 index 000000000..879060e8e --- /dev/null +++ b/tests/vm/tnilclosurecallstacktrace.nim @@ -0,0 +1,23 @@ +discard """ + action: reject + nimout: ''' +stack trace: (most recent call last) +tnilclosurecallstacktrace.nim(23, 6) tnilclosurecallstacktrace +tnilclosurecallstacktrace.nim(20, 6) baz +tnilclosurecallstacktrace.nim(17, 6) bar +tnilclosurecallstacktrace.nim(14, 4) foo +tnilclosurecallstacktrace.nim(14, 4) Error: attempt to call nil closure +''' +""" + +proc foo(x: proc ()) = + x() + +proc bar(x: proc ()) = + foo(x) + +proc baz(x: proc ()) = + bar(x) + +static: + baz(nil) diff --git a/tests/vm/tnilref.nim b/tests/vm/tnilref.nim new file mode 100644 index 000000000..5e27cf0cb --- /dev/null +++ b/tests/vm/tnilref.nim @@ -0,0 +1,7 @@ +discard """ + errormsg: "attempt to access a nil address" +""" + +static: + var s: ref int + s[] = 1 \ No newline at end of file diff --git a/tests/vm/tnimnode.nim b/tests/vm/tnimnode.nim new file mode 100644 index 000000000..f1c4d5e5a --- /dev/null +++ b/tests/vm/tnimnode.nim @@ -0,0 +1,80 @@ +import macros + +proc assertEq(arg0,arg1: string): void = + if arg0 != arg1: + raiseAssert("strings not equal:\n" & arg0 & "\n" & arg1) + +# a simple assignment of stmtList to another variable +var node {.compileTime.}: NimNode +# an assignment of stmtList into an array +var nodeArray {.compileTime.}: array[1, NimNode] +# an assignment of stmtList into a seq +var nodeSeq {.compileTime.} = newSeq[NimNode](2) + +proc checkNode(arg: NimNode; name: string): void {. compileTime .} = + echo "checking ", name + + assertEq arg.lispRepr, """(StmtList (DiscardStmt (Empty)))""" + + node = arg + nodeArray = [arg] + nodeSeq[0] = arg + var seqAppend = newSeq[NimNode](0) + seqAppend.add([arg]) # at the time of this writing this works + seqAppend.add(arg) # bit this creates a copy + arg.add newCall(ident"echo", newLit("Hello World")) + + assertEq arg.lispRepr, """(StmtList (DiscardStmt (Empty)) (Call (Ident "echo") (StrLit "Hello World")))""" + assertEq node.lispRepr, """(StmtList (DiscardStmt (Empty)) (Call (Ident "echo") (StrLit "Hello World")))""" + assertEq nodeArray[0].lispRepr, """(StmtList (DiscardStmt (Empty)) (Call (Ident "echo") (StrLit "Hello World")))""" + assertEq nodeSeq[0].lispRepr, """(StmtList (DiscardStmt (Empty)) (Call (Ident "echo") (StrLit "Hello World")))""" + assertEq seqAppend[0].lispRepr, """(StmtList (DiscardStmt (Empty)) (Call (Ident "echo") (StrLit "Hello World")))""" + assertEq seqAppend[1].lispRepr, """(StmtList (DiscardStmt (Empty)) (Call (Ident "echo") (StrLit "Hello World")))""" + + echo "OK" + +# the root node that is used to generate the Ast +var stmtList {.compileTime.}: NimNode + +static: + stmtList = newStmtList(nnkDiscardStmt.newTree(newEmptyNode())) + + checkNode(stmtList, "direct construction") + + +macro foo(stmtList: untyped): untyped = + checkNode(stmtList, "untyped macro argument") + +foo: + discard + + +static: + stmtList = quote do: + discard + + checkNode(newTree(nnkStmtList, stmtList), "create with quote") + + +static: + echo "testing body from loop" + var loop = quote do: + for i in 0 ..< 10: + discard + + let innerBody = loop[2] + innerBody.add newCall(ident"echo", newLit("Hello World")) + + assertEq loop[2].lispRepr, innerBody.lispRepr + + echo "OK" + + +static: + echo "testing creation of comment node" + var docComment: NimNode = newNimNode(nnkCommentStmt) + docComment.strVal = "This is a doc comment" + + assertEq repr(docComment), "## This is a doc comment" + + echo "OK" diff --git a/tests/vm/tnocompiletimefunc.nim b/tests/vm/tnocompiletimefunc.nim new file mode 100644 index 000000000..a95648c0f --- /dev/null +++ b/tests/vm/tnocompiletimefunc.nim @@ -0,0 +1,14 @@ +discard """ + errormsg: "request to generate code for .compileTime proc: foo" +""" + +# ensure compileTime funcs can't be called from runtime + +func foo(a: int): int {.compileTime.} = + a * a + +proc doAThing(): int = + for i in 0..2: + result += foo(i) + +echo doAThing() diff --git a/tests/vm/tnocompiletimefunclambda.nim b/tests/vm/tnocompiletimefunclambda.nim new file mode 100644 index 000000000..d134eea40 --- /dev/null +++ b/tests/vm/tnocompiletimefunclambda.nim @@ -0,0 +1,6 @@ +discard """ + errormsg: "request to generate code for .compileTime proc: :anonymous" +""" + +let a = func(a: varargs[int]) {.compileTime, closure.} = + discard a[0] \ No newline at end of file diff --git a/tests/vm/tnoreturn.nim b/tests/vm/tnoreturn.nim new file mode 100644 index 000000000..d4f8601a9 --- /dev/null +++ b/tests/vm/tnoreturn.nim @@ -0,0 +1,32 @@ +block: # issue #22216 + type + Result[T, E] = object + case oVal: bool + of false: + eVal: E + of true: + vVal: T + + func raiseResultDefect(m: string) {.noreturn, noinline.} = + raise (ref Defect)(msg: m) + + template withAssertOk(self: Result, body: untyped): untyped = + case self.oVal + of false: + raiseResultDefect("Trying to access value with err Result") + else: + body + + func value[T, E](self: Result[T, E]): T {.inline.} = + withAssertOk(self): + self.vVal + + const + x = Result[int, string](oVal: true, vVal: 123) + z = x.value() + + let + xx = Result[int, string](oVal: true, vVal: 123) + zz = x.value() + + doAssert z == zz diff --git a/tests/vm/topenarrays.nim b/tests/vm/topenarrays.nim new file mode 100644 index 000000000..375d2523d --- /dev/null +++ b/tests/vm/topenarrays.nim @@ -0,0 +1,89 @@ +proc mutate(a: var openarray[int]) = + var i = 0 + for x in a.mitems: + x = i + inc i + +proc mutate(a: var openarray[char]) = + var i = 1 + for ch in a.mitems: + ch = 'a' + + +static: + var a = [10, 20, 30] + assert a.toOpenArray(1, 2).len == 2 + + mutate(a) + assert a.toOpenArray(0, 2) == [0, 1, 2] + assert a.toOpenArray(0, 0) == [0] + assert a.toOpenArray(1, 2) == [1, 2] + assert "Hello".toOpenArray(1, 4) == "ello" + var str = "Hello" + str.toOpenArray(2, 4).mutate() + assert str.toOpenArray(0, 4).len == 5 + assert str.toOpenArray(0, 0).len == 1 + assert str.toOpenArray(0, 0).high == 0 + assert str == "Heaaa" + assert str.toOpenArray(0, 4) == "Heaaa" + + var arr: array[3..4, int] = [1, 2] + assert arr.toOpenArray(3, 4) == [1, 2] + assert arr.toOpenArray(3, 4).len == 2 + assert arr.toOpenArray(3, 3).high == 0 + + assert arr.toOpenArray(3, 4).toOpenArray(0, 0) == [1] + + +proc doThing(s: static openArray[int]) = discard + +doThing([10, 20, 30].toOpenArray(0, 0)) + +# bug #19969 +proc f(): array[1, byte] = + var a: array[1, byte] + result[0..0] = a.toOpenArray(0, 0) + +doAssert static(f()) == [byte(0)] + + +# bug #15952 +proc main1[T](a: openArray[T]) = discard +proc main2[T](a: var openArray[T]) = discard + +proc main = + var a = [1,2,3,4,5] + main1(a.toOpenArray(1,3)) + main2(a.toOpenArray(1,3)) +static: main() +main() + +# bug #16306 +{.experimental: "views".} +proc test(x: openArray[int]): tuple[id: int] = + let y: openArray[int] = toOpenArray(x, 0, 2) + result = (y[0],) +template fn= + doAssert test([0,1,2,3,4,5]).id == 0 +fn() # ok +static: fn() + + +block: # bug #22095 + type + StUint = object + limbs: array[4, uint64] + + func shlAddMod(a: var openArray[uint64]) = + a[0] = 10 + + func divRem(r: var openArray[uint64]) = + shlAddMod(r.toOpenArray(0, 3)) + + func fn(): StUint = + divRem(result.limbs) + + const + z = fn() + + doAssert z.limbs[0] == 10 diff --git a/tests/vm/toverflowopcaddimmint.nim b/tests/vm/toverflowopcaddimmint.nim new file mode 100644 index 000000000..4ff614e5b --- /dev/null +++ b/tests/vm/toverflowopcaddimmint.nim @@ -0,0 +1,11 @@ +discard """ + errormsg: "over- or underflow" +""" + +static: + proc p = + var + x = int64.high + discard x + 1 + doAssert false + p() diff --git a/tests/vm/toverflowopcaddint.nim b/tests/vm/toverflowopcaddint.nim new file mode 100644 index 000000000..d494245b1 --- /dev/null +++ b/tests/vm/toverflowopcaddint.nim @@ -0,0 +1,12 @@ +discard """ + errormsg: "over- or underflow" +""" + +static: + proc p = + var + x = int64.high + y = 1 + discard x + y + doAssert false + p() diff --git a/tests/vm/toverflowopcmulint.nim b/tests/vm/toverflowopcmulint.nim new file mode 100644 index 000000000..936eea6c2 --- /dev/null +++ b/tests/vm/toverflowopcmulint.nim @@ -0,0 +1,11 @@ +discard """ + errormsg: "over- or underflow" +""" + +static: + proc p = + var + x = 1'i64 shl 62 + discard x * 2 + doAssert false + p() diff --git a/tests/vm/toverflowopcsubimmint.nim b/tests/vm/toverflowopcsubimmint.nim new file mode 100644 index 000000000..08356590c --- /dev/null +++ b/tests/vm/toverflowopcsubimmint.nim @@ -0,0 +1,10 @@ +discard """ + errormsg: "over- or underflow" +""" + +static: + proc p = + var x = int64.low + discard x - 1 + doAssert false + p() diff --git a/tests/vm/toverflowopcsubint.nim b/tests/vm/toverflowopcsubint.nim new file mode 100644 index 000000000..74e34c6a4 --- /dev/null +++ b/tests/vm/toverflowopcsubint.nim @@ -0,0 +1,12 @@ +discard """ + errormsg: "over- or underflow" +""" + +static: + proc p = + var + x = int64.low + y = 1 + discard x - y + doAssert false + p() diff --git a/tests/vm/tquadplus.nim b/tests/vm/tquadplus.nim new file mode 100644 index 000000000..acf20cd96 --- /dev/null +++ b/tests/vm/tquadplus.nim @@ -0,0 +1,14 @@ +# bug #1023 + + +type Quadruple = tuple[a, b, c, d: int] + +proc `+`(s, t: Quadruple): Quadruple = + (a: s.a + t.a, b: s.b + t.b, c: s.c + t.c, d: s.d + t.d) + +const + A = (a: 0, b: -1, c: 0, d: 1) + B = (a: 0, b: -2, c: 1, d: 0) + C = A + B + +doAssert $C.d & " == " & $(A+B).d == "1 == 1" diff --git a/tests/vm/tref.nim b/tests/vm/tref.nim new file mode 100644 index 000000000..e70305225 --- /dev/null +++ b/tests/vm/tref.nim @@ -0,0 +1,71 @@ +static: + var + a: ref string + b: ref string + new a + + a[] = "Hello world" + b = a + + b[5] = 'c' + doAssert a[] == "Hellocworld" + doAssert b[] == "Hellocworld" + + proc notGlobal() = + var + a: ref string + b: ref string + new a + + a[] = "Hello world" + b = a + + b[5] = 'c' + doAssert a[] == "Hellocworld" + doAssert b[] == "Hellocworld" + notGlobal() + +static: # bug 6081 + block: + type Obj = object + field: ref int + var i: ref int + new(i) + var r = Obj(field: i) + var rr = r + r.field = nil + doAssert rr.field != nil + + proc foo() = # Proc to avoid special global logic + var s: seq[ref int] + var i: ref int + new(i) + s.add(i) + var head = s[0] + s[0] = nil + doAssert head != nil + + foo() + +static: + + block: # global alias + var s: ref int + new(s) + var ss = s + s[] = 1 + doAssert ss[] == 1 + +static: # bug #8402 + type R = ref object + var empty: R + let otherEmpty = empty + +block: + # fix https://github.com/timotheecour/Nim/issues/88 + template fun() = + var s = @[10,11,12] + var a = s[0].addr + a[] += 100 # was giving SIGSEGV + doAssert a[] == 110 + static: fun() diff --git a/tests/vm/treset.nim b/tests/vm/treset.nim new file mode 100644 index 000000000..32fbc7f04 --- /dev/null +++ b/tests/vm/treset.nim @@ -0,0 +1,50 @@ +static: + type Obj = object + field: int + var o = Obj(field: 1) + reset(o) + doAssert o.field == 0 + + var x = 4 + reset(x) + doAssert x == 0 + +static: + type ObjB = object + field: int + var o = ObjB(field: 1) + o = default(ObjB) + doAssert o.field == 0 + +static: + var i = 2 + reset(i) + doAssert i == 0 + +static: + var i = new int + reset(i) + doAssert i.isNil + +static: + var s = @[1, 2, 3] + reset(s) + doAssert s == @[] + +static: + proc f() = + var i = 2 + reset(i) + doAssert i == 0 + f() + +proc main = + var y = [1, 2, 3, 4] + y = default(array[4, int]) + for a in y: doAssert(a == 0) + + var x = 4 + x = default(int) + doAssert x == 0 + +main() diff --git a/tests/vm/triangle_array.nim b/tests/vm/triangle_array.nim new file mode 100644 index 000000000..0704239c6 --- /dev/null +++ b/tests/vm/triangle_array.nim @@ -0,0 +1,13 @@ +# bug #1781 + +proc initCombinations: array[11, array[11, int]] = + result[0] = [1,2,3,4,5,6,7,8,9,10,11] + result[1][1 .. 10] = [12,13,14,15,16,17,18,19,20,21] + result[2][2 .. 10] = [22,23,24,25,26,27,28,29,30] + result[3][3 .. 10] = [31,32,33,34,35,36,37,38] + result[4][4 .. 10] = [39,40,41,42,43,44,45] + result[5][5 .. 10] = [46,47,48,49,50,51] + result[6][6 .. 10] = [52,53,54,55,56] + +const combinations = initCombinations() +doAssert combinations[6][10] == 56 diff --git a/tests/vm/tscriptcompiletime.nims b/tests/vm/tscriptcompiletime.nims new file mode 100644 index 000000000..daec54bf7 --- /dev/null +++ b/tests/vm/tscriptcompiletime.nims @@ -0,0 +1,9 @@ +discard """ + cmd: "nim e $file" +""" + +import mscriptcompiletime + +macro foo = + doAssert bar == 2 +foo() diff --git a/tests/vm/tseq_badinit.nim b/tests/vm/tseq_badinit.nim new file mode 100644 index 000000000..5fa223c85 --- /dev/null +++ b/tests/vm/tseq_badinit.nim @@ -0,0 +1,58 @@ + +type + AObj = object + i: int + d: float + ATup = tuple + i: int + d: float + MyEnum = enum + E01, E02, E03 + Myrange = range[0..10] + + MyProc = proc (x: int): bool + MyInt = distinct int + MyAlias = MyInt + MySet = set[char] + MyArray = array[4, char] + MySeq = seq[string] + +template test(typename, default: untyped) = + proc `abc typename`(): seq[typename] = + result = newSeq[typename]() + result.add(default) + result.setLen(3) + for i in 0 ..< 2: + result[i] = default + + const constval = `abc typename`() + doAssert(constval == `abc typename`()) + + proc `arr typename`(): array[4, typename] = + for i in 0 ..< 2: + result[i] = default + const constarr = `arr typename`() + doAssert(constarr == `arr typename`()) + +proc even(x: int): bool = x mod 2 == 0 +proc `==`(x, y: MyInt): bool = ord(x) == ord(y) +proc `$`(x: MyInt): string = $ord(x) +proc `$`(x: proc): string = + if x.isNil: "(nil)" else: "funcptr" + +test(int, 0) +test(uint, 0) +test(float, 0.1) +test(char, '0') +test(bool, false) +test(uint8, 2) +test(string, "data") +test(MyProc, even) +test(MyEnum, E02) +test(AObj, AObj()) +test(ATup, (i:11, d:9.99)) +test(Myrange, 4) +test(MyInt, MyInt(4)) +test(MyAlias, MyAlias(4)) +test(MyArray, ['0','1','2','3']) +test(MySeq, @["data"]) diff --git a/tests/vm/tsetlen.nim b/tests/vm/tsetlen.nim new file mode 100644 index 000000000..9fd30f331 --- /dev/null +++ b/tests/vm/tsetlen.nim @@ -0,0 +1,30 @@ +type Foo = object + index: int + +block: + proc fun[T]() = + var foo: T + var n = 10 + + var foos: seq[T] + foos.setLen n + + n.inc + foos.setLen n + + for i in 0 ..< n: + let temp = foos[i] + when T is object: + doAssert temp.index == 0 + when T is ref object: + doAssert temp == nil + doAssert temp == foo + + static: + fun[Foo]() + fun[int]() + fun[float]() + fun[string]() + fun[(int, string)]() + fun[ref Foo]() + fun[seq[int]]() diff --git a/tests/vm/tsignaturehash.nim b/tests/vm/tsignaturehash.nim new file mode 100644 index 000000000..972ec6fb0 --- /dev/null +++ b/tests/vm/tsignaturehash.nim @@ -0,0 +1,20 @@ +# test sym digest is computable at compile time + +import macros, algorithm +import ../../dist/checksums/src/checksums/md5 + +macro testmacro(s: typed{nkSym}): string = + let s = getMD5(signaturehash(s) & " - " & symBodyHash(s)) + result = newStrLitNode(s) + +macro testmacro(s: typed{nkOpenSymChoice|nkClosedSymChoice}): string = + var str = "" + for sym in s: + str &= symBodyHash(sym) + result = newStrLitNode(getMD5(str)) + +# something recursive and/or generic +discard testmacro(testmacro) +discard testmacro(`[]`) +discard testmacro(binarySearch) +discard testmacro(sort) diff --git a/tests/vm/tsimpleglobals.nim b/tests/vm/tsimpleglobals.nim new file mode 100644 index 000000000..7ab665070 --- /dev/null +++ b/tests/vm/tsimpleglobals.nim @@ -0,0 +1,16 @@ +discard """ + nimout: "abc xyz bb" +""" + +# bug #2473 +type + Test = tuple[a,b: string] + +static: + var s:seq[Test] = @[(a:"a", b:"b")] + s[0] = (a:"aa", b:"bb") + + var x: Test + x.a = "abc" + x.b = "xyz" + echo x.a, " ", x.b, " ", s[0].b diff --git a/tests/vm/tslow_tables.nim b/tests/vm/tslow_tables.nim new file mode 100644 index 000000000..e40187f18 --- /dev/null +++ b/tests/vm/tslow_tables.nim @@ -0,0 +1,30 @@ +discard """ + timeout: "7" + action: "compile" + nimout: '''create +search +done''' +""" + +# bug #12195 + +import tables + +type Flop = object + a: array[128, int] # <-- compile time is proportional to array size + +proc hop(): bool = + var v: Table[int, Flop] + + echo "create" + for i in 1..1000: + v.add i, Flop() + + echo "search" + for i in 1..1000: + discard contains(v, i) + + echo "done" + +const r {.used.} = hop() + diff --git a/tests/vm/tslurp.nim b/tests/vm/tslurp.nim new file mode 100644 index 000000000..d762eb079 --- /dev/null +++ b/tests/vm/tslurp.nim @@ -0,0 +1,12 @@ +import os + +template getScriptDir(): string = + parentDir(instantiationInfo(-1, true).filename) + +const + relRes = slurp"./tslurp.nim" + absRes = slurp(getScriptDir() / "tslurp.nim") + +doAssert relRes.len > 200 +doAssert absRes.len > 200 +doAssert relRes == absRes diff --git a/tests/vm/tstaticprintseq.nim b/tests/vm/tstaticprintseq.nim new file mode 100644 index 000000000..f4aab6b7e --- /dev/null +++ b/tests/vm/tstaticprintseq.nim @@ -0,0 +1,92 @@ +discard """ + nimout: '''1 +2 +3 +1 +2 +3 +1 +2 +3 +1 +2 +3 +aa +bb +11 +22 +aa +bb +24 +2147483647 2147483647 +5''' +""" + +const s = @[1,2,3] + +macro foo() = + for e in s: + echo e + +foo() + +static: + for e in s: + echo e + +macro bar(x: static[seq[int]]): untyped = + for e in x: + echo e + +bar s +bar(@[1, 2, 3]) + +type + TData = tuple + letters: seq[string] + numbers: seq[int] + +const data: TData = (@["aa", "bb"], @[11, 22]) + +static: + var m1 = data + for x in m1.letters: echo x + + var m2: TData = data + for x in m2.numbers: echo x + +macro ff(d: static[TData]) = + for x in d.letters: + echo x + +ff(data) + +# bug #1010 + +proc `*==`(x: var int, y: int) {.inline, noSideEffect.} = + ## Binary `*=` operator for ordinals + x = x * y + +proc fac: int = + var x = 1; + for i in 1..4: + x *== i; + return x + +const y = fac() + +static: + echo y + +static: + var foo2 = int32.high + echo foo2, " ", int32.high + +# bug #1329 + +static: + var a: ref int + new(a) + a[] = 5 + + echo a[] diff --git a/tests/vm/tstring_openarray.nim b/tests/vm/tstring_openarray.nim new file mode 100644 index 000000000..9318344f8 --- /dev/null +++ b/tests/vm/tstring_openarray.nim @@ -0,0 +1,33 @@ + +# 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 main() = + 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) + +static: main() +main() diff --git a/tests/vm/tstringnil.nim b/tests/vm/tstringnil.nim new file mode 100644 index 000000000..d5dd4f4c9 --- /dev/null +++ b/tests/vm/tstringnil.nim @@ -0,0 +1,50 @@ +# bug #1744 + +import macros + +type + SuiteTest = object + suiteName: string + suiteDesc: string + testName: string + testDesc: string + testBlock: NimNode + +proc buildSuiteContents(suiteName, suiteDesc, suiteBloc: NimNode): tuple[tests: seq[SuiteTest]] {.compileTime.} = + var + tests:seq[SuiteTest] = @[] + + for child in suiteBloc.children(): + case $child[0].ident: + of "test": + + var testObj = SuiteTest() + if suiteName.kind == nnkNilLit: + testObj.suiteName = "" + else: + testObj.suiteName = $suiteName + if suiteDesc.kind == nnkNilLit: + testObj.suiteDesc = "" + else: + testObj.suiteDesc = suiteDesc.strVal + testObj.testName = $child[1] # should not ever be nil + if child[2].kind == nnkNilLit: + testObj.testDesc = "" + else: + testObj.testDesc = child[2].strVal + testObj.testBlock = child[1] + + tests.add(testObj) + + else: + discard + + return (tests: tests) + +macro suite(suiteName, suiteDesc, suiteBloc: untyped): typed = + let contents = buildSuiteContents(suiteName, suiteDesc, suiteBloc) + +# Test above +suite basics, "Description of such": + test(t5, ""): + doAssert false diff --git a/tests/vm/tswap.nim b/tests/vm/tswap.nim new file mode 100644 index 000000000..bdbe5528c --- /dev/null +++ b/tests/vm/tswap.nim @@ -0,0 +1,34 @@ +discard """ +nimout: ''' +x.data = @[10] +y = @[11] +x.data = @[11] +y = @[10] +@[3, 2, 1] +''' +""" + +# bug #2946 + +proc testSwap(): int {.compiletime.} = + type T = object + data: seq[int] + var x: T + x.data = @[10] + var y = @[11] + echo "x.data = ", x.data + echo "y = ", y + swap(y, x.data) + echo "x.data = ", x.data + echo "y = ", y + result = 99 + +const something = testSwap() + +# bug #15463 +block: + static: + var s = @[1, 2, 3] + swap(s[0], s[2]) + + echo s diff --git a/tests/vm/ttouintconv.nim b/tests/vm/ttouintconv.nim new file mode 100644 index 000000000..8c43a3adb --- /dev/null +++ b/tests/vm/ttouintconv.nim @@ -0,0 +1,84 @@ +import macros + +discard """ +nimout: ''' +8 9 17 +239 255 +61439 65534 65535 +4026531839 4294967294 +17293822569102704639 +18446744073709551614 +18446744073709551615 +127 +32767 +2147483647 +9223372036854775807 +0 +128 +4294967287''' +""" + +#bug #2514 + +macro foo() = + var x = 8'u8 + var y = 9'u16 + var z = 17'u32 + + echo x," ", y," ", z + + var a = 0xEF'u8 + var aa = 0xFF'u8 + echo a, " ", aa + + var b = 0xEFFF'u16 + var bb = 0xFFFE'u16 + var bbb = 0xFFFF'u16 + echo b, " ", bb, " ", bbb + + var c = 0xEFFFFFFF'u32 + var cc = 0xFFFFFFFE'u32 + echo c, " ", cc + + var d = 0xEFFFFFFFFFFFFFFF'u64 + echo d + + var f = 0xFFFFFFFFFFFFFFFE'u64 + echo f + + var g = 0xFFFFFFFFFFFFFFFF'u64 + echo g + + var xx = 0x7F'u8 and 0xFF + echo xx + + var yy = 0x7FFF'u16 + echo yy + + var zz = 0x7FFFFFFF'u32 + echo zz + +macro foo2() = + var xx = 0x7FFFFFFFFFFFFFFF + echo xx + + var yy = 0 + echo yy + + var zz = 0x80'u8 + echo zz + + var ww = -9 + var vv = cast[uint](ww) + var kk = cast[uint32](vv) + echo kk + +foo() +foo2() + +block: + const neg5VM = block: + let x = -5'i8 + uint64(x) + let y = -5'i8 + doAssert uint64(y) == neg5VM diff --git a/tests/vm/ttypedesc.nim b/tests/vm/ttypedesc.nim new file mode 100644 index 000000000..d799e5adb --- /dev/null +++ b/tests/vm/ttypedesc.nim @@ -0,0 +1,31 @@ +block: # issue #15760 + type + Banana = object + SpecialBanana = object + + proc getName(_: type Banana): string = "Banana" + proc getName(_: type SpecialBanana): string = "SpecialBanana" + + proc x[T](): string = + const n = getName(T) # this one works + result = n + + proc y(T: type): string = + const n = getName(T) # this one failed to compile + result = n + + doAssert x[SpecialBanana]() == "SpecialBanana" + doAssert y(SpecialBanana) == "SpecialBanana" + +import macros + +block: # issue #23112 + type Container = object + foo: string + + proc canBeImplicit(t: typedesc) {.compileTime.} = + let tDesc = getType(t) + doAssert tDesc.kind == nnkObjectTy + + static: + canBeImplicit(Container) diff --git a/tests/vm/tunsupportedintfloatcast.nim b/tests/vm/tunsupportedintfloatcast.nim new file mode 100644 index 000000000..d65f10d86 --- /dev/null +++ b/tests/vm/tunsupportedintfloatcast.nim @@ -0,0 +1,3 @@ +static: + echo cast[int32](12.0) #[tt.Error + ^ VM does not support 'cast' from tyFloat with size 8 to tyInt32 with size 4 due to different sizes]# diff --git a/tests/vm/tvarsection.nim b/tests/vm/tvarsection.nim new file mode 100644 index 000000000..cd34bd02e --- /dev/null +++ b/tests/vm/tvarsection.nim @@ -0,0 +1,11 @@ +var + a {.compileTime.} = 2 + b = -1 + c {.compileTime.} = 3 + d = "abc" + +static: + doAssert a == 2 + doAssert c == 3 + +doAssert ($b & $d) == "-1abc" diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim new file mode 100644 index 000000000..6aeac5529 --- /dev/null +++ b/tests/vm/tvmmisc.nim @@ -0,0 +1,796 @@ +import macros +import os + +# bug #4462 +block: + proc foo(t: typedesc) {.compileTime.} = + assert sameType(getType(t), getType(int)) + + static: + foo(int) + +# bug #4412 +block: + proc default[T](t: typedesc[T]): T {.inline.} = discard + + static: + var x = default(type(0)) + +# bug #6379 +import algorithm + +static: + var numArray = [1, 2, 3, 4, -1] + numArray.sort(cmp) + doAssert numArray == [-1, 1, 2, 3, 4] + + var str = "cba" + str.sort(cmp) + doAssert str == "abc" + +# bug #6086 +import math, sequtils, sugar + +block: + proc f: int = + toSeq(10..<10_000).filter( + a => a == ($a).map( + d => (d.ord-'0'.ord).int^4 + ).sum + ).sum + + var a = f() + const b = f() + + doAssert a == b + +block: + proc f(): seq[char] = + result = "hello".map(proc(x: char): char = x) + + var runTime = f() + const compTime = f() + doAssert runTime == compTime + +# #6083 +block: + proc abc(): seq[int] = + result = @[0] + result.setLen(2) + var tmp: int + + for i in 0 ..< 2: + inc tmp + result[i] = tmp + + const fact1000 = abc() + doAssert fact1000 == @[1, 2] + +# Tests for VM ops +block: + static: + # for joint test, the project path is different, so I disabled it: + when false: + doAssert "vm" in getProjectPath() + + let b = getEnv("UNSETENVVAR") + doAssert b == "" + doAssert existsEnv("UNSERENVVAR") == false + putEnv("UNSETENVVAR", "VALUE") + doAssert getEnv("UNSETENVVAR") == "VALUE" + doAssert existsEnv("UNSETENVVAR") == true + + doAssert fileExists("MISSINGFILE") == false + doAssert dirExists("MISSINGDIR") == false + doAssert fileExists(currentSourcePath()) + doAssert dirExists(currentSourcePath().parentDir) + +# bug #7210 +block: + static: + proc f(size: int): int = + var some = newStringOfCap(size) + result = size + doAssert f(4) == 4 + +# bug #6689 +block: + static: + proc foo(): int = 0 + var f: proc(): int + doAssert f.isNil + f = foo + doAssert(not f.isNil) + +block: + static: + var x: ref ref int + new(x) + doAssert(not x.isNil) + +# bug #7871 +static: + type Obj = object + field: int + var s = newSeq[Obj](1) + var o = Obj() + s[0] = o + o.field = 2 + doAssert s[0].field == 0 + +# bug #8125 +static: + let def_iter_var = ident("it") + +# bug #8142 +static: + type Obj = object + names: string + + proc pushName(o: var Obj) = + var s = "" + s.add("FOOBAR") + o.names.add(s) + + var o = Obj() + o.names = "" + o.pushName() + o.pushName() + doAssert o.names == "FOOBARFOOBAR" + +# bug #8154 +import parseutils + +static: + type Obj = object + i: int + + proc foo(): Obj = + discard parseInt("1", result.i, 0) + + static: + doAssert foo().i == 1 + +# bug #10333 +block: + const + encoding: auto = [ + ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"], + ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"], + ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"], + ["", "M", "MM", "MMM", "--", "-", "--", "---", "----", "--"], + ] + doAssert encoding.len == 4 + +# bug #10886 + +proc tor(): bool = + result = true + result = false or result + +proc tand(): bool = + result = false + result = true and result + +const + ctor = tor() + ctand = not tand() + +static: + doAssert ctor + doAssert ctand + +block: # bug #13081 + type Kind = enum + k0, k1, k2, k3 + + type Foo = object + x0: float + case kind: Kind + of k0: discard + of k1: x1: int + of k2: x2: string + of k3: x3: string + + const j1 = Foo(x0: 1.2, kind: k1, x1: 12) + const j2 = Foo(x0: 1.3, kind: k2, x2: "abc") + const j3 = Foo(x0: 1.3, kind: k3, x3: "abc2") + static: + doAssert $j1 == "(x0: 1.2, kind: k1, x1: 12)" + doAssert $j2 == """(x0: 1.3, kind: k2, x2: "abc")""" + doAssert $j3 == """(x0: 1.3, kind: k3, x3: "abc2")""" + doAssert $j1 == "(x0: 1.2, kind: k1, x1: 12)" + doAssert $j2 == """(x0: 1.3, kind: k2, x2: "abc")""" + doAssert $j3 == """(x0: 1.3, kind: k3, x3: "abc2")""" + + doAssert j1.x1 == 12 + static: + doAssert j1.x1 == 12 + +block: # bug #15595 + proc fn0()=echo 0 + proc fn1()=discard + proc main= + var local = 0 + proc fn2()=echo local + var a0 = fn0 + var a1 = fn1 + var a2 = fn2 + var a3: proc() + var a4: proc() + doAssert a0 == fn0 # bugfix + doAssert a1 == fn1 # ditto + doAssert a2 == fn2 # ditto + + doAssert fn0 != fn1 + + doAssert a2 != nil + doAssert a3 == nil # bugfix + + doAssert a3 == a4 # bugfix + static: main() + main() + +block: # issue #20543 + type F = proc() + const myArray = block: + var r: array[1, F] + r[0] = nil + r + doAssert isNil(myArray[0]) + +# bug #15363 +import sequtils + +block: + func identity(a: bool): bool = a + + var a: seq[bool] = static: + newSeq[bool](0).mapIt(it) # segfaults + var b: seq[bool] = static: + newSeq[bool](0).filterIt(it) # does not segfault + var c: seq[bool] = static: + newSeq[bool](0).map(identity) # does not segfault + var d: seq[bool] = static: + newSeq[bool](0).map(proc (a: bool): bool = false) # segfaults + var e: seq[bool] = static: + newSeq[bool](0).filter(identity) # does not segfault + var f: seq[bool] = static: + newSeq[bool](0).filter(proc (a: bool): bool = false) # segfaults + + doAssert a == @[] + doAssert b == @[] + doAssert c == @[] + doAssert d == @[] + doAssert e == @[] + doAssert f == @[] + + +block: # bug #18310 + macro t() : untyped = + let + x = nnkTupleConstr.newTree(newLit(1)) + y = nnkTupleConstr.newTree(newLit(2)) + doAssert not (x == y) # not using != intentionally + doAssert not(cast[int](x) == cast[int](y)) + doAssert not(system.`==`(x, y)) + doAssert system.`==`(x, x) + t() + +block: # bug #10815 + type + Opcode = enum + iChar, iSet + + Inst = object + case code: Opcode + of iChar: + c: char + of iSet: + cs: set[char] + + Patt = seq[Inst] + + + proc `$`(p: Patt): string = + discard + + proc P(): Patt = + result.add Inst(code: iSet) + + const a = P() + doAssert $a == "" + +import tables + +block: # bug #8007 + type + CostKind = enum + Fixed, + Dynamic + + Cost = object + case kind*: CostKind + of Fixed: + cost*: int + of Dynamic: + handler*: proc(value: int): int {.nimcall.} + + proc foo(value: int): int {.nimcall.} = + sizeof(value) + + const a: array[2, Cost] =[ + Cost(kind: Fixed, cost: 999), + Cost(kind: Dynamic, handler: foo) + ] + + # OK with arrays & object variants + doAssert $a == "[(kind: Fixed, cost: 999), (kind: Dynamic, handler: ...)]" + + const b: Table[int, Cost] = { + 0: Cost(kind: Fixed, cost: 999), + 1: Cost(kind: Dynamic, handler: foo) + }.toTable + + # KO with Tables & object variants + # echo b # {0: (kind: Fixed, cost: 0), 1: (kind: Dynamic, handler: ...)} # <----- wrong behaviour + doAssert $b == "{0: (kind: Fixed, cost: 999), 1: (kind: Dynamic, handler: ...)}" + + const c: Table[int, int] = { + 0: 100, + 1: 999 + }.toTable + + # OK with Tables and primitive int + doAssert $c == "{0: 100, 1: 999}" + + # For some reason the following gives + # Error: invalid type for const: Cost + const d0 = Cost(kind: Fixed, cost: 999) + + # OK with seq & object variants + const d = @[Cost(kind: Fixed, cost: 999), Cost(kind: Dynamic, handler: foo)] + doAssert $d == "@[(kind: Fixed, cost: 999), (kind: Dynamic, handler: ...)]" + +block: # bug #14340 + block: + proc opl3EnvelopeCalcSin0() = discard + type EnvelopeSinfunc = proc() {.nimcall.} # todo: fixme + # const EnvelopeCalcSin0 = opl3EnvelopeCalcSin0 # ok + const EnvelopeCalcSin0: EnvelopeSinfunc = opl3EnvelopeCalcSin0 # was bug + const envelopeSin = [EnvelopeCalcSin0] + var a = 0 + envelopeSin[a]() + + block: + type Mutator = proc() {.noSideEffect, gcsafe.} + proc mutator0() = discard + const mTable = [Mutator(mutator0)] + var i=0 + mTable[i]() + +block: # VM wrong register free causes errors in unrelated code + block: # bug #15597 + #[ + Error: unhandled exception: 'sym' is not accessible using discriminant 'kind' of type 'TNode' [FieldDefect] + in /Users/timothee/git_clone/nim/Nim_prs/compiler/vm.nim(1176) rawExecute + in opcIndCall + in let prc = if not isClosure: bb.sym else: bb[0].sym + ]# + proc bar2(head: string): string = "asdf" + proc zook(u1: int) = discard + + type PathEntry = object + kind: int + path: string + + iterator globOpt(): int = + var u1: int + + zook(u1) + zook(u1) + zook(u1) + zook(u1) + zook(u1) + zook(u1) + zook(u1) + zook(u1) + zook(u1) + zook(u1) + zook(u1) + zook(u1) + zook(u1) + zook(u1) + + var entry = PathEntry() + entry.path = bar2("") + if false: + echo "here2" + + proc processAux(a: float) = discard + + template bar(iter: untyped): untyped = + var ret: float + for x in iter: break + ret + + proc main() = + processAux(bar(globOpt())) + static: main() + + block: # ditto + # D20201024T133245 + type Deque = object + proc initDeque2(initialSize: int = 4): Deque = Deque() + proc len2(a: Deque): int = 2 + proc baz(dir: string): bool = true + proc bar2(head: string): string = "asdf" + proc bar3(path: var string) = path = path + + type PathEntry = object + kind: int + path: string + + proc initGlobOpt(dir: string, a1=false,a2=false,a3=false,a4=false): string = dir + + iterator globOpt(dir: string): int = + var stack = initDeque2() + doAssert baz("") + let z = stack.len2 + if stack.len2 >= 0: + var entry = PathEntry() + let current = if true: stack.len2 else: stack.len2 + entry.path = bar2("") + bar3(entry.path) + if false: + echo "here2" # comment here => you get same error as https://github.com/nim-lang/Nim/issues/15704 + + proc processAux(a: float) = discard + + template bar(iter: untyped): untyped = + var ret: float + for x in iter: break + ret + proc main() = + processAux(bar(globOpt(initGlobOpt(".")))) + static: main() + + block: # bug #15704 + #[ + Error: attempt to access a nil address kind: rkFloat + ]# + type Deque = object + proc initDeque2(initialSize: int = 4): Deque = Deque() + proc len2(a: Deque): int = 2 + + proc baz(dir: string): bool = true + proc bar2(head: string): string = "asdf" + proc bar3(path: var string) = path = path + + type PathEntry = object + kind: int + path: string + depth: int + + proc initGlobOpt(dir: string, a1=false,a2=false,a3=false,a4=false): string = + dir + + iterator globOpt(dir: string): int = + var stack = initDeque2() + doAssert baz("") + let z = stack.len2 + var a5: int + if stack.len2 >= 0: + var entry = PathEntry() + if false: + echo "here" + let current = if true: stack.len2 else: stack.len2 + entry.depth = 1 + entry.path = bar2("") + bar3(entry.path) + proc processAux(a: float) = discard + template bar(iter: untyped): untyped = + var ret: float + for x in iter: + break + ret + const dir = "." + proc main() = + processAux(bar(globOpt(initGlobOpt(dir)))) + static: main() + +block: # bug #8015 + block: + type Foo = object + case b: bool + of false: v1: int + of true: v2: int + const t = [Foo(b: false, v1: 1), Foo(b: true, v2: 2)] + doAssert $t == "[(b: false, v1: 1), (b: true, v2: 2)]" + doAssert $t[0] == "(b: false, v1: 1)" # was failing + + block: + type + CostKind = enum + Fixed, + Dynamic + + Cost = object + case kind*: CostKind + of Fixed: + cost*: int + of Dynamic: + handler*: proc(): int {.nimcall.} + + proc foo1(): int {.nimcall.} = + 100 + + proc foo2(): int {.nimcall.} = + 200 + + # Change to `let` and it doesn't crash + const costTable = [ + 0: Cost(kind: Fixed, cost: 999), + 1: Cost(kind: Dynamic, handler: foo1), + 2: Cost(kind: Dynamic, handler: foo2) + ] + + doAssert $costTable[0] == "(kind: Fixed, cost: 999)" + doAssert costTable[1].handler() == 100 + doAssert costTable[2].handler() == 200 + + # Now trying to carry the table as an object field + type + Wrapper = object + table: array[3, Cost] + + proc procNewWrapper(): Wrapper = + result.table = costTable + + # Alternatively, change to `const` and it doesn't crash + let viaProc = procNewWrapper() + + doAssert viaProc.table[1].handler != nil + doAssert viaProc.table[2].handler != nil + doAssert $viaProc.table[0] == "(kind: Fixed, cost: 999)" + doAssert viaProc.table[1].handler() == 100 + doAssert viaProc.table[2].handler() == 200 + + +# bug #19198 + +block: + type + Foo[n: static int] = int + +block: + static: + let x = int 1 + doAssert $(x.type) == "int" # Foo + +block: + static: + let x = int 1 + let y = x + 1 + # Error: unhandled exception: value out of range: -8 notin 0 .. 65535 [RangeDefect] + doAssert y == 2 + + +type Atom* = object + bar: int + +proc main() = # bug #12994 + var s: seq[Atom] + var atom: Atom + var checked = 0 + for i in 0..<2: + atom.bar = 5 + s.add atom + atom.reset + if i == 0: + checked += 1 + doAssert $s == "@[(bar: 5)]" + else: + checked += 1 + doAssert $s == "@[(bar: 5), (bar: 5)]" + doAssert checked == 2 + +static: main() +main() + +# bug #19201 +proc foo(s: sink string) = doAssert s.len == 3 + +static: + foo("abc") + + +static: + for i in '1' .. '2': # bug #10938 + var s: set[char] + doAssert s == {} + incl(s, i) + + for _ in 0 ..< 3: # bug #13312 + var s: string + s.add("foo") + doAssert s == "foo" + + for i in 1 .. 5: # bug #13918 + var arr: array[3, int] + var val: int + doAssert arr == [0, 0, 0] and val == 0 + for j in 0 ..< len(arr): + arr[j] = i + val = i + +# bug #20985 +let a = block: + var groups: seq[seq[int]] + for i in 0 ..< 3: + var group: seq[int] + for j in 0 ..< 3: + group.add j + groups.add group + groups + +const b = block: + var groups: seq[seq[int]] + for i in 0 ..< 3: + var group: seq[int] + for j in 0 ..< 3: + group.add j + groups.add group + groups + +doAssert a == @[@[0, 1, 2], @[0, 1, 2], @[0, 1, 2]] +doAssert b == @[@[0, 1, 2], @[0, 1, 2], @[0, 1, 2]] + +macro m1(s: string): int = + var ProcID {.global, compileTime.}: int + inc(ProcID) + result = newLit(ProcID) + +proc macroGlobal = + doAssert m1("Macro argument") == 1 + doAssert m1("Macro argument") == 2 + doAssert m1("Macro argument") == 3 + +static: macroGlobal() +macroGlobal() + +block: # bug #10108 + template reject(x) = + static: doAssert(not compiles(x)) + + static: + let x: int = 2 + proc deliver_x(): int = x + var y2 = deliver_x() + discard y2 + reject: + const c5 = deliver_x() + +block: # bug #7590 + proc doInit[T]():auto= + var a: T + return a + + proc fun2[T](tup1:T)= + const tup0=doInit[T]() + + # var tup=tup0 #ok + const tup=tup0 #causes bug + + doAssert tup is tuple + doAssert tup[0] is tuple + for ai in tup.fields: + doAssert ai is tuple, "BUG2" + + # const c=(foo:(bar1: 0.0)) + const c=(foo:(bar1:"foo1")) + fun2(c) + +block: # bug #21708 + type + Tup = tuple[name: string] + + const X: array[2, Tup] = [(name: "foo",), (name: "bar",)] + + static: + let s = X[0] + doAssert s[0] == "foo" + +block: + proc swap[T](x: var T): T = + result = x + x = default(T) + + proc merge[T](a, b: var openArray[T]) = + a[0] = swap b[0] + + static: + var x = "abc" + var y = "356" + merge(x, y) + doAssert x == "3bc" + +block: # bug #22190 + type + EVMFork = enum + Berlin + Istanbul + Shanghai + + const + Vm2OpAllForks = + {EVMFork.low .. EVMFork.high} + + vm2OpExecBlockData = [(forks: Vm2OpAllForks)] + + proc mkOpTable(selected: EVMFork): bool = + selected notin vm2OpExecBlockData[0].forks + + const + tab = mkOpTable(Berlin) + + doAssert not tab + +block: # issue #22524 + const cnst = cstring(nil) + doAssert cnst.isNil + doAssert cnst == nil + let b = cnst + doAssert b.isNil + doAssert b == nil + + let a = static: cstring(nil) + doAssert a.isNil + + static: + var x: cstring + doAssert x.isNil + doAssert x == nil + doAssert x != "" + +block: # issue #15730 + const s: cstring = "" + doAssert s != nil + + static: + let s: cstring = "" + doAssert not s.isNil + doAssert s != nil + doAssert s == "" + +static: # more nil cstring issues + let x = cstring(nil) + doAssert x.len == 0 + +block: # bug #23925 + type Foo = enum A = -1 + proc foo = + doAssert cast[Foo](-1) == A + doAssert ord(A) == -1 + + static: foo() + foo() + + type E = enum + e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 e10 e11 e12 e13 e14 e15 e16 e17 e18 e19 e20 + e21 e22 e23 e24 e25 e26 e27 e28 e29 e30 e31 e32 e33 e34 e35 e36 e37 e38 + e39 e40 e41 e42 e43 e44 e45 e46 e47 e48 e49 e50 e51 e52 e53 e54 e55 e56 + e57 e58 e59 e60 e61 e62 e63 e64 e65 e66 e67 e68 e69 e70 e71 e72 e73 e74 + e75 e76 e77 e78 e79 e80 e81 e82 e83 e84 e85 e86 e87 e88 e89 e90 e91 e92 + e93 e94 e95 e96 e97 e98 e99 e100 e101 e102 e103 e104 e105 e106 e107 e108 + e109 e110 e111 e112 e113 e114 e115 e116 e117 e118 e119 e120 e121 e122 + e123 e124 e125 e126 e127 e128 + proc bar = + doAssert cast[E](int(e128)) == e128 + + static: bar() + bar() + +static: # bug #21353 + var s: proc () = default(proc ()) + doAssert s == nil diff --git a/tests/vm/tvmops.nim b/tests/vm/tvmops.nim new file mode 100644 index 000000000..3d8d5a9ac --- /dev/null +++ b/tests/vm/tvmops.nim @@ -0,0 +1,46 @@ +discard """ + targets: "c cpp js" +""" + +#[ +test for vmops.nim +]# +import os +import math +import strutils + +static: + # TODO: add more tests + block: #getAppFilename, gorgeEx, gorge + const nim = getCurrentCompilerExe() + let ret = gorgeEx(nim & " --version") + doAssert ret.exitCode == 0 + doAssert ret.output.contains "Nim Compiler" + let ret2 = gorgeEx(nim & " --nonxistent") + doAssert ret2.exitCode != 0 + let output3 = gorge(nim & " --version") + doAssert output3.contains "Nim Compiler" + + block: + const key = "D20181210T175037" + const val = "foo" + putEnv(key, val) + doAssert existsEnv(key) + doAssert getEnv(key) == val + + block: + # sanity check (we probably don't need to test for all ops) + const a1 = arcsin 0.3 + let a2 = arcsin 0.3 + doAssert a1 == a2 + + block bitxor: + let x = -1'i32 + let y = 1'i32 + doAssert (x xor y) == -2 + +block: + # Check against bugs like #9176 + doAssert getCurrentCompilerExe() == getCurrentCompilerExe().static + if false: #pending #9176 + doAssert gorgeEx("nonxistent") == gorgeEx("nonxistent").static diff --git a/tests/vm/tvmopsDanger.nim b/tests/vm/tvmopsDanger.nim new file mode 100644 index 000000000..966feffe6 --- /dev/null +++ b/tests/vm/tvmopsDanger.nim @@ -0,0 +1,13 @@ +discard """ + cmd: "nim c --experimental:vmopsDanger -r $file" +""" +when defined(nimPreviewSlimSystem): + import std/assertions +import std/[times, os] + +const foo = getTime() +let bar = foo +doAssert bar > low(Time) + +static: # bug #23932 + doAssert getCurrentDir().len > 0 diff --git a/tests/vm/twrong_concat.nim b/tests/vm/twrong_concat.nim new file mode 100644 index 000000000..59a10bdb9 --- /dev/null +++ b/tests/vm/twrong_concat.nim @@ -0,0 +1,22 @@ +# bug #3804 + +#import sequtils + +type AnObj = ref object + field: string + +#proc aBug(objs: seq[AnObj]) {.compileTime.} = +# discard objs.mapIt(it.field & " bug") + +proc sameBug(objs: seq[AnObj]) {.compileTime.} = + var strSeq = newSeq[string](objs.len) + strSeq[0] = objs[0].field & " bug" + +static: + var objs: seq[AnObj] = @[] + objs.add(AnObj(field: "hello")) + + sameBug(objs) + # sameBug(objs) + echo objs[0].field + doAssert(objs[0].field == "hello") # fails, because (objs[0].field == "hello bug") - mutated! diff --git a/tests/vm/twrongarray.nim b/tests/vm/twrongarray.nim new file mode 100644 index 000000000..7f24290e2 --- /dev/null +++ b/tests/vm/twrongarray.nim @@ -0,0 +1,17 @@ +discard """ + errormsg: "cannot evaluate at compile time: size" + line: 16 +""" + +#bug #1343 + +when false: + proc one(dummy: int, size: int) = + var x: array[size, int] # compile error: constant expression expected + + proc three(size: int) = + var x: array[size * 1, int] # compile error: cannot evaluate at compile time: size + +proc two(dummy: int, size: int) = + var x: array[size * 1, int] # compiles, but shouldn't? + # doAssert(x.len == size) # just for fun diff --git a/tests/vm/twrongconst.nim b/tests/vm/twrongconst.nim new file mode 100644 index 000000000..a329cb578 --- /dev/null +++ b/tests/vm/twrongconst.nim @@ -0,0 +1,9 @@ +discard """ + errormsg: "cannot evaluate at compile time: x" + line: 7 +""" + +var x: array[100, char] +template foo : char = x[42] + +const myConst = foo diff --git a/tests/vm/twrongwhen.nim b/tests/vm/twrongwhen.nim new file mode 100644 index 000000000..d67e42883 --- /dev/null +++ b/tests/vm/twrongwhen.nim @@ -0,0 +1,13 @@ +discard """ + errormsg: "cannot evaluate at compile time: x" + line: 7 +""" + +proc bla(x:int) = + when x == 0: + echo "oops" + else: + echo "good" + +bla(2) # echos "oops" + diff --git a/tests/vm/tyaytypedesc.nim b/tests/vm/tyaytypedesc.nim new file mode 100644 index 000000000..8cb402bff --- /dev/null +++ b/tests/vm/tyaytypedesc.nim @@ -0,0 +1,17 @@ +# bug #3357 + +type NodeType* = enum + ntWhitespace + +type TokenType* = enum + ttWhitespace + +proc enumTable*[A, B, C](a: openArray[tuple[key: A, val: B]], ret: typedesc[C]): C = + for item in a: + result[item.key] = item.val + +const tokenTypeToNodeType = { + ttWhitespace: ntWhitespace, +}.enumTable(array[ttWhitespace..ttWhitespace, NodeType]) + +doAssert tokenTypeToNodeType[ttWhitespace] == ntWhitespace diff --git a/tests/vm/tzero_extend.nim b/tests/vm/tzero_extend.nim new file mode 100644 index 000000000..418dbc486 --- /dev/null +++ b/tests/vm/tzero_extend.nim @@ -0,0 +1,44 @@ + +const RANGE = -384.. -127 + +proc get_values(): (seq[int8], seq[int16], seq[int32]) = + let i8 = -3'i8 + let i16 = -3'i16 + let i32 = -3'i32 + doAssert int(cast[uint8](i8)) == 0xFD + doAssert int64(cast[uint8](i8)) == 0xFD + doAssert int(cast[uint16](i16)) == 0xFFFD + doAssert int64(cast[uint16](i16)) == 0xFFFD + + result[0] = @[]; result[1] = @[]; result[2] = @[] + + for offset in RANGE: + let i8 = -(1'i64 shl 9) + offset + let i16 = -(1'i64 shl 17) + offset + let i32 = -(1'i64 shl 33) + offset + + # higher bits are masked. these should be exactly equal to offset. + result[0].add cast[int8](cast[uint64](i8)) + result[1].add cast[int16](cast[uint64](i16)) + result[2].add cast[int32](cast[uint64](i32)) + + +# these values this computed by VM +const COMPILETIME_VALUES = get_values() + +# these values this computed by compiler +let RUNTIME_VALUES = get_values() + +template check_values(int_type: static[int]) = + var index = 0 + let cvalues = COMPILETIME_VALUES[int_type] + let rvalues = RUNTIME_VALUES[int_type] + for offset in RANGE: + let moffset = cast[type(rvalues[0])](offset) + doAssert(moffset == rvalues[index] and moffset == cvalues[index], + "expected: " & $moffset & " got runtime: " & $rvalues[index] & " && compiletime: " & $cvalues[index] ) + inc(index) + +check_values(0) # uint8 +check_values(1) # uint16 +check_values(2) # uint32 |