diff options
author | Simon Hafner <hafnersimon@gmail.com> | 2015-05-13 12:06:05 -0500 |
---|---|---|
committer | Simon Hafner <hafnersimon@gmail.com> | 2015-05-13 12:06:05 -0500 |
commit | 9c4a74637db266c3cfcffcfb1e65bae982c6e4bf (patch) | |
tree | 495f50a989d7ab696ddb0b7b0e815c572ab27f3c /tests | |
parent | c55f884b5c0ebc0b637138a8de446ba1fd05acdf (diff) | |
parent | 0b184f2584221543a7dec9c8ae4a700533919e0c (diff) | |
download | Nim-9c4a74637db266c3cfcffcfb1e65bae982c6e4bf.tar.gz |
Merge branch 'devel' into jpoirier-realtimeGCTest
Diffstat (limited to 'tests')
71 files changed, 2030 insertions, 242 deletions
diff --git a/tests/assert/tfailedassert.nim b/tests/assert/tfailedassert.nim index 729cdcac7..1e6764471 100644 --- a/tests/assert/tfailedassert.nim +++ b/tests/assert/tfailedassert.nim @@ -30,7 +30,7 @@ proc bar: int = # local overrides that are active only # in this proc onFailedAssert(msg): echo "WARNING: " & msg - + assert(false, "first assertion from bar") onFailedAssert(msg): diff --git a/tests/assign/moverload_asgn2.nim b/tests/assign/moverload_asgn2.nim new file mode 100644 index 000000000..6620adbeb --- /dev/null +++ b/tests/assign/moverload_asgn2.nim @@ -0,0 +1,10 @@ +type + Concrete* = object + a*, b*: string + rc*: int # refcount + +proc `=`(d: var Concrete; src: Concrete) = + shallowCopy(d.a, src.a) + shallowCopy(d.b, src.b) + dec d.rc + d.rc = src.rc + 1 diff --git a/tests/assign/toverload_asgn1.nim b/tests/assign/toverload_asgn1.nim new file mode 100644 index 000000000..dbc3a71c4 --- /dev/null +++ b/tests/assign/toverload_asgn1.nim @@ -0,0 +1,75 @@ +discard """ + output: '''Concrete '=' +Concrete '=' +Concrete '=' +Concrete '=' +Concrete '=' +GenericT[T] '=' int +GenericT[T] '=' float +GenericT[T] '=' float +GenericT[T] '=' float +GenericT[T] '=' string +GenericT[T] '=' int8 +GenericT[T] '=' bool +GenericT[T] '=' bool +GenericT[T] '=' bool +GenericT[T] '=' bool''' +""" + +import typetraits + +type + Concrete = object + a, b: string + +proc `=`(d: var Concrete; src: Concrete) = + shallowCopy(d.a, src.a) + shallowCopy(d.b, src.b) + echo "Concrete '='" + +var x, y: array[0..2, Concrete] +var cA, cB: Concrete + +var cATup, cBTup: tuple[x: int, ha: Concrete] + +x = y +cA = cB +cATup = cBTup + +type + GenericT[T] = object + a, b: T + +proc `=`[T](d: var GenericT[T]; src: GenericT[T]) = + shallowCopy(d.a, src.a) + shallowCopy(d.b, src.b) + echo "GenericT[T] '=' ", type(T).name + +var ag: GenericT[int] +var bg: GenericT[int] + +ag = bg + +var xg, yg: array[0..2, GenericT[float]] +var cAg, cBg: GenericT[string] + +var cATupg, cBTupg: tuple[x: int, ha: GenericT[int8]] + +xg = yg +cAg = cBg +cATupg = cBTupg + +var caSeqg, cbSeqg: seq[GenericT[bool]] +newSeq(cbSeqg, 4) +caSeqg = cbSeqg + +when false: + type + Foo = object + case b: bool + of false: xx: GenericT[int] + of true: yy: bool + + var + a, b: Foo + a = b diff --git a/tests/assign/toverload_asgn2.nim b/tests/assign/toverload_asgn2.nim new file mode 100644 index 000000000..243c90494 --- /dev/null +++ b/tests/assign/toverload_asgn2.nim @@ -0,0 +1,22 @@ +discard """ + output: '''i value 88 +2aa''' +""" + +import moverload_asgn2 + +proc passAround(i: int): Concrete = + echo "i value ", i + result = Concrete(a: "aa", b: "bb", rc: 0) + +proc main = + let + i = 88 + v = passAround(i) + z = v.a + var + x: Concrete + x = v + echo x.rc, z # 2aa + +main() diff --git a/tests/async/tasynctry.nim b/tests/async/tasynctry.nim index 99433b9d8..f77198e2e 100644 --- a/tests/async/tasynctry.nim +++ b/tests/async/tasynctry.nim @@ -82,6 +82,15 @@ proc test3(): Future[int] {.async.} = result = 2 return +proc test4(): Future[int] {.async.} = + try: + discard await foo() + raise newException(ValueError, "Test4") + except OSError: + result = 1 + except: + result = 2 + var x = test() assert x.read @@ -90,3 +99,6 @@ assert x.read var y = test3() assert y.read == 2 + +y = test4() +assert y.read == 2 diff --git a/tests/async/tasynctry2.nim b/tests/async/tasynctry2.nim new file mode 100644 index 000000000..444a058be --- /dev/null +++ b/tests/async/tasynctry2.nim @@ -0,0 +1,16 @@ +discard """ + file: "tasynctry2.nim" + errormsg: "\'yield\' cannot be used within \'try\' in a non-inlined iterator" + line: 15 +""" +import asyncdispatch + +proc foo(): Future[bool] {.async.} = discard + +proc test5(): Future[int] {.async.} = + try: + discard await foo() + raise newException(ValueError, "Test5") + except: + discard await foo() + result = 0 diff --git a/tests/bind/tnicerrorforsymchoice.nim b/tests/bind/tnicerrorforsymchoice.nim index bf6d92927..5145fdcff 100644 --- a/tests/bind/tnicerrorforsymchoice.nim +++ b/tests/bind/tnicerrorforsymchoice.nim @@ -1,17 +1,17 @@ discard """ line: 18 - errormsg: "type mismatch: got (proc (TScgi) | proc (AsyncSocket, StringTableRef, string)" + errormsg: "type mismatch: got (proc (s: TScgi) | proc (client: AsyncSocket, headers: StringTableRef, input: string){.gcsafe, locks: 0.}" """ #bug #442 import scgi, sockets, asyncio, strtabs proc handleSCGIRequest[TScgi: ScgiState | AsyncScgiState](s: TScgi) = discard -proc handleSCGIRequest(client: AsyncSocket, headers: StringTableRef, +proc handleSCGIRequest(client: AsyncSocket, headers: StringTableRef, input: string) = discard -proc test(handle: proc (client: AsyncSocket, headers: StringTableRef, +proc test(handle: proc (client: AsyncSocket, headers: StringTableRef, input: string), b: int) = discard diff --git a/tests/ccgbugs/tarray_equality.nim b/tests/ccgbugs/tarray_equality.nim new file mode 100644 index 000000000..66a953439 --- /dev/null +++ b/tests/ccgbugs/tarray_equality.nim @@ -0,0 +1,15 @@ +discard """ + output: '''true +true''' +""" + +# bug #2489 + +let a = [1] +let b = [1] +echo a == b + +# bug #2498 +var x: array[0, int] +var y: array[0, int] +echo x == y diff --git a/tests/ccgbugs/tpartialcs.nim b/tests/ccgbugs/tpartialcs.nim new file mode 100644 index 000000000..12ff65c37 --- /dev/null +++ b/tests/ccgbugs/tpartialcs.nim @@ -0,0 +1,20 @@ + +# bug #2551 + +type Tup = tuple + A, a: int + +type Obj = object + A, a: int + +var x: Tup # This works. +var y: Obj # This doesn't. + +# bug #2212 + +proc f() = + let + p = 1.0 + P = 0.25 + 0.5 + +f() diff --git a/tests/closure/tinvalidclosure.nim b/tests/closure/tinvalidclosure.nim index 18968a6c6..c9136a736 100644 --- a/tests/closure/tinvalidclosure.nim +++ b/tests/closure/tinvalidclosure.nim @@ -1,6 +1,6 @@ discard """ line: 12 - errormsg: "type mismatch: got (proc (int){.closure, gcsafe, locks: 0.})" + errormsg: "type mismatch: got (proc (x: int){.closure, gcsafe, locks: 0.})" """ proc ugh[T](x: T) {.closure.} = diff --git a/tests/collections/tcounttable.nim b/tests/collections/tcounttable.nim new file mode 100644 index 000000000..ebbb1c8e5 --- /dev/null +++ b/tests/collections/tcounttable.nim @@ -0,0 +1,19 @@ +discard """ + output: "And we get here" +""" + +# bug #2625 + +const s_len = 32 + +import tables +var substr_counts: CountTable[string] = initCountTable[string]() +var my_string = "Hello, this is sadly broken for strings over 64 characters. Note that it *does* appear to work for short strings." +for i in 0..(my_string.len - s_len): + let s = my_string[i..i+s_len-1] + substr_counts[s] = 1 + # substr_counts[s] = substr_counts[s] + 1 # Also breaks, + 2 as well, etc. + # substr_counts.inc(s) # This works + #echo "Iteration ", i + +echo "And we get here" diff --git a/tests/collections/tsets.nim b/tests/collections/tsets.nim index 656c5b3f2..a5bbe8dbd 100644 --- a/tests/collections/tsets.nim +++ b/tests/collections/tsets.nim @@ -1,17 +1,37 @@ -discard """ - output: '''true -true''' -""" - import sets -var - a = initSet[int]() - b = initSet[int]() - c = initSet[string]() -for i in 0..5: a.incl(i) -for i in 1..6: b.incl(i) -for i in 0..5: c.incl($i) +block setEquality: + var + a = initSet[int]() + b = initSet[int]() + c = initSet[string]() + + for i in 0..5: a.incl(i) + for i in 1..6: b.incl(i) + for i in 0..5: c.incl($i) + + doAssert map(a, proc(x: int): int = x + 1) == b + doAssert map(a, proc(x: int): string = $x) == c + + +block setsContainingTuples: + var set = initSet[tuple[i: int, i64: int64, f: float]]() + set.incl( (i: 123, i64: 123'i64, f: 3.14) ) + doAssert set.contains( (i: 123, i64: 123'i64, f: 3.14) ) + doAssert( not set.contains( (i: 456, i64: 789'i64, f: 2.78) ) ) + + +block setWithTuplesWithSeqs: + var s = initSet[tuple[s: seq[int]]]() + s.incl( (s: @[1, 2, 3]) ) + doAssert s.contains( (s: @[1, 2, 3]) ) + doAssert( not s.contains((s: @[4, 5, 6])) ) + + +block setWithSequences: + var s = initSet[seq[int]]() + s.incl( @[1, 2, 3] ) + doAssert s.contains(@[1, 2, 3]) + doAssert( not s.contains(@[4, 5, 6]) ) + -echo map(a, proc(x: int): int = x + 1) == b -echo map(a, proc(x: int): string = $x) == c diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index 3a923610e..a10606843 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -22,15 +22,15 @@ const "---00": 346677844, "0": 34404, "1": 344004, - "10": 34484, + "10": 34484, "11": 34474, "12": 789, "19": 34464, - "2": 344774, "20": 34454, + "2": 344774, "20": 34454, "3": 342244, "30": 34141244, "34": 123456, "4": 3412344, "40": 344114, - "5": 341232144, "50": 344490, + "5": 341232144, "50": 344490, "6": 34214544, "60": 344491, "7": 3434544, "70": 344492, "8": 344544, "80": 344497, @@ -46,7 +46,7 @@ block tableTest1: for x in 0..1: for y in 0..1: assert t[(x,y)] == $x & $y - assert($t == + assert($t == "{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}") block tableTest2: @@ -55,14 +55,16 @@ block tableTest2: t["111"] = 1.000043 t["123"] = 1.23 t.del("111") - + t["012"] = 67.9 t["123"] = 1.5 # test overwriting - + assert t["123"] == 1.5 assert t["111"] == 0.0 # deleted assert(not hasKey(t, "111")) - + assert "123" in t + assert("111" notin t) + for key, val in items(data): t[key] = val.toFloat for key, val in items(data): assert t[key] == val.toFloat diff --git a/tests/collections/ttablesref.nim b/tests/collections/ttablesref.nim index 16b0d831e..0b641ebc7 100644 --- a/tests/collections/ttablesref.nim +++ b/tests/collections/ttablesref.nim @@ -22,15 +22,15 @@ const "---00": 346677844, "0": 34404, "1": 344004, - "10": 34484, + "10": 34484, "11": 34474, "12": 789, "19": 34464, - "2": 344774, "20": 34454, + "2": 344774, "20": 34454, "3": 342244, "30": 34141244, "34": 123456, "4": 3412344, "40": 344114, - "5": 341232144, "50": 344490, + "5": 341232144, "50": 344490, "6": 34214544, "60": 344491, "7": 3434544, "70": 344492, "8": 344544, "80": 344497, @@ -46,7 +46,7 @@ block tableTest1: for x in 0..1: for y in 0..1: assert t[(x,y)] == $x & $y - assert($t == + assert($t == "{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}") block tableTest2: @@ -55,17 +55,19 @@ block tableTest2: t["111"] = 1.000043 t["123"] = 1.23 t.del("111") - + t["012"] = 67.9 t["123"] = 1.5 # test overwriting - + assert t["123"] == 1.5 assert t["111"] == 0.0 # deleted + assert "123" in t assert(not hasKey(t, "111")) - + assert "111" notin t + for key, val in items(data): t[key] = val.toFloat for key, val in items(data): assert t[key] == val.toFloat - + block orderedTableTest1: var t = newOrderedTable[string, int](2) diff --git a/tests/cpp/tcppraise.nim b/tests/cpp/tcppraise.nim new file mode 100644 index 000000000..a9ea8e6ce --- /dev/null +++ b/tests/cpp/tcppraise.nim @@ -0,0 +1,17 @@ +discard """ + cmd: "nim cpp $file" + output: '''foo +bar +Need odd and >= 3 digits## +baz''' +""" + +# bug #1888 +echo "foo" +try: + echo "bar" + raise newException(ValueError, "Need odd and >= 3 digits") +# echo "baz" +except ValueError: + echo getCurrentExceptionMsg(), "##" +echo "baz" diff --git a/tests/cpp/tget_subsystem.nim b/tests/cpp/tget_subsystem.nim new file mode 100644 index 000000000..461914739 --- /dev/null +++ b/tests/cpp/tget_subsystem.nim @@ -0,0 +1,23 @@ +discard """ + cmd: "nim cpp $file" +""" + +{.emit: """ + +namespace System { + struct Input {}; +} + +struct SystemManager { + template <class T> + static T* getSubsystem() { return new T; } +}; + +""".} + +type Input {.importcpp: "System::Input".} = object +proc getSubsystem*[T](): ptr T {. + importcpp: "SystemManager::getSubsystem<'*0>()", nodecl.} + +let input: ptr Input = getSubsystem[Input]() + diff --git a/tests/cpp/tvector_iterator.nim b/tests/cpp/tvector_iterator.nim new file mode 100644 index 000000000..cb5ab33af --- /dev/null +++ b/tests/cpp/tvector_iterator.nim @@ -0,0 +1,19 @@ +discard """ + cmd: "nim cpp $file" +""" + +{.emit: """ + +template <class T> +struct Vector { + struct Iterator {}; +}; + +""".} + +type + Vector {.importcpp: "Vector".} [T] = object + VectorIterator {.importcpp: "Vector<'0>::Iterator".} [T] = object + +var x: VectorIterator[void] + diff --git a/tests/cpp/tvectorseq.nim b/tests/cpp/tvectorseq.nim new file mode 100644 index 000000000..6eb5dc9e4 --- /dev/null +++ b/tests/cpp/tvectorseq.nim @@ -0,0 +1,38 @@ +discard """ + output: '''(x: 1.0) +(x: 0.0)''' + cmd: "nim cpp $file" + disabled: "true" +""" + +# This cannot work yet because we omit type information for importcpp'ed types. +# Fixing this is not hard, but also requires fixing Urhonimo. + +# bug #2536 + +{.emit: """/*TYPESECTION*/ +struct Vector3 { +public: + Vector3(): x(5) {} + Vector3(float x_): x(x_) {} + float x; +}; +""".} + +type Vector3 {.importcpp: "Vector3", nodecl} = object + x: cfloat + +proc constructVector3(a: cfloat): Vector3 {.importcpp: "Vector3(@)", nodecl} + +# hack around another codegen issue: Generics are attached to where they came +# from: +proc `$!`(v: seq[Vector3]): string = "(x: " & $v[0].x & ")" + +proc vec3List*(): seq[Vector3] = + let s = @[constructVector3(cfloat(1))] + echo($!s) + result = s + echo($!result) + +let f = vec3List() +#echo($!f) diff --git a/tests/destructor/tdestructor.nim b/tests/destructor/tdestructor.nim index cbaba3154..639dba941 100644 --- a/tests/destructor/tdestructor.nim +++ b/tests/destructor/tdestructor.nim @@ -40,7 +40,7 @@ type x: A y: B z: C - + TObjKind = enum A, B, C, D TCaseObj = object @@ -57,14 +57,14 @@ type q: TMyGeneric3[TMyObj, int, int] r: string -proc destroy(o: var TMyObj) {.override.} = +proc `=destroy`(o: var TMyObj) = if o.p != nil: dealloc o.p echo "myobj destroyed" -proc destroy(o: var TMyGeneric1) {.override.} = +proc `=destroy`(o: var TMyGeneric1) = echo "mygeneric1 destroyed" -proc destroy[A, B](o: var TMyGeneric2[A, B]) {.override.} = +proc `=destroy`[A, B](o: var TMyGeneric2[A, B]) = echo "mygeneric2 destroyed" proc open: TMyObj = @@ -83,12 +83,12 @@ proc mygeneric1() = proc mygeneric2[T](val: T) = var a = open() - + var b = TMyGeneric2[int, T](x: 10, y: val) echo "mygeneric2 constructed" var c = TMyGeneric3[int, int, string](x: 10, y: 20, z: "test") - + proc mygeneric3 = var x = TMyGeneric3[int, string, TMyGeneric1[int]]( x: 10, y: "test", z: TMyGeneric1[int](x: 10)) @@ -111,11 +111,11 @@ proc caseobj = block: echo "----" var o1 = TCaseObj(kind: A, x: TMyGeneric1[int](x: 10)) - + block: echo "----" var o2 = TCaseObj(kind: B, y: open()) - + block: echo "----" var o3 = TCaseObj(kind: D, innerKind: B, r: "test", diff --git a/tests/destructor/tdestructor2.nim b/tests/destructor/tdestructor2.nim index 6f966d861..34fa466af 100644 --- a/tests/destructor/tdestructor2.nim +++ b/tests/destructor/tdestructor2.nim @@ -5,14 +5,14 @@ discard """ {.experimental.} -type +type TMyObj = object x, y: int p: pointer - -proc destroy(o: var TMyObj) {.override.} = + +proc `=destroy`(o: var TMyObj) = if o.p != nil: dealloc o.p - + proc open: TMyObj = result = TMyObj(x: 1, y: 2, p: alloc(3)) diff --git a/tests/distinct/tdistinct_consts.nim b/tests/distinct/tdistinct_consts.nim new file mode 100644 index 000000000..4f6ced2d2 --- /dev/null +++ b/tests/distinct/tdistinct_consts.nim @@ -0,0 +1,20 @@ + +# bug #2641 + +type MyChar = distinct char +const c:MyChar = MyChar('a') + +type MyBool = distinct bool +const b:MyBool = MyBool(true) + +type MyBoolSet = distinct set[bool] +const bs:MyBoolSet = MyBoolSet({true}) + +type MyCharSet= distinct set[char] +const cs:MyCharSet = MyCharSet({'a'}) + +type MyBoolSeq = distinct seq[bool] +const bseq:MyBoolSeq = MyBoolSeq(@[true, false]) + +type MyBoolArr = distinct array[3, bool] +const barr:MyBoolArr = MyBoolArr([true, false, true]) diff --git a/tests/effects/tgcsafe.nim b/tests/effects/tgcsafe.nim index 0d5109439..d146794b6 100644 --- a/tests/effects/tgcsafe.nim +++ b/tests/effects/tgcsafe.nim @@ -1,5 +1,5 @@ discard """ - line: 16 + line: 17 errormsg: "'mainUnsafe' is not GC-safe" cmd: "nim $target --hints:on --threads:on $options $file" """ diff --git a/tests/exception/texceptionbreak.nim b/tests/exception/texceptionbreak.nim index 76e986787..00dd8ed9f 100644 --- a/tests/exception/texceptionbreak.nim +++ b/tests/exception/texceptionbreak.nim @@ -5,20 +5,20 @@ discard """ # First variety try: - raise newException(EOS, "Problem") -except EOS: + raise newException(OSError, "Problem") +except OSError: for y in [1, 2, 3]: discard try: discard - except EOS: + except OSError: discard echo "1" # Second Variety try: - raise newException(EOS, "Problem") -except EOS: + raise newException(OSError, "Problem") +except OSError: for y in [1, 2, 3]: discard for y in [1, 2, 3]: @@ -28,8 +28,8 @@ echo "2" # Third Variety try: - raise newException(EOS, "Problem") -except EOS: + raise newException(OSError, "Problem") +except OSError: block: break @@ -38,8 +38,8 @@ echo "3" # Fourth Variety block: try: - raise newException(EOS, "Problem") - except EOS: + raise newException(OSError, "Problem") + except OSError: break -echo "4" \ No newline at end of file +echo "4" diff --git a/tests/exception/texceptions.nim b/tests/exception/texceptions.nim index 69b2d0f6a..bdf338599 100644 --- a/tests/exception/texceptions.nim +++ b/tests/exception/texceptions.nim @@ -35,9 +35,9 @@ echo "" proc reraise_in_except = try: echo "BEFORE" - raise newException(EIO, "") + raise newException(IOError, "") - except EIO: + except IOError: echo "EXCEPT" raise @@ -52,7 +52,7 @@ echo "" proc return_in_except = try: echo "BEFORE" - raise newException(EIO, "") + raise newException(IOError, "") except: echo "EXCEPT" diff --git a/tests/exception/texcsub.nim b/tests/exception/texcsub.nim index 3dba357f9..02125d2c0 100644 --- a/tests/exception/texcsub.nim +++ b/tests/exception/texcsub.nim @@ -5,12 +5,12 @@ discard """ # Test inheritance for exception matching: try: - raise newException(EOS, "dummy message") -except E_Base: + raise newException(OSError, "dummy message") +except Exception: echo "caught!" -except: +except: echo "wtf!?" - + #OUT caught! diff --git a/tests/exception/tfinally4.nim b/tests/exception/tfinally4.nim index 05c57c4f5..3aa707ff6 100644 --- a/tests/exception/tfinally4.nim +++ b/tests/exception/tfinally4.nim @@ -8,19 +8,19 @@ discard """ var raiseEx = true var returnA = true var returnB = false - -proc main: int = + +proc main: int = try: #A try: #B if raiseEx: - raise newException(EOS, "") + raise newException(OSError, "") return 3 finally: #B echo "B1" if returnB: return 2 echo "B2" - except EOS: #A + except OSError: #A echo "catch" finally: #A echo "A1" diff --git a/tests/exception/tnestedreturn.nim b/tests/exception/tnestedreturn.nim index 591638f0e..1480764f1 100644 --- a/tests/exception/tnestedreturn.nim +++ b/tests/exception/tnestedreturn.nim @@ -7,7 +7,7 @@ discard """ proc test1() = - finally: echo "A" + defer: echo "A" try: raise newException(OSError, "Problem") @@ -19,7 +19,7 @@ test1() proc test2() = - finally: echo "B" + defer: echo "B" try: return diff --git a/tests/exception/tonraise.nim b/tests/exception/tonraise.nim index 1a555dd94..a155f0b8e 100644 --- a/tests/exception/tonraise.nim +++ b/tests/exception/tonraise.nim @@ -4,8 +4,8 @@ success''' """ type - ESomething = object of E_Base - ESomeOtherErr = object of E_Base + ESomething = object of Exception + ESomeOtherErr = object of Exception proc genErrors(s: string) = if s == "error!": @@ -17,14 +17,14 @@ proc foo() = var i = 0 try: inc i - onRaise(proc (e: ref E_Base): bool = + onRaise(proc (e: ref Exception): bool = echo "i: ", i) genErrors("errssor!") except ESomething: echo("ESomething happened") except: echo("Some other error happened") - + # test that raise handler is gone: try: genErrors("error!") diff --git a/tests/exception/treraise.nim b/tests/exception/treraise.nim index cbd0b5f8a..b2a11d34f 100644 --- a/tests/exception/treraise.nim +++ b/tests/exception/treraise.nim @@ -4,8 +4,8 @@ discard """ exitcode: "1" """ type - ESomething = object of E_Base - ESomeOtherErr = object of E_Base + ESomething = object of Exception + ESomeOtherErr = object of Exception proc genErrors(s: string) = if s == "error!": diff --git a/tests/generics/twrong_generic_object.nim b/tests/generics/twrong_generic_object.nim new file mode 100644 index 000000000..00d90c55e --- /dev/null +++ b/tests/generics/twrong_generic_object.nim @@ -0,0 +1,21 @@ +discard """ + errormsg: "cannot instantiate: 'GenericNodeObj'" + line: 21 +""" +# bug #2509 +type + GenericNodeObj[T] = ref object + obj: T + + Node* = ref object + children*: seq[Node] + parent*: Node + + nodeObj*: GenericNodeObj # [int] + +proc newNode*(nodeObj: GenericNodeObj): Node = + result = Node(nodeObj: nodeObj) + newSeq(result.children, 10) + +var genericObj = GenericNodeObj[int]() +var myNode = newNode(genericObj) diff --git a/tests/js/test2.nim b/tests/js/test2.nim index 5a734358c..1a42fbfda 100644 --- a/tests/js/test2.nim +++ b/tests/js/test2.nim @@ -1,6 +1,7 @@ discard """ output: '''foo -js 3.14''' +js 3.14 +7''' """ # This file tests the JavaScript generator @@ -20,3 +21,11 @@ else: proc foo(val: float): string = "js " & $val echo foo(3.14) + +# #2495 +type C = concept x + +proc test(x: C, T: typedesc): T = + cast[T](x) + +echo 7.test(int8) diff --git a/tests/js/tstringitems.nim b/tests/js/tstringitems.nim new file mode 100644 index 000000000..f4ea02fec --- /dev/null +++ b/tests/js/tstringitems.nim @@ -0,0 +1,24 @@ +discard """ + output: '''Hello +Hello''' +""" + +# bug #2581 + +const someVars = [ "Hello" ] +var someVars2 = [ "Hello" ] + +proc getSomeVar: string = + for i in someVars: + if i == "Hello": + result = i + break + +proc getSomeVar2: string = + for i in someVars2: + if i == "Hello": + result = i + break + +echo getSomeVar() +echo getSomeVar2() diff --git a/tests/js/tunittests.nim b/tests/js/tunittests.nim index af38cd9b9..8a264a5e0 100644 --- a/tests/js/tunittests.nim +++ b/tests/js/tunittests.nim @@ -1,3 +1,10 @@ +discard """ + disabled: "true" +""" + +# Unittest uses lambdalifting at compile-time which we disable for the JS +# codegen! So this cannot and will not work for quite some time. + import unittest suite "Bacon": diff --git a/tests/macros/tlexerex.nim b/tests/macros/tlexerex.nim new file mode 100644 index 000000000..d348a4bcc --- /dev/null +++ b/tests/macros/tlexerex.nim @@ -0,0 +1,16 @@ + +import macros + +macro match*(s: cstring|string; pos: int; sections: untyped): untyped = + for sec in sections.children: + expectKind sec, nnkOfBranch + expectLen sec, 2 + result = newStmtList() + +when isMainModule: + var input = "the input" + var pos = 0 + match input, pos: + of r"[a-zA-Z_]\w+": echo "an identifier" + of r"\d+": echo "an integer" + of r".": echo "something else" diff --git a/tests/macros/treturnsempty.nim b/tests/macros/treturnsempty.nim new file mode 100644 index 000000000..7af26a747 --- /dev/null +++ b/tests/macros/treturnsempty.nim @@ -0,0 +1,12 @@ +discard """ + errormsg: "type mismatch" + line: 11 +""" +# bug #2372 +macro foo(dummy: int): stmt = + discard + +proc takeStr(s: string) = echo s + +takeStr foo(12) + diff --git a/tests/macros/ttryparseexpr.nim b/tests/macros/ttryparseexpr.nim index af932eb7d..c7bbc8e5b 100644 --- a/tests/macros/ttryparseexpr.nim +++ b/tests/macros/ttryparseexpr.nim @@ -15,5 +15,6 @@ const valid = 45 a = test("foo&&") b = test("valid") + c = test("\"") # bug #2504 echo a, " ", b diff --git a/tests/macros/typesapi2.nim b/tests/macros/typesapi2.nim index 016295ba4..2e59d2154 100644 --- a/tests/macros/typesapi2.nim +++ b/tests/macros/typesapi2.nim @@ -1,4 +1,4 @@ -# tests to see if a symbol returned from macros.getType() can +# tests to see if a symbol returned from macros.getType() can # be used as a type import macros @@ -20,7 +20,7 @@ static: assert iii is TestFN proc foo11 : testTypesym(void) = echo "HI!" -static: assert foo11 is proc():void +static: assert foo11 is (proc():void {.nimcall.}) var sss: testTypesym(seq[int]) static: assert sss is seq[int] diff --git a/tests/manyloc/standalone/panicoverride.nim b/tests/manyloc/standalone/panicoverride.nim index efd2b21f9..d9b3f4388 100644 --- a/tests/manyloc/standalone/panicoverride.nim +++ b/tests/manyloc/standalone/panicoverride.nim @@ -7,13 +7,13 @@ proc exit(code: int) {.importc, header: "<stdlib.h>", cdecl.} proc rawoutput(s: string) = printf("%s\n", s) -proc panic(s: string) = +proc panic(s: string) {.noreturn.} = rawoutput(s) exit(1) # Alternatively we also could implement these 2 here: # -# template sysFatal(exceptn: typeDesc, message: string) -# template sysFatal(exceptn: typeDesc, message, arg: string) +# proc sysFatal(exceptn: typeDesc, message: string) {.noReturn.} +# proc sysFatal(exceptn: typeDesc, message, arg: string) {.noReturn.} {.pop.} diff --git a/tests/metatype/tautoproc.nim b/tests/metatype/tautoproc.nim index 562f508fc..ef5377096 100644 --- a/tests/metatype/tautoproc.nim +++ b/tests/metatype/tautoproc.nim @@ -1,11 +1,13 @@ discard """ - errormsg: "expression 'generate(builder)' has no type (or is ambiguous)" + output: "empty" """ # bug #898 +import typetraits + proc measureTime(e: auto) = - discard + echo e.type.name proc generate(a: int): void = discard diff --git a/tests/misc/tcharinc.nim b/tests/misc/tcharinc.nim new file mode 100644 index 000000000..1b5d19c18 --- /dev/null +++ b/tests/misc/tcharinc.nim @@ -0,0 +1,10 @@ +discard """ + output: "1" +""" + +var c = '\0' +while true: + if c == '\xFF': break + inc c + +echo "1" diff --git a/tests/misc/tgtk.nim b/tests/misc/tgtk.nim deleted file mode 100644 index 82227689d..000000000 --- a/tests/misc/tgtk.nim +++ /dev/null @@ -1,53 +0,0 @@ -discard """ - disabled: true -""" -import - gtk2, glib2, atk, gdk2, gdk2pixbuf, libglade2, pango, - pangoutils - -proc hello(widget: PWidget, data: pointer) {.cdecl.} = - write(stdout, "Hello World\n") - -proc delete_event(widget: PWidget, event: PEvent, - data: pointer): bool {.cdecl.} = - # If you return FALSE in the "delete_event" signal handler, - # GTK will emit the "destroy" signal. Returning TRUE means - # you don't want the window to be destroyed. - # This is useful for popping up 'are you sure you want to quit?' - # type dialogs. - write(stdout, "delete event occurred\n") - # Change TRUE to FALSE and the main window will be destroyed with - # a "delete_event". - return false - -# Another callback -proc mydestroy(widget: PWidget, data: pointer) {.cdecl.} = - gtk2.main_quit() - -proc mymain() = - # GtkWidget is the storage type for widgets - gtk2.nimrod_init() - var window = window_new(gtk2.WINDOW_TOPLEVEL) - discard g_signal_connect(window, "delete_event", - Gcallback(delete_event), nil) - discard g_signal_connect(window, "destroy", Gcallback(mydestroy), nil) - # Sets the border width of the window. - set_border_width(window, 10) - - # Creates a new button with the label "Hello World". - var button = button_new("Hello World") - - discard g_signal_connect(button, "clicked", Gcallback(hello), nil) - - # This packs the button into the window (a gtk container). - add(window, button) - - # The final step is to display this newly created widget. - show(button) - - # and the window - show(window) - - gtk2.main() - -mymain() diff --git a/tests/misc/tlibs.nim b/tests/misc/tlibs.nim deleted file mode 100644 index e7a02c7fd..000000000 --- a/tests/misc/tlibs.nim +++ /dev/null @@ -1,28 +0,0 @@ -discard """ - disabled: true -""" - -# Test wether the bindings at least compile... - -import - unicode, cgi, terminal, libcurl, - parsexml, parseopt, parsecfg, - osproc, complex, - sdl, smpeg, sdl_gfx, sdl_net, sdl_mixer, sdl_ttf, - sdl_image, sdl_mixer_nosmpeg, - cursorfont, xatom, xf86vmode, xkb, xrandr, xshm, xvlib, keysym, xcms, xi, - xkblib, xrender, xutil, x, xf86dga, xinerama, xlib, xresource, xv, - gtk2, glib2, pango, gdk2, - cairowin32, cairoxlib, - odbcsql, - gl, glut, glu, glx, glext, wingl, - lua, lualib, lauxlib, mysql, sqlite3, python, tcl, - db_postgres, db_mysql, db_sqlite, ropes, sockets, browsers, httpserver, - httpclient, parseutils, unidecode, xmldom, xmldomparser, xmltree, xmlparser, - htmlparser, re, graphics, colors, pegs, subexes, dialogs - -when defined(linux): - import - zlib, zipfiles - -writeln(stdout, "test compilation of binding modules") diff --git a/tests/misc/tnewlibs.nim b/tests/misc/tnewlibs.nim deleted file mode 100644 index 3b74a9b63..000000000 --- a/tests/misc/tnewlibs.nim +++ /dev/null @@ -1,21 +0,0 @@ -discard """ - disabled: true -""" - -# Test wether the bindings at least compile... - -import - tcl, - sdl, smpeg, sdl_gfx, sdl_net, sdl_mixer, sdl_ttf, - sdl_image, sdl_mixer_nosmpeg, - gtk2, glib2, pango, gdk2, - unicode, cgi, terminal, libcurl, - parsexml, parseopt, parsecfg, - osproc, - cairowin32, cairoxlib, - gl, glut, glu, glx, glext, wingl, - lua, lualib, lauxlib, mysql, sqlite3, db_mongo, md5, asyncio, mimetypes, - cookies, events, ftpclient, scgi, irc - - -writeln(stdout, "test compilation of binding modules") diff --git a/tests/misc/tunsigned64mod.nim b/tests/misc/tunsigned64mod.nim index 9ae0d535a..3007405a2 100644 --- a/tests/misc/tunsigned64mod.nim +++ b/tests/misc/tunsigned64mod.nim @@ -10,3 +10,17 @@ let t1 = v1 mod 2 # works let t2 = 7'u64 mod 2'u64 # works let t3 = v2 mod 2'u64 # Error: invalid type: 'range 0..1(uint64) let t4 = (v2 mod 2'u64).uint64 # works + +# bug #2550 + +var x: uint # doesn't work +echo x mod 2 == 0 + +var y: uint64 # doesn't work +echo y mod 2 == 0 + +var z: uint32 # works +echo z mod 2 == 0 + +var a: int # works +echo a mod 2 == 0 diff --git a/tests/misc/tunsignedinc.nim b/tests/misc/tunsignedinc.nim new file mode 100644 index 000000000..95622156f --- /dev/null +++ b/tests/misc/tunsignedinc.nim @@ -0,0 +1,14 @@ +discard """ + output: '''253''' +""" + +# bug #2427 + +import unsigned + +var x = 0'u8 +dec x # OverflowError +x -= 1 # OverflowError +x = x - 1 # No error + +echo x diff --git a/tests/objects/tillegal_recursion.nim b/tests/objects/tillegal_recursion.nim new file mode 100644 index 000000000..171a04f87 --- /dev/null +++ b/tests/objects/tillegal_recursion.nim @@ -0,0 +1,7 @@ +discard """ + errormsg: "illegal recursion in type 'object'" + line: 7 +""" +# bug #1691 +type + Foo = ref object of Foo diff --git a/tests/objects/tobjloop.nim b/tests/objects/tobjloop.nim new file mode 100644 index 000000000..9fea1e2fb --- /dev/null +++ b/tests/objects/tobjloop.nim @@ -0,0 +1,15 @@ +discard """ + output: "is Nil false" +""" +# bug #1658 + +type + Loop* = ref object + onBeforeSelect*: proc (L: Loop) + +var L: Loop +new L +L.onBeforeSelect = proc (bar: Loop) = + echo "is Nil ", bar.isNil + +L.onBeforeSelect(L) diff --git a/tests/objects/trefobjsyntax2.nim b/tests/objects/trefobjsyntax2.nim new file mode 100644 index 000000000..8ee209cc7 --- /dev/null +++ b/tests/objects/trefobjsyntax2.nim @@ -0,0 +1,19 @@ +# bug #2508 + +type + GenericNodeObj[T] = ref object + obj: T + + Node* = ref object + children*: seq[Node] + parent*: Node + + nodeObj*: GenericNodeObj[int] + +proc newNode*(nodeObj: GenericNodeObj): Node = + result = Node(nodeObj: nodeObj) + newSeq(result.children, 10) + +var genericObj = GenericNodeObj[int]() + +var myNode = newNode(genericObj) diff --git a/tests/overload/tspec.nim b/tests/overload/tspec.nim index 685df503a..f2002a390 100644 --- a/tests/overload/tspec.nim +++ b/tests/overload/tspec.nim @@ -11,7 +11,10 @@ ref T 123 2 1 -@[123, 2, 1]''' +@[123, 2, 1] +Called! +merge with var +merge no var''' """ # Things that's even in the spec now! @@ -79,3 +82,37 @@ proc takeV[T](a: varargs[T]) = takeV([123, 2, 1]) # takeV's T is "int", not "array of int" echo(@[123, 2, 1]) + +# bug #2600 + +type + FutureBase* = ref object of RootObj ## Untyped future. + + Future*[T] = ref object of FutureBase ## Typed future. + value: T ## Stored value + + FutureVar*[T] = distinct Future[T] + +proc newFuture*[T](): Future[T] = + new(result) + +proc newFutureVar*[T](): FutureVar[T] = + result = FutureVar[T](newFuture[T]()) + +proc mget*[T](future: FutureVar[T]): var T = + Future[T](future).value + +proc reset*[T](future: FutureVar[T]) = + echo "Called!" + +proc merge[T](x: Future[T]) = echo "merge no var" +proc merge[T](x: var Future[T]) = echo "merge with var" + +when true: + var foo = newFutureVar[string]() + foo.mget() = "" + foo.mget.add("Foobar") + foo.reset() + var bar = newFuture[int]() + bar.merge # merge with var + merge(newFuture[int]()) # merge no var diff --git a/tests/overload/tstmtoverload.nim b/tests/overload/tstmtoverload.nim new file mode 100644 index 000000000..f1944b637 --- /dev/null +++ b/tests/overload/tstmtoverload.nim @@ -0,0 +1,38 @@ + +# bug #2481 +import math + +template test(loopCount: int, extraI: int, testBody: stmt): stmt = + block: + for i in 0..loopCount-1: + testBody + echo "done extraI=", extraI + +template test(loopCount: int, extraF: float, testBody: stmt): stmt = + block: + test(loopCount, round(extraF), testBody) + +template test(loopCount: int, testBody: stmt): stmt = + block: + test(loopCount, 0, testBody) + echo "done extraI passed 0" + +when isMainModule: + var + loops = 0 + + test 0, 0: + loops += 1 + echo "test 0 complete, loops=", loops + + test 1, 1.0: + loops += 1 + echo "test 1.0 complete, loops=", loops + + when true: + # when true we get the following compile time error: + # b.nim(35, 6) Error: expression 'loops += 1' has no type (or is ambiguous) + loops = 0 + test 2: + loops += 1 + echo "test no extra complete, loops=", loops diff --git a/tests/parallel/tgc_unsafe2.nim b/tests/parallel/tgc_unsafe2.nim new file mode 100644 index 000000000..ec4605fe9 --- /dev/null +++ b/tests/parallel/tgc_unsafe2.nim @@ -0,0 +1,39 @@ +discard """ + line: 28 + nimout: '''tgc_unsafe2.nim(22, 5) Warning: 'trick' is not GC-safe as it accesses 'global' which is a global using GC'ed memory +tgc_unsafe2.nim(26, 5) Warning: 'track' is not GC-safe as it calls 'trick' +tgc_unsafe2.nim(28, 5) Error: 'consumer' is not GC-safe as it calls 'track' +''' + errormsg: "'consumer' is not GC-safe as it calls 'track'" +""" + +import threadpool + +type StringChannel = TChannel[string] +var channels: array[1..3, StringChannel] + +type + MyObject[T] = object + x: T + +var global: MyObject[string] +var globalB: MyObject[float] + +proc trick(ix: int) = + echo global.x + echo channels[ix].recv() + +proc track(ix: int) = trick(ix) + +proc consumer(ix: int) {.thread.} = + track(ix) + +proc main = + for ix in 1..3: channels[ix].open() + for ix in 1..3: spawn consumer(ix) + for ix in 1..3: channels[ix].send("test") + sync() + for ix in 1..3: channels[ix].close() + +when isMainModule: + main() diff --git a/tests/parallel/twrong_refcounts.nim b/tests/parallel/twrong_refcounts.nim new file mode 100644 index 000000000..db32a96d8 --- /dev/null +++ b/tests/parallel/twrong_refcounts.nim @@ -0,0 +1,53 @@ +discard """ + output: "Success" +""" + +import math, threadPool + +# --- + +type + Person = object + age: int + friend: ref Person + +var + people: seq[ref Person] = @[] + +proc newPerson(age:int): ref Person = + result.new() + result.age = age + +proc greet(p:Person) = + #echo p.age, ", ", p.friend.age + p.friend.age += 1 + +# --- + +proc setup = + for i in 0 .. <20: + people.add newPerson(i + 1) + for i in 0 .. <20: + people[i].friend = people[random(20)] + +proc update = + var countA: array[20, int] + var countB: array[20, int] + + for i, p in people: + countA[i] = getRefCount(p) + parallel: + for i in 0 .. people.high: + spawn greet(people[i][]) + for i, p in people: + countB[i] = getRefCount(p) + + for i in 0 .. <20: + doAssert countA[i] == countB[i] + echo "Success" + +# --- + +when isMainModule: + setup() + update() diff --git a/tests/parser/tinvcolonlocation1.nim b/tests/parser/tinvcolonlocation1.nim new file mode 100644 index 000000000..cacde48bd --- /dev/null +++ b/tests/parser/tinvcolonlocation1.nim @@ -0,0 +1,12 @@ +discard """ + file: "tinvcolonlocation1.nim" + line: 8 + column: 3 + errormsg: "':' expected" +""" +try #<- missing ':' + echo "try" +except: + echo "except" +finally: + echo "finally" diff --git a/tests/parser/tinvcolonlocation2.nim b/tests/parser/tinvcolonlocation2.nim new file mode 100644 index 000000000..2b6a92b9d --- /dev/null +++ b/tests/parser/tinvcolonlocation2.nim @@ -0,0 +1,15 @@ +discard """ + file: "tinvcolonlocation2.nim" + line: 11 + column: 1 + errormsg: "':' expected" +""" +try: + echo "try" +except #<- missing ':' + echo "except" +finally: +#<-- error will be here above, at the beginning of finally, +# since compiler tries to consome echo and part of except +# expression + echo "finally" diff --git a/tests/parser/tinvcolonlocation3.nim b/tests/parser/tinvcolonlocation3.nim new file mode 100644 index 000000000..2b30b1dbe --- /dev/null +++ b/tests/parser/tinvcolonlocation3.nim @@ -0,0 +1,12 @@ +discard """ + file: "tinvcolonlocation3.nim" + line: 12 + column: 3 + errormsg: "':' expected" +""" +try: + echo "try" +except: + echo "except" +finally #<- missing ':' + echo "finally" diff --git a/tests/parser/tstrongspaces.nim b/tests/parser/tstrongspaces.nim index 91506daf0..e70b91988 100644 --- a/tests/parser/tstrongspaces.nim +++ b/tests/parser/tstrongspaces.nim @@ -2,6 +2,12 @@ discard """ output: '''35 +true +true +4 +true +1 +false 77 (Field0: 1, Field1: 2, Field2: 2) ha @@ -9,11 +15,26 @@ true tester args all all args +19 +-3 +false +-2 ''' """ echo 2+5 * 5 +# Keyword operators +echo 1 + 16 shl 1 == 1 + (16 shl 1) +echo 2 and 1 in {0, 30} +echo 2+2 * 2 shr 1 +echo false or 2 and 1 in {0, 30} + +proc `^`(a, b: int): int = a + b div 2 +echo 19 mod 16 ^ 4 + 2 and 1 +echo 18 mod 16 ^ 4 > 0 + +# echo $foo gotcha let foo = 77 echo $foo @@ -27,7 +48,7 @@ when true: let b = 66 let c = 90 let bar = 8000 - if foo+4 * 4 == 8 and b&c | 9 ++ + if foo+4 * 4 == 8 and b&c | 9 ++ bar: echo "ho" else: @@ -50,3 +71,13 @@ const echo tester & " " & args|"all" echo "all" | tester & " " & args echo "all"|tester & " " & args + +# Test arrow like operators. See also tests/macros/tclosuremacro.nim +proc `+->`(a, b: int): int = a + b*4 +template `===>`(a, b: int): expr = a - b shr 1 + +echo 3 +-> 2 + 2 and 4 +var arrowed = 3+->2 + 2 and 4 # arrowed = 4 +echo arrowed ===> 15 +echo (2 * 3+->2) == (2*3 +-> 2) +echo arrowed ===> 2 + 3+->2 diff --git a/tests/parser/ttupleunpack.nim b/tests/parser/ttupleunpack.nim new file mode 100644 index 000000000..aaa06f9f4 --- /dev/null +++ b/tests/parser/ttupleunpack.nim @@ -0,0 +1,35 @@ +discard """ + file: "ttupleunpack.nim" + output: "" + exitcode: 0 +""" + +proc returnsTuple(): (int, int, int) = (4, 2, 3) + +proc main2 = + let (x, _, z) = returnsTuple() + +proc main() = + + proc foo(): tuple[x, y, z: int] = + return (4, 2, 3) + + var (x, _, y) = foo() + doAssert x == 4 + doAssert y == 3 + + var (a, _, _) = foo() + doAssert a == 4 + + var (aa, _, _) = foo() + doAssert aa == 4 + + iterator bar(): tuple[x, y, z: int] = + yield (1,2,3) + + for x, y, _ in bar(): + doAssert x == 1 + doAssert y == 2 + +main() +main2() diff --git a/tests/sets/tsets.nim b/tests/sets/tsets.nim index e370209ed..646175329 100644 --- a/tests/sets/tsets.nim +++ b/tests/sets/tsets.nim @@ -1,6 +1,7 @@ discard """ file: "tsets.nim" - output: "Ha ein F ist in s!" + output: '''Ha ein F ist in s! +false''' """ # Test the handling of sets @@ -15,30 +16,30 @@ type TAZ = range['a'..'z'] TAZset = set[TAZ] - TTokType* = enum + TTokType* = enum tkInvalid, tkEof, tkSymbol, - tkAddr, tkAnd, tkAs, tkAsm, tkBlock, tkBreak, tkCase, tkCast, tkConst, - tkContinue, tkConverter, tkDiscard, tkDiv, tkElif, tkElse, tkEnd, tkEnum, - tkExcept, tkException, tkFinally, tkFor, tkFrom, tkGeneric, tkIf, tkImplies, - tkImport, tkIn, tkInclude, tkIs, tkIsnot, tkIterator, tkLambda, tkMacro, - tkMethod, tkMod, tkNil, tkNot, tkNotin, tkObject, tkOf, tkOr, tkOut, tkProc, - tkPtr, tkRaise, tkRecord, tkRef, tkReturn, tkShl, tkShr, tkTemplate, tkTry, + tkAddr, tkAnd, tkAs, tkAsm, tkBlock, tkBreak, tkCase, tkCast, tkConst, + tkContinue, tkConverter, tkDiscard, tkDiv, tkElif, tkElse, tkEnd, tkEnum, + tkExcept, tkException, tkFinally, tkFor, tkFrom, tkGeneric, tkIf, tkImplies, + tkImport, tkIn, tkInclude, tkIs, tkIsnot, tkIterator, tkLambda, tkMacro, + tkMethod, tkMod, tkNil, tkNot, tkNotin, tkObject, tkOf, tkOr, tkOut, tkProc, + tkPtr, tkRaise, tkRecord, tkRef, tkReturn, tkShl, tkShr, tkTemplate, tkTry, tkType, tkVar, tkWhen, tkWhere, tkWhile, tkWith, tkWithout, tkXor, tkYield, - tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit, tkFloatLit, - tkFloat32Lit, tkFloat64Lit, tkStrLit, tkRStrLit, tkTripleStrLit, tkCharLit, - tkRCharLit, tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, - tkCurlyRi, tkBracketDotLe, tkBracketDotRi, - tkCurlyDotLe, tkCurlyDotRi, + tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit, tkFloatLit, + tkFloat32Lit, tkFloat64Lit, tkStrLit, tkRStrLit, tkTripleStrLit, tkCharLit, + tkRCharLit, tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, + tkCurlyRi, tkBracketDotLe, tkBracketDotRi, + tkCurlyDotLe, tkCurlyDotRi, tkParDotLe, tkParDotRi, - tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot, tkHat, tkOpr, + tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot, tkHat, tkOpr, tkComment, tkAccent, tkInd, tkSad, tkDed, tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr TTokTypeRange = range[tkSymbol..tkDed] TTokTypes* = set[TTokTypeRange] const - toktypes: TTokTypes = {TTokTypeRange(tkSymbol)..pred(tkIntLit), + toktypes: TTokTypes = {TTokTypeRange(tkSymbol)..pred(tkIntLit), tkStrLit..tkTripleStrLit} var @@ -62,3 +63,142 @@ for x in low(TTokTypeRange) .. high(TTokTypeRange): #OUT Ha ein F ist in s! +type + TMsgKind* = enum + errUnknown, errIllFormedAstX, errInternal, errCannotOpenFile, errGenerated, + errXCompilerDoesNotSupportCpp, errStringLiteralExpected, + errIntLiteralExpected, errInvalidCharacterConstant, + errClosingTripleQuoteExpected, errClosingQuoteExpected, + errTabulatorsAreNotAllowed, errInvalidToken, errLineTooLong, + errInvalidNumber, errNumberOutOfRange, errNnotAllowedInCharacter, + errClosingBracketExpected, errMissingFinalQuote, errIdentifierExpected, + errNewlineExpected, + errInvalidModuleName, + errOperatorExpected, errTokenExpected, errStringAfterIncludeExpected, + errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected, + errInvalidPragma, errUnknownPragma, errInvalidDirectiveX, + errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation, + errExceptionExpected, errExceptionAlreadyHandled, + errYieldNotAllowedHere, errYieldNotAllowedInTryStmt, + errInvalidNumberOfYieldExpr, errCannotReturnExpr, errAttemptToRedefine, + errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel, + errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected, + errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler, + errOnOrOffExpectedButXFound, errNoneBoehmRefcExpectedButXFound, + errNoneSpeedOrSizeExpectedButXFound, errGuiConsoleOrLibExpectedButXFound, + errUnknownOS, errUnknownCPU, errGenOutExpectedButXFound, + errArgsNeedRunOption, errInvalidMultipleAsgn, errColonOrEqualsExpected, + errExprExpected, errUndeclaredIdentifier, errUseQualifier, errTypeExpected, + errSystemNeeds, errExecutionOfProgramFailed, errNotOverloadable, + errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue, + errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous, + errConstantDivisionByZero, errOrdinalTypeExpected, + errOrdinalOrFloatTypeExpected, errOverOrUnderflow, + errCannotEvalXBecauseIncompletelyDefined, errChrExpectsRange0_255, + errDynlibRequiresExportc, errUndeclaredFieldX, errNilAccess, + errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType, + errValueOutOfSetBounds, errFieldInitTwice, errFieldNotInit, + errExprXCannotBeCalled, errExprHasNoType, errExprXHasNoType, + errCastNotInSafeMode, errExprCannotBeCastedToX, errCommaOrParRiExpected, + errCurlyLeOrParLeExpected, errSectionExpected, errRangeExpected, + errMagicOnlyInSystem, errPowerOfTwoExpected, + errStringMayNotBeEmpty, errCallConvExpected, errProcOnlyOneCallConv, + errSymbolMustBeImported, errExprMustBeBool, errConstExprExpected, + errDuplicateCaseLabel, errRangeIsEmpty, errSelectorMustBeOfCertainTypes, + errSelectorMustBeOrdinal, errOrdXMustNotBeNegative, errLenXinvalid, + errWrongNumberOfVariables, errExprCannotBeRaised, errBreakOnlyInLoop, + errTypeXhasUnknownSize, errConstNeedsConstExpr, errConstNeedsValue, + errResultCannotBeOpenArray, errSizeTooBig, errSetTooBig, + errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects, + errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX, + errCannotInstantiateX, errExprHasNoAddress, errXStackEscape, + errVarForOutParamNeeded, + errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX, + errAmbiguousCallXYZ, errWrongNumberOfArguments, + errXCannotBePassedToProcVar, + errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed, + errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX, + errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice, + errInvalidOrderInArrayConstructor, + errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry, + errOptionExpected, errXisNoLabel, errNotAllCasesCovered, + errUnknownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable, + errNoPragmasAllowedForX, errNoGenericParamsAllowedForX, + errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent, + errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX, + errXNotAllowedHere, errInvalidControlFlowX, + errXisNoType, errCircumNeedsPointer, errInvalidExpression, + errInvalidExpressionX, errEnumHasNoValueX, errNamedExprExpected, + errNamedExprNotAllowed, errXExpectsOneTypeParam, + errArrayExpectsTwoTypeParams, errInvalidVisibilityX, errInitHereNotAllowed, + errXCannotBeAssignedTo, errIteratorNotAllowed, errXNeedsReturnType, + errNoReturnTypeDeclared, + errInvalidCommandX, errXOnlyAtModuleScope, + errXNeedsParamObjectType, + errTemplateInstantiationTooNested, errInstantiationFrom, + errInvalidIndexValueForTuple, errCommandExpectsFilename, + errMainModuleMustBeSpecified, + errXExpected, + errTIsNotAConcreteType, + errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError, + errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile, + errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly, + errOnlyACallOpCanBeDelegator, errUsingNoSymbol, + errMacroBodyDependsOnGenericTypes, + errDestructorNotGenericEnough, + errInlineIteratorsAsProcParams, + errXExpectsTwoArguments, + errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations, + errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX, + errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument, + errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate, + errXhasSideEffects, errIteratorExpected, errLetNeedsInit, + errThreadvarCannotInit, errWrongSymbolX, errIllegalCaptureX, + errXCannotBeClosure, errXMustBeCompileTime, + errCannotInferTypeOfTheLiteral, + errCannotInferReturnType, + errGenericLambdaNotAllowed, + errCompilerDoesntSupportTarget, + errUser, + warnCannotOpenFile, + warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit, + warnDeprecated, warnConfigDeprecated, + warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel, + warnUnknownSubstitutionX, warnLanguageXNotSupported, + warnFieldXNotSupported, warnCommentXIgnored, + warnNilStatement, warnTypelessParam, + warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode, + warnEachIdentIsTuple, warnShadowIdent, + warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2, + warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed, + warnUser, + hintSuccess, hintSuccessX, + hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded, + hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled, + hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath, + hintConditionAlwaysTrue, hintName, hintPattern, + hintUser + +const + fatalMin* = errUnknown + fatalMax* = errInternal + errMin* = errUnknown + errMax* = errUser + warnMin* = warnCannotOpenFile + warnMax* = pred(hintSuccess) + hintMin* = hintSuccess + hintMax* = high(TMsgKind) + +type + TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints + TNoteKinds* = set[TNoteKind] + +var + gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} - + {warnShadowIdent, warnUninit, + warnProveField, warnProveIndex, warnGcUnsafe} + + +#import compiler.msgs + +echo warnUninit in gNotes diff --git a/tests/stdlib/tdialogs.nim b/tests/stdlib/tdialogs.nim deleted file mode 100644 index f0203d319..000000000 --- a/tests/stdlib/tdialogs.nim +++ /dev/null @@ -1,17 +0,0 @@ -# Test the dialogs module - -import dialogs, gtk2 - -gtk2.nimrod_init() - -var x = chooseFilesToOpen(nil) -for a in items(x): - writeln(stdout, a) - -info(nil, "start with an info box") -warning(nil, "now a warning ...") -error(nil, "... and an error!") - -writeln(stdout, chooseFileToOpen(nil)) -writeln(stdout, chooseFileToSave(nil)) -writeln(stdout, chooseDir(nil)) diff --git a/tests/stdlib/treloop.nim b/tests/stdlib/treloop.nim new file mode 100644 index 000000000..35236708c --- /dev/null +++ b/tests/stdlib/treloop.nim @@ -0,0 +1,9 @@ +discard """ + output: "@[(, +, 1, 2, )]" +""" + +import re + +let str = "(+ 1 2)" +var tokenRE = re"""[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)""" +echo str.findAll(tokenRE) diff --git a/tests/template/tdefault_nil.nim b/tests/template/tdefault_nil.nim new file mode 100644 index 000000000..891166306 --- /dev/null +++ b/tests/template/tdefault_nil.nim @@ -0,0 +1,14 @@ + +# bug #2629 +import sequtils, os + +template glob_rst(basedir: string = nil): expr = + if baseDir.isNil: + to_seq(walk_files("*.rst")) + else: + to_seq(walk_files(basedir/"*.rst")) + +let + rst_files = concat(glob_rst(), glob_rst("docs")) + +when isMainModule: echo rst_files diff --git a/tests/template/tstmt_semchecked_twice.nim b/tests/template/tstmt_semchecked_twice.nim new file mode 100644 index 000000000..05c16c3c9 --- /dev/null +++ b/tests/template/tstmt_semchecked_twice.nim @@ -0,0 +1,30 @@ + +# bug #2585 + +type + RenderPass = object + state: ref int + + RenderData* = object + fb: int + walls: seq[RenderPass] + + Mat2 = int + Vector2[T] = T + Pixels=int + +template use*(fb: int, st: stmt) : stmt = + echo "a ", $fb + st + echo "a ", $fb + +proc render(rdat: var RenderData; passes: var openarray[RenderPass]; proj: Mat2; + indexType = 1) = + for i in 0 .. <len(passes): + echo "blah ", repr(passes[i]) + + + +proc render2*(rdat: var RenderData; screenSz: Vector2[Pixels]; proj: Mat2) = + use rdat.fb: + render(rdat, rdat.walls, proj, 1) diff --git a/tests/template/ttempl2.nim b/tests/template/ttempl2.nim index 142bbb8c7..aaa2f1344 100644 --- a/tests/template/ttempl2.nim +++ b/tests/template/ttempl2.nim @@ -3,12 +3,12 @@ discard """ line: 18 errormsg: "undeclared identifier: \'b\'" """ -template declareInScope(x: expr, t: typeDesc): stmt {.immediate.} = +template declareInScope(x: untyped, t: typeDesc): untyped {.immediate.} = var x: t - -template declareInNewScope(x: expr, t: typeDesc): stmt {.immediate.} = + +template declareInNewScope(x: untyped, t: typeDesc): untyped {.immediate.} = # open a new scope: - block: + block: var x: t declareInScope(a, int) diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index 2d66d2f8e..336cf211e 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -238,7 +238,7 @@ proc testStdlib(r: var TResults, pattern, options: string, cat: Category) = for test in os.walkFiles(pattern): let contents = readFile(test).string if contents.contains("when isMainModule"): - testSpec r, makeTest(test, options, cat, actionRun) + testSpec r, makeTest(test, options, cat, actionRunNoSpec) else: testNoSpec r, makeTest(test, options, cat, actionCompile) diff --git a/tests/testament/specs.nim b/tests/testament/specs.nim index 2a8a4ea24..9306bf025 100644 --- a/tests/testament/specs.nim +++ b/tests/testament/specs.nim @@ -10,13 +10,14 @@ import parseutils, strutils, os, osproc, streams, parsecfg const - cmdTemplate* = r"nim $target --hints:on $options $file" + cmdTemplate* = r"nim $target --hints:on -d:testing $options $file" type TTestAction* = enum actionCompile = "compile" actionRun = "run" actionReject = "reject" + actionRunNoSpec = "runNoSpec" TResultEnum* = enum reNimcCrash, # nim compiler seems to have crashed reMsgsDiffer, # error messages differ @@ -42,7 +43,8 @@ type action*: TTestAction file*, cmd*: string outp*: string - line*, exitCode*: int + line*, column*: int + exitCode*: int msg*: string ccodeCheck*: string err*: TResultEnum @@ -77,7 +79,7 @@ proc extractSpec(filename: string): string = when not defined(nimhygiene): {.pragma: inject.} -template parseSpecAux(fillResult: stmt) {.immediate.} = +template parseSpecAux(fillResult: untyped) = var ss = newStringStream(extractSpec(filename)) var p {.inject.}: CfgParser open(p, ss, filename, 1) @@ -91,13 +93,18 @@ template parseSpecAux(fillResult: stmt) {.immediate.} = fillResult close(p) -proc parseSpec*(filename: string): TSpec = - result.file = filename +proc specDefaults*(result: var TSpec) = result.msg = "" result.outp = "" result.nimout = "" result.ccodeCheck = "" result.cmd = cmdTemplate + result.line = 0 + result.column = 0 + +proc parseSpec*(filename: string): TSpec = + specDefaults(result) + result.file = filename parseSpecAux: case normalize(e.key) of "action": @@ -108,7 +115,8 @@ proc parseSpec*(filename: string): TSpec = else: echo ignoreMsg(p, e) of "file": result.file = e.value of "line": discard parseInt(e.value, result.line) - of "output": + of "column": discard parseInt(e.value, result.column) + of "output": result.action = actionRun result.outp = e.value of "outputsub": @@ -117,7 +125,7 @@ proc parseSpec*(filename: string): TSpec = result.substr = true of "sortoutput": result.sortoutput = parseCfgBool(e.value) - of "exitcode": + of "exitcode": discard parseInt(e.value, result.exitCode) of "msg": result.msg = e.value diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim index 86ff6a689..93cb3cc7a 100644 --- a/tests/testament/tester.nim +++ b/tests/testament/tester.nim @@ -50,7 +50,7 @@ type let pegLineError = - peg"{[^(]*} '(' {\d+} ', ' \d+ ') ' ('Error') ':' \s* {.*}" + peg"{[^(]*} '(' {\d+} ', ' {\d+} ') ' ('Error') ':' \s* {.*}" pegOtherError = peg"'Error:' \s* {.*}" pegSuccess = peg"'Hint: operation successful'.*" pegOfInterest = pegLineError / pegOtherError @@ -77,11 +77,13 @@ proc callCompiler(cmdTemplate, filename, options: string, result.msg = "" result.file = "" result.outp = "" - result.line = -1 + result.line = 0 + result.column = 0 if err =~ pegLineError: result.file = extractFilename(matches[0]) result.line = parseInt(matches[1]) - result.msg = matches[2] + result.column = parseInt(matches[2]) + result.msg = matches[3] elif err =~ pegOtherError: result.msg = matches[0] elif suc =~ pegSuccess: @@ -149,8 +151,11 @@ proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest) = elif extractFilename(expected.file) != extractFilename(given.file) and "internal error:" notin expected.msg: r.addResult(test, expected.file, given.file, reFilesDiffer) - elif expected.line != given.line and expected.line != 0: - r.addResult(test, $expected.line, $given.line, reLinesDiffer) + elif expected.line != given.line and expected.line != 0 or + expected.column != given.column and expected.column != 0: + r.addResult(test, $expected.line & ':' & $expected.column, + $given.line & ':' & $given.column, + reLinesDiffer) else: r.addResult(test, expected.msg, given.msg, reSuccess) inc(r.passed) @@ -210,7 +215,12 @@ proc testSpec(r: var TResults, test: TTest) = let tname = test.name.addFileExt(".nim") inc(r.total) styledEcho "Processing ", fgCyan, extractFilename(tname) - var expected = parseSpec(tname) + var expected: TSpec + if test.action != actionRunNoSpec: + expected = parseSpec(tname) + else: + specDefaults expected + expected.action = actionRunNoSpec if expected.err == reIgnored: r.addResult(test, "", "", reIgnored) inc(r.skipped) @@ -220,7 +230,7 @@ proc testSpec(r: var TResults, test: TTest) = var given = callCompiler(expected.cmd, test.name, test.options & " --hint[Path]:off --hint[Processing]:off", test.target) compilerOutputTests(test, given, expected, r) - of actionRun: + of actionRun, actionRunNoSpec: var given = callCompiler(expected.cmd, test.name, test.options, test.target) if given.err != reSuccess: diff --git a/tests/tuples/tuint_tuple.nim b/tests/tuples/tuint_tuple.nim new file mode 100644 index 000000000..24bcead5e --- /dev/null +++ b/tests/tuples/tuint_tuple.nim @@ -0,0 +1,10 @@ +# bug #1986 found by gdmoore + +proc test(): int64 = + return 0xdeadbeef.int64 + +const items = [ + (var1: test(), var2: 100'u32), + (var1: test(), var2: 192'u32) +] + diff --git a/tests/tuples/tuple_with_nil.nim b/tests/tuples/tuple_with_nil.nim new file mode 100644 index 000000000..26e4ae85e --- /dev/null +++ b/tests/tuples/tuple_with_nil.nim @@ -0,0 +1,766 @@ +import macros +from strutils import IdentStartChars +import parseutils +import unicode +import math +import fenv +import unsigned +import pegs +import streams + +type + FormatError = object of Exception ## Error in the format string. + + Writer = concept W + ## Writer to output a character `c`. + when (NimMajor, NimMinor, NimPatch) > (0, 10, 2): + write(W, 'c') + else: + block: + var x: W + write(x, char) + + FmtAlign = enum ## Format alignment + faDefault ## default for given format type + faLeft ## left aligned + faRight ## right aligned + faCenter ## centered + faPadding ## right aligned, fill characters after sign (numbers only) + + FmtSign = enum ## Format sign + fsMinus ## only unary minus, no reservered sign space for positive numbers + fsPlus ## unary minus and unary plus + fsSpace ## unary minus and reserved space for positive numbers + + FmtType = enum ## Format type + ftDefault ## default format for given parameter type + ftStr ## string + ftChar ## character + ftDec ## decimal integer + ftBin ## binary integer + ftOct ## octal integer + ftHex ## hexadecimal integer + ftFix ## real number in fixed point notation + ftSci ## real number in scientific notation + ftGen ## real number in generic form (either fixed point or scientific) + ftPercent ## real number multiplied by 100 and % added + + Format = tuple ## Formatting information. + typ: FmtType ## format type + precision: int ## floating point precision + width: int ## minimal width + fill: string ## the fill character, UTF8 + align: FmtAlign ## aligment + sign: FmtSign ## sign notation + baseprefix: bool ## whether binary, octal, hex should be prefixed by 0b, 0x, 0o + upcase: bool ## upper case letters in hex or exponential formats + comma: bool ## + arysep: string ## separator for array elements + + PartKind = enum pkStr, pkFmt + + Part = object + ## Information of a part of the target string. + case kind: PartKind ## type of the part + of pkStr: + str: string ## literal string + of pkFmt: + arg: int ## position argument + fmt: string ## format string + field: string ## field of argument to be accessed + index: int ## array index of argument to be accessed + nested: bool ## true if the argument contains nested formats + +const + DefaultPrec = 6 ## Default precision for floating point numbers. + DefaultFmt: Format = (ftDefault, -1, -1, nil, faDefault, fsMinus, false, false, false, nil) + ## Default format corresponding to the empty format string, i.e. + ## `x.format("") == x.format(DefaultFmt)`. + round_nums = [0.5, 0.05, 0.005, 0.0005, 0.00005, 0.000005, 0.0000005, 0.00000005] + ## Rounding offset for floating point numbers up to precision 8. + +proc write(s: var string; c: char) = + s.add(c) + +proc has(c: Captures; i: range[0..pegs.MaxSubpatterns-1]): bool {.nosideeffect, inline.} = + ## Tests whether `c` contains a non-empty capture `i`. + let b = c.bounds(i) + result = b.first <= b.last + +proc get(str: string; c: Captures; i: range[0..MaxSubpatterns-1]; def: char): char {.nosideeffect, inline.} = + ## If capture `i` is non-empty return that portion of `str` casted + ## to `char`, otherwise return `def`. + result = if c.has(i): str[c.bounds(i).first] else: def + +proc get(str: string; c: Captures; i: range[0..MaxSubpatterns-1]; def: string; begoff: int = 0): string {.nosideeffect, inline.} = + ## If capture `i` is non-empty return that portion of `str` as + ## string, otherwise return `def`. + let b = c.bounds(i) + result = if c.has(i): str.substr(b.first + begoff, b.last) else: def + +proc get(str: string; c: Captures; i: range[0..MaxSubpatterns-1]; def: int; begoff: int = 0): int {.nosideeffect, inline.} = + ## If capture `i` is non-empty return that portion of `str` + ## converted to int, otherwise return `def`. + if c.has(i): + discard str.parseInt(result, c.bounds(i).first + begoff) + else: + result = def + +proc parse(fmt: string): Format {.nosideeffect.} = + # Converts the format string `fmt` into a `Format` structure. + let p = + sequence(capture(?sequence(anyRune(), &charSet({'<', '>', '=', '^'}))), + capture(?charSet({'<', '>', '=', '^'})), + capture(?charSet({'-', '+', ' '})), + capture(?charSet({'#'})), + capture(?(+digits())), + capture(?charSet({','})), + capture(?sequence(charSet({'.'}), +digits())), + capture(?charSet({'b', 'c', 'd', 'e', 'E', 'f', 'F', 'g', 'G', 'n', 'o', 's', 'x', 'X', '%'})), + capture(?sequence(charSet({'a'}), *pegs.any()))) + # let p=peg"{(_&[<>=^])?}{[<>=^]?}{[-+ ]?}{[#]?}{[0-9]+?}{[,]?}{([.][0-9]+)?}{[bcdeEfFgGnosxX%]?}{(a.*)?}" + + var caps: Captures + if fmt.rawmatch(p, 0, caps) < 0: + raise newException(FormatError, "Invalid format string") + + result.fill = fmt.get(caps, 0, nil) + + case fmt.get(caps, 1, 0.char) + of '<': result.align = faLeft + of '>': result.align = faRight + of '^': result.align = faCenter + of '=': result.align = faPadding + else: result.align = faDefault + + case fmt.get(caps, 2, '-') + of '-': result.sign = fsMinus + of '+': result.sign = fsPlus + of ' ': result.sign = fsSpace + else: result.sign = fsMinus + + result.baseprefix = caps.has(3) + + result.width = fmt.get(caps, 4, -1) + + if caps.has(4) and fmt[caps.bounds(4).first] == '0': + if result.fill != nil: + raise newException(FormatError, "Leading 0 in with not allowed with explicit fill character") + if result.align != faDefault: + raise newException(FormatError, "Leading 0 in with not allowed with explicit alignment") + result.fill = "0" + result.align = faPadding + + result.comma = caps.has(5) + + result.precision = fmt.get(caps, 6, -1, 1) + + case fmt.get(caps, 7, 0.char) + of 's': result.typ = ftStr + of 'c': result.typ = ftChar + of 'd', 'n': result.typ = ftDec + of 'b': result.typ = ftBin + of 'o': result.typ = ftOct + of 'x': result.typ = ftHex + of 'X': result.typ = ftHex; result.upcase = true + of 'f', 'F': result.typ = ftFix + of 'e': result.typ = ftSci + of 'E': result.typ = ftSci; result.upcase = true + of 'g': result.typ = ftGen + of 'G': result.typ = ftGen; result.upcase = true + of '%': result.typ = ftPercent + else: result.typ = ftDefault + + result.arysep = fmt.get(caps, 8, nil, 1) + +proc getalign(fmt: Format; defalign: FmtAlign; slen: int) : tuple[left, right:int] {.nosideeffect.} = + ## Returns the number of left and right padding characters for a + ## given format alignment and width of the object to be printed. + ## + ## `fmt` + ## the format data + ## `default` + ## if `fmt.align == faDefault`, then this alignment is used + ## `slen` + ## the width of the object to be printed. + ## + ## The returned values `(left, right)` will be as minimal as possible + ## so that `left + slen + right >= fmt.width`. + result.left = 0 + result.right = 0 + if (fmt.width >= 0) and (slen < fmt.width): + let alg = if fmt.align == faDefault: defalign else: fmt.align + case alg: + of faLeft: result.right = fmt.width - slen + of faRight, faPadding: result.left = fmt.width - slen + of faCenter: + result.left = (fmt.width - slen) div 2 + result.right = fmt.width - slen - result.left + else: discard + +proc writefill(o: var Writer; fmt: Format; n: int; signum: int = 0) = + ## Write characters for filling. This function also writes the sign + ## of a numeric format and handles the padding alignment + ## accordingly. + ## + ## `o` + ## output object + ## `add` + ## output function + ## `fmt` + ## format to be used (important for padding aligment) + ## `n` + ## the number of filling characters to be written + ## `signum` + ## the sign of the number to be written, < 0 negative, > 0 positive, = 0 zero + if fmt.align == faPadding and signum != 0: + if signum < 0: write(o, '-') + elif fmt.sign == fsPlus: write(o, '+') + elif fmt.sign == fsSpace: write(o, ' ') + + if fmt.fill == nil: + for i in 1..n: write(o, ' ') + else: + for i in 1..n: + for c in fmt.fill: + write(o, c) + + if fmt.align != faPadding and signum != 0: + if signum < 0: write(o, '-') + elif fmt.sign == fsPlus: write(o, '+') + elif fmt.sign == fsSpace: write(o, ' ') + +proc writeformat(o: var Writer; s: string; fmt: Format) = + ## Write string `s` according to format `fmt` using output object + ## `o` and output function `add`. + if fmt.typ notin {ftDefault, ftStr}: + raise newException(FormatError, "String variable must have 's' format type") + + # compute alignment + let len = if fmt.precision < 0: runelen(s) else: min(runelen(s), fmt.precision) + var alg = getalign(fmt, faLeft, len) + writefill(o, fmt, alg.left) + var pos = 0 + for i in 0..len-1: + let rlen = runeLenAt(s, pos) + for j in pos..pos+rlen-1: write(o, s[j]) + pos += rlen + writefill(o, fmt, alg.right) + +proc writeformat(o: var Writer; c: char; fmt: Format) = + ## Write character `c` according to format `fmt` using output object + ## `o` and output function `add`. + if not (fmt.typ in {ftChar, ftDefault}): + raise newException(FormatError, "Character variable must have 'c' format type") + + # compute alignment + var alg = getalign(fmt, faLeft, 1) + writefill(o, fmt, alg.left) + write(o, c) + writefill(o, fmt, alg.right) + +proc writeformat(o: var Writer; c: Rune; fmt: Format) = + ## Write rune `c` according to format `fmt` using output object + ## `o` and output function `add`. + if not (fmt.typ in {ftChar, ftDefault}): + raise newException(FormatError, "Character variable must have 'c' format type") + + # compute alignment + var alg = getalign(fmt, faLeft, 1) + writefill(o, fmt, alg.left) + let s = c.toUTF8 + for c in s: write(o, c) + writefill(o, fmt, alg.right) + +proc abs(x: SomeUnsignedInt): SomeUnsignedInt {.inline.} = x + ## Return the absolute value of the unsigned int `x`. + +proc writeformat(o: var Writer; i: SomeInteger; fmt: Format) = + ## Write integer `i` according to format `fmt` using output object + ## `o` and output function `add`. + var fmt = fmt + if fmt.typ == ftDefault: + fmt.typ = ftDec + if not (fmt.typ in {ftBin, ftOct, ftHex, ftDec}): + raise newException(FormatError, "Integer variable must of one of the following types: b,o,x,X,d,n") + + var base: type(i) + var len = 0 + case fmt.typ: + of ftDec: + base = 10 + of ftBin: + base = 2 + if fmt.baseprefix: len += 2 + of ftOct: + base = 8 + if fmt.baseprefix: len += 2 + of ftHex: + base = 16 + if fmt.baseprefix: len += 2 + else: assert(false) + + if fmt.sign != fsMinus or i < 0: len.inc + + var x: type(i) = abs(i) + var irev: type(i) = 0 + var ilen = 0 + while x > 0.SomeInteger: + len.inc + ilen.inc + irev = irev * base + x mod base + x = x div base + if ilen == 0: + ilen.inc + len.inc + + var alg = getalign(fmt, faRight, len) + writefill(o, fmt, alg.left, if i >= 0.SomeInteger: 1 else: -1) + if fmt.baseprefix: + case fmt.typ + of ftBin: + write(o, '0') + write(o, 'b') + of ftOct: + write(o, '0') + write(o, 'o') + of ftHex: + write(o, '0') + write(o, 'x') + else: + raise newException(FormatError, "# only allowed with b, o, x or X") + while ilen > 0: + ilen.dec + let c = irev mod base + irev = irev div base + if c < 10: + write(o, ('0'.int + c.int).char) + elif fmt.upcase: + write(o, ('A'.int + c.int - 10).char) + else: + write(o, ('a'.int + c.int - 10).char) + writefill(o, fmt, alg.right) + +proc writeformat(o: var Writer; p: pointer; fmt: Format) = + ## Write pointer `i` according to format `fmt` using output object + ## `o` and output function `add`. + ## + ## Pointers are casted to unsigned int and formated as hexadecimal + ## with prefix unless specified otherwise. + var f = fmt + if f.typ == 0.char: + f.typ = 'x' + f.baseprefix = true + writeformat(o, add, cast[uint](p), f) + +proc writeformat(o: var Writer; x: SomeReal; fmt: Format) = + ## Write real number `x` according to format `fmt` using output + ## object `o` and output function `add`. + var fmt = fmt + # handle default format + if fmt.typ == ftDefault: + fmt.typ = ftGen + if fmt.precision < 0: fmt.precision = DefaultPrec + if not (fmt.typ in {ftFix, ftSci, ftGen, ftPercent}): + raise newException(FormatError, "Integer variable must of one of the following types: f,F,e,E,g,G,%") + + let positive = x >= 0 and classify(x) != fcNegZero + var len = 0 + + if fmt.sign != fsMinus or not positive: len.inc + + var prec = if fmt.precision < 0: DefaultPrec else: fmt.precision + var y = abs(x) + var exp = 0 + var numstr, frstr: array[0..31, char] + var numlen, frbeg, frlen = 0 + + if fmt.typ == ftPercent: y *= 100 + + case classify(x): + of fcNan: + numstr[0..2] = ['n', 'a', 'n'] + numlen = 3 + of fcInf, fcNegInf: + numstr[0..2] = ['f', 'n', 'i'] + numlen = 3 + of fcZero, fcNegZero: + numstr[0] = '0' + numlen = 1 + else: # a usual fractional number + if not (fmt.typ in {ftFix, ftPercent}): # not fixed point + exp = int(floor(log10(y))) + if fmt.typ == ftGen: + if prec == 0: prec = 1 + if -4 <= exp and exp < prec: + prec = prec-1-exp + exp = 0 + else: + prec = prec - 1 + len += 4 # exponent + else: + len += 4 # exponent + # shift y so that 1 <= abs(y) < 2 + if exp > 0: y /= pow(10.SomeReal, abs(exp).SomeReal) + elif exp < 0: y *= pow(10.SomeReal, abs(exp).SomeReal) + elif fmt.typ == ftPercent: + len += 1 # percent sign + + # handle rounding by adding +0.5 * LSB + if prec < len(round_nums): y += round_nums[prec] + + # split into integer and fractional part + var mult = 1'i64 + for i in 1..prec: mult *= 10 + var num = y.int64 + var fr = ((y - num.SomeReal) * mult.SomeReal).int64 + # build integer part string + while num != 0: + numstr[numlen] = ('0'.int + (num mod 10)).char + numlen.inc + num = num div 10 + if numlen == 0: + numstr[0] = '0' + numlen.inc + # build fractional part string + while fr != 0: + frstr[frlen] = ('0'.int + (fr mod 10)).char + frlen.inc + fr = fr div 10 + while frlen < prec: + frstr[frlen] = '0' + frlen.inc + # possible remove trailing 0 + if fmt.typ == ftGen: + while frbeg < frlen and frstr[frbeg] == '0': frbeg.inc + # update length of string + len += numlen; + if frbeg < frlen: + len += 1 + frlen - frbeg # decimal point and fractional string + + let alg = getalign(fmt, faRight, len) + writefill(o, fmt, alg.left, if positive: 1 else: -1) + for i in (numlen-1).countdown(0): write(o, numstr[i]) + if frbeg < frlen: + write(o, '.') + for i in (frlen-1).countdown(frbeg): write(o, frstr[i]) + if fmt.typ == ftSci or (fmt.typ == ftGen and exp != 0): + write(o, if fmt.upcase: 'E' else: 'e') + if exp >= 0: + write(o, '+') + else: + write(o, '-') + exp = -exp + if exp < 10: + write(o, '0') + write(o, ('0'.int + exp).char) + else: + var i=0 + while exp > 0: + numstr[i] = ('0'.int + exp mod 10).char + i+=1 + exp = exp div 10 + while i>0: + i-=1 + write(o, numstr[i]) + if fmt.typ == ftPercent: write(o, '%') + writefill(o, fmt, alg.right) + +proc writeformat(o: var Writer; b: bool; fmt: Format) = + ## Write boolean value `b` according to format `fmt` using output + ## object `o`. A boolean may be formatted numerically or as string. + ## In the former case true is written as 1 and false as 0, in the + ## latter the strings "true" and "false" are shown, respectively. + ## The default is string format. + if fmt.typ in {ftStr, ftDefault}: + writeformat(o, + if b: "true" + else: "false", + fmt) + elif fmt.typ in {ftBin, ftOct, ftHex, ftDec}: + writeformat(o, + if b: 1 + else: 0, + fmt) + else: + raise newException(FormatError, "Boolean values must of one of the following types: s,b,o,x,X,d,n") + +proc writeformat(o: var Writer; ary: openarray[any]; fmt: Format) = + ## Write array `ary` according to format `fmt` using output object + ## `o` and output function `add`. + if ary.len == 0: return + + var sep: string + var nxtfmt = fmt + if fmt.arysep == nil: + sep = "\t" + elif fmt.arysep.len == 0: + sep = "" + else: + let sepch = fmt.arysep[0] + let nxt = 1 + skipUntil(fmt.arysep, sepch, 1) + if nxt >= 1: + nxtfmt.arysep = fmt.arysep.substr(nxt) + sep = fmt.arysep.substr(1, nxt-1) + else: + nxtfmt.arysep = "" + sep = fmt.arysep.substr(1) + writeformat(o, ary[0], nxtfmt) + for i in 1..ary.len-1: + for c in sep: write(o, c) + writeformat(o, ary[i], nxtfmt) + +proc addformat[T](o: var Writer; x: T; fmt: Format = DefaultFmt) {.inline.} = + ## Write `x` formatted with `fmt` to `o`. + writeformat(o, x, fmt) + +proc addformat[T](o: var Writer; x: T; fmt: string) {.inline.} = + ## The same as `addformat(o, x, parse(fmt))`. + addformat(o, x, fmt.parse) + +proc addformat(s: var string; x: string) {.inline.} = + ## Write `x` to `s`. This is a fast specialized version for + ## appending unformatted strings. + add(s, x) + +proc addformat(f: File; x: string) {.inline.} = + ## Write `x` to `f`. This is a fast specialized version for + ## writing unformatted strings to a file. + write(f, x) + +proc addformat[T](f: File; x: T; fmt: Format = DefaultFmt) {.inline.} = + ## Write `x` to file `f` using format `fmt`. + var g = f + writeformat(g, x, fmt) + +proc addformat[T](f: File; x: T; fmt: string) {.inline.} = + ## Write `x` to file `f` using format string `fmt`. This is the same + ## as `addformat(f, x, parse(fmt))` + addformat(f, x, parse(fmt)) + +proc addformat(s: Stream; x: string) {.inline.} = + ## Write `x` to `s`. This is a fast specialized version for + ## writing unformatted strings to a stream. + write(s, x) + +proc addformat[T](s: Stream; x: T; fmt: Format = DefaultFmt) {.inline.} = + ## Write `x` to stream `s` using format `fmt`. + var g = s + writeformat(g, x, fmt) + +proc addformat[T](s: Stream; x: T; fmt: string) {.inline.} = + ## Write `x` to stream `s` using format string `fmt`. This is the same + ## as `addformat(s, x, parse(fmt))` + addformat(s, x, parse(fmt)) + +proc format[T](x: T; fmt: Format): string = + ## Return `x` formatted as a string according to format `fmt`. + result = "" + addformat(result, x, fmt) + +proc format[T](x: T; fmt: string): string = + ## Return `x` formatted as a string according to format string `fmt`. + result = format(x, fmt.parse) + +proc format[T](x: T): string {.inline.} = + ## Return `x` formatted as a string according to the default format. + ## The default format corresponds to an empty format string. + var fmt {.global.} : Format = DefaultFmt + result = format(x, fmt) + +proc unquoted(s: string): string {.compileTime.} = + ## Return `s` {{ and }} by single { and }, respectively. + result = "" + var pos = 0 + while pos < s.len: + let nxt = pos + skipUntil(s, {'{', '}'}) + result.add(s.substr(pos, nxt)) + pos = nxt + 2 + +proc splitfmt(s: string): seq[Part] {.compiletime, nosideeffect.} = + ## Split format string `s` into a sequence of "parts". + ## + + ## Each part is either a literal string or a format specification. A + ## format specification is a substring of the form + ## "{[arg][:format]}" where `arg` is either empty or a number + ## refering to the arg-th argument and an additional field or array + ## index. The format string is a string accepted by `parse`. + let subpeg = sequence(capture(digits()), + capture(?sequence(charSet({'.'}), *pegs.identStartChars(), *identChars())), + capture(?sequence(charSet({'['}), +digits(), charSet({']'}))), + capture(?sequence(charSet({':'}), *pegs.any()))) + result = @[] + var pos = 0 + while true: + let oppos = pos + skipUntil(s, {'{', '}'}, pos) + # reached the end + if oppos >= s.len: + if pos < s.len: + result.add(Part(kind: pkStr, str: s.substr(pos).unquoted)) + return + # skip double + if oppos + 1 < s.len and s[oppos] == s[oppos+1]: + result.add(Part(kind: pkStr, str: s.substr(pos, oppos))) + pos = oppos + 2 + continue + if s[oppos] == '}': + error("Single '}' encountered in format string") + if oppos > pos: + result.add(Part(kind: pkStr, str: s.substr(pos, oppos-1).unquoted)) + # find matching closing } + var lvl = 1 + var nested = false + pos = oppos + while lvl > 0: + pos.inc + pos = pos + skipUntil(s, {'{', '}'}, pos) + if pos >= s.len: + error("Single '{' encountered in format string") + if s[pos] == '{': + lvl.inc + if lvl == 2: + nested = true + if lvl > 2: + error("Too many nested format levels") + else: + lvl.dec + let clpos = pos + var fmtpart = Part(kind: pkFmt, arg: -1, fmt: s.substr(oppos+1, clpos-1), field: nil, index: int.high, nested: nested) + if fmtpart.fmt.len > 0: + var m: array[0..3, string] + if not fmtpart.fmt.match(subpeg, m): + error("invalid format string") + + if m[1] != nil and m[1].len > 0: + fmtpart.field = m[1].substr(1) + if m[2] != nil and m[2].len > 0: + discard parseInt(m[2].substr(1, m[2].len-2), fmtpart.index) + + if m[0].len > 0: discard parseInt(m[0], fmtpart.arg) + if m[3] == nil or m[3].len == 0: + fmtpart.fmt = "" + elif m[3][0] == ':': + fmtpart.fmt = m[3].substr(1) + else: + fmtpart.fmt = m[3] + result.add(fmtpart) + pos = clpos + 1 + +proc literal(s: string): NimNode {.compiletime, nosideeffect.} = + ## Return the nim literal of string `s`. This handles the case if + ## `s` is nil. + result = if s == nil: newNilLit() else: newLit(s) + +proc literal(b: bool): NimNode {.compiletime, nosideeffect.} = + ## Return the nim literal of boolean `b`. This is either `true` + ## or `false` symbol. + result = if b: "true".ident else: "false".ident + +proc literal[T](x: T): NimNode {.compiletime, nosideeffect.} = + ## Return the nim literal of value `x`. + when type(x) is enum: + result = ($x).ident + else: + result = newLit(x) + +proc generatefmt(fmtstr: string; + args: var openarray[tuple[arg:NimNode, cnt:int]]; + arg: var int;): seq[tuple[val, fmt:NimNode]] {.compiletime.} = + ## fmtstr + ## the format string + ## args + ## array of expressions for the arguments + ## arg + ## the number of the next argument for automatic parsing + ## + ## If arg is < 0 then the functions assumes that explicit numbering + ## must be used, otherwise automatic numbering is used starting at + ## `arg`. The value of arg is updated according to the number of + ## arguments being used. If arg == 0 then automatic and manual + ## numbering is not decided (because no explicit manual numbering is + ## fixed und no automatically numbered argument has been used so + ## far). + ## + ## The function returns a list of pairs `(val, fmt)` where `val` is + ## an expression to be formatted and `fmt` is the format string (or + ## Format). Therefore, the resulting string can be generated by + ## concatenating expressions `val.format(fmt)`. If `fmt` is `nil` + ## then `val` is a (literal) string expression. + try: + result = @[] + for part in splitfmt(fmtstr): + case part.kind + of pkStr: result.add((newLit(part.str), nil)) + of pkFmt: + # first compute the argument expression + # start with the correct index + var argexpr : NimNode + if part.arg >= 0: + if arg > 0: + error("Cannot switch from automatic field numbering to manual field specification") + if part.arg >= args.len: + error("Invalid explicit argument index: " & $part.arg) + argexpr = args[part.arg].arg + args[part.arg].cnt = args[part.arg].cnt + 1 + arg = -1 + else: + if arg < 0: + error("Cannot switch from manual field specification to automatic field numbering") + if arg >= args.len: + error("Too few arguments for format string") + argexpr = args[arg].arg + args[arg].cnt = args[arg].cnt + 1 + arg.inc + # possible field access + if part.field != nil and part.field.len > 0: + argexpr = newDotExpr(argexpr, part.field.ident) + # possible array access + if part.index < int.high: + argexpr = newNimNode(nnkBracketExpr).add(argexpr, newLit(part.index)) + # now the expression for the format data + var fmtexpr: NimNode + if part.nested: + # nested format string. Compute the format string by + # concatenating the parts of the substring. + for e in generatefmt(part.fmt, args, arg): + var newexpr = if part.fmt == nil: e.val else: newCall(bindsym"format", e.val, e.fmt) + if fmtexpr != nil and fmtexpr.kind != nnkNilLit: + fmtexpr = infix(fmtexpr, "&", newexpr) + else: + fmtexpr = newexpr + else: + # literal format string, precompute the format data + fmtexpr = newNimNode(nnkPar) + for field, val in part.fmt.parse.fieldPairs: + fmtexpr.add(newNimNode(nnkExprColonExpr).add(field.ident, literal(val))) + # add argument + result.add((argexpr, fmtexpr)) + finally: + discard + +proc addfmtfmt(fmtstr: string; args: NimNode; retvar: NimNode): NimNode {.compileTime.} = + var argexprs = newseq[tuple[arg:NimNode; cnt:int]](args.len) + result = newNimNode(nnkStmtListExpr) + # generate let bindings for arguments + for i in 0..args.len-1: + let argsym = gensym(nskLet, "arg" & $i) + result.add(newLetStmt(argsym, args[i])) + argexprs[i].arg = argsym + # add result values + var arg = 0 + for e in generatefmt(fmtstr, argexprs, arg): + if e.fmt == nil or e.fmt.kind == nnkNilLit: + result.add(newCall(bindsym"addformat", retvar, e.val)) + else: + result.add(newCall(bindsym"addformat", retvar, e.val, e.fmt)) + for i, arg in argexprs: + if arg.cnt == 0: + warning("Argument " & $(i+1) & " `" & args[i].repr & "` is not used in format string") + +macro addfmt(s: var string, fmtstr: string{lit}, args: varargs[expr]): expr = + ## The same as `s.add(fmtstr.fmt(args...))` but faster. + result = addfmtfmt($fmtstr, args, s) + +var s: string = "" +s.addfmt("a:{}", 42) diff --git a/tests/tuples/tuple_with_seq.nim b/tests/tuples/tuple_with_seq.nim new file mode 100644 index 000000000..39edb500f --- /dev/null +++ b/tests/tuples/tuple_with_seq.nim @@ -0,0 +1,46 @@ +discard """ + output: '''it's nil +@[1, 2, 3]''' +""" + +template foo(s: string = nil) = + if isNil(s): + echo "it's nil" + else: + echo s + +foo + + +# bug #2632 + +proc takeTup(x: tuple[s: string;x: seq[int]]) = + discard + +takeTup(("foo", @[])) + + +#proc foobar(): () = + +proc f(xs: seq[int]) = + discard + +proc g(t: tuple[n:int, xs:seq[int]]) = + discard + +when isMainModule: + f(@[]) # OK + g((1,@[1])) # OK + g((0,@[])) # NG + + +# bug #2630 +type T = tuple[a: seq[int], b: int] + +var t: T = (@[1,2,3], 7) + +proc test(s: seq[int]): T = + echo s + (s, 7) + +t = test(t.a) diff --git a/tests/types/temptyseqs.nim b/tests/types/temptyseqs.nim index 2b07ba679..834f63729 100644 --- a/tests/types/temptyseqs.nim +++ b/tests/types/temptyseqs.nim @@ -1,5 +1,13 @@ discard """ - output: "1" + output: '''1 +foo +bar +baz +foo +bar +baz +yes +no''' """ # bug #1708 @@ -24,3 +32,59 @@ when true: const foo2: seq[string] = @[] echo foo[0][0][0] + +proc takeEmpty(x: openArray[string] = []) = discard +takeEmpty() +takeEmpty([]) + +proc takeEmpty2(x: openArray[string] = @[]) = discard +takeEmpty2() +takeEmpty2([]) +takeEmpty2(@[]) + +#takeEmpty2([nil]) + +#rawMessage(errExecutionOfProgramFailed, []) + +# bug #2470 +const + stuff: seq[string] = @[] + +for str in stuff: + echo "str=", str + +# bug #1354 +proc foo4[T](more: seq[T] = @[]) = + var more2 = more + +foo4[int]() + +proc maino: int = + var wd: cstring = nil + inc result + +discard maino() + +proc varargso(a: varargs[string]) = + for x in a: + echo x + +varargso(["foo", "bar", "baz"]) +varargso("foo", "bar", "baz") + + +type + Flago = enum + tfNeedsInit, tfNotNil + +var s: set[Flago] = {tfNeedsInit} + +if {tfNeedsInit, tfNotNil} * s != {}: + echo "yes" +else: + echo "no" + +if {tfNeedsInit, tfNotNil} * s <= {tfNotNil}: + echo "yes" +else: + echo "no" diff --git a/tests/types/tisopr.nim b/tests/types/tisopr.nim index 8b7fe4e46..b9acfa5fb 100644 --- a/tests/types/tisopr.nim +++ b/tests/types/tisopr.nim @@ -1,5 +1,11 @@ discard """ - output: '''true true false yes''' + output: '''true true false yes +false +false +false +true +true +no''' """ proc IsVoid[T](): string = @@ -28,7 +34,7 @@ no s.items is iterator: float yes s.items is iterator: TNumber no s.items is iterator: object -type +type Iter[T] = iterator: T yes s.items is Iter[TNumber] @@ -51,3 +57,34 @@ yes Foo[4, int] is Bar[int] no Foo[4, int] is Baz[4] yes Foo[4, float] is Baz[4] + +# bug #2505 + +echo(8'i8 is int32) + +# bug #1853 +type SeqOrSet[E] = seq[E] or set[E] +type SeqOfInt = seq[int] +type SeqOrSetOfInt = SeqOrSet[int] + +# This prints "false", which seems less correct that (1) printing "true" or (2) +# raising a compiler error. +echo seq is SeqOrSet + +# This prints "false", as expected. +echo seq is SeqOrSetOfInt + +# This prints "true", as expected. +echo SeqOfInt is SeqOrSet + +# This causes an internal error (filename: compiler/semtypes.nim, line: 685). +echo SeqOfInt is SeqOrSetOfInt + +# bug #2522 +proc test[T](x: T) = + when T is typedesc: + echo "yes" + else: + echo "no" + +test(7) |