From 06ad80cc4555ec1cb80d46baac2d93525137314c Mon Sep 17 00:00:00 2001 From: def Date: Mon, 5 Jan 2015 01:30:03 +0100 Subject: [PATCH 001/250] indent = 0 looks better for `$`(node: JsonNode) --- lib/pure/json.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 385787d6c4..c5510a50e2 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -864,7 +864,7 @@ proc pretty*(node: JsonNode, indent = 2): string = proc `$`*(node: JsonNode): string = ## Converts `node` to its JSON Representation on one line. result = "" - toPretty(result, node, 1, false) + toPretty(result, node, 0, false) iterator items*(node: JsonNode): JsonNode = ## Iterator for the items of `node`. `node` has to be a JArray. From f223e94ccd98448e245e5a7bd7e7da396b9ae9c8 Mon Sep 17 00:00:00 2001 From: def Date: Mon, 5 Jan 2015 01:30:30 +0100 Subject: [PATCH 002/250] Add operator `%*` to JSON --- lib/pure/json.nim | 77 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index c5510a50e2..eed01e3761 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -30,9 +30,28 @@ ## ## 1.3000000000000000e+00 ## true +## +## This module can also be used to comfortably create JSON using the `%*` +## operator: +## +## .. code-block:: nim +## +## var hisName = "John" +## let herAge = 31 +## var j = %* +## [ +## { +## "name": hisName, +## "age": 30 +## }, +## { +## "name": "Susan", +## "age": herAge +## } +## ] import - hashes, strutils, lexbase, streams, unicode + hashes, strutils, lexbase, streams, unicode, macros type JsonEventKind* = enum ## enumeration of all events that may occur when parsing @@ -625,6 +644,31 @@ proc `%`*(elements: openArray[JsonNode]): JsonNode = newSeq(result.elems, elements.len) for i, p in pairs(elements): result.elems[i] = p +proc toJson(x: expr): expr {.compiletime.} = + case x.kind + of nnkBracket: + result = newNimNode(nnkBracket) + for i in 0 .. Date: Mon, 5 Jan 2015 13:19:10 +0100 Subject: [PATCH 003/250] Remove debugging echos again --- lib/pure/json.nim | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index eed01e3761..1b4b135b63 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -665,9 +665,7 @@ proc toJson(x: expr): expr {.compiletime.} = macro `%*`*(x: expr): expr = ## Convert an expression to a JsonParser directly, without having to specify ## `%` for every element. - echo x.treeRepr result = toJson(x) - echo result.treeRepr proc `==`* (a,b: JsonNode): bool = ## Check two nodes for equality From c19fb7b366d1ccdf209c5121112fba948ca4cbf8 Mon Sep 17 00:00:00 2001 From: dumndummer Date: Wed, 28 Jan 2015 21:44:52 +0000 Subject: [PATCH 004/250] Update sequtils.nim Renamed param name 'pred' to 'op' in mapIt template to better correspond with map proc in system module --- lib/pure/collections/sequtils.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index befc9bacb5..a0e9280f54 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -382,7 +382,7 @@ template foldr*(sequence, operation: expr): expr = result = operation result -template mapIt*(seq1, typ, pred: expr): expr = +template mapIt*(seq1, typ, op: expr): expr = ## Convenience template around the ``map`` proc to reduce typing. ## ## The template injects the ``it`` variable which you can use directly in an @@ -400,7 +400,7 @@ template mapIt*(seq1, typ, pred: expr): expr = result.add(pred) result -template mapIt*(varSeq, pred: expr) = +template mapIt*(varSeq, op: expr) = ## Convenience template around the mutable ``map`` proc to reduce typing. ## ## The template injects the ``it`` variable which you can use directly in an From 5ecc461a944b54a516e6f81df4bd6db95a86e682 Mon Sep 17 00:00:00 2001 From: Simon Hafner Date: Thu, 29 Jan 2015 04:40:27 -0600 Subject: [PATCH 005/250] Fixes #2030 --- compiler/semexprs.nim | 2 +- compiler/semfold.nim | 4 ++-- tests/exprs/thighCString.nim | 6 ++++++ 3 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 tests/exprs/thighCString.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 6638848df8..34a9cd1dd8 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -306,7 +306,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = var typ = skipTypes(n.sons[1].typ, abstractVarRange + {tyTypeDesc, tyFieldAccessor}) case typ.kind - of tySequence, tyString, tyOpenArray, tyVarargs: + of tySequence, tyString, tyCString, tyOpenArray, tyVarargs: n.typ = getSysType(tyInt) of tyArrayConstr, tyArray: n.typ = typ.sons[0] # indextype diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 1988c512e6..a3f1b1c130 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -665,8 +665,8 @@ proc getConstExpr(m: PSym, n: PNode): PNode = of mLow: result = newIntNodeT(firstOrd(n.sons[1].typ), n) of mHigh: - if skipTypes(n.sons[1].typ, abstractVar).kind notin - {tyOpenArray, tyVarargs, tySequence, tyString}: + if skipTypes(n.sons[1].typ, abstractVar).kind notin + {tySequence, tyString, tyCString, tyOpenArray, tyVarargs}: result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n) else: var a = getArrayConstr(m, n.sons[1]) diff --git a/tests/exprs/thighCString.nim b/tests/exprs/thighCString.nim new file mode 100644 index 0000000000..543966df46 --- /dev/null +++ b/tests/exprs/thighCString.nim @@ -0,0 +1,6 @@ +discard """ + output: "5" +""" +let test = cstring("foobar") + +echo high(test) From 1a8541d908169470c4ee15ffdecd58f98c335e79 Mon Sep 17 00:00:00 2001 From: Simon Hafner Date: Sun, 1 Feb 2015 04:11:46 -0600 Subject: [PATCH 006/250] Fixed high(cstring) in vmgen too --- compiler/vmgen.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 1201208792..fe6526a34f 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -893,7 +893,8 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) = of mHigh: if dest < 0: dest = c.getTemp(n.typ) let tmp = c.genx(n.sons[1]) - if n.sons[1].typ.skipTypes(abstractVar-{tyTypeDesc}).kind == tyString: + case n.sons[1].typ.skipTypes(abstractVar-{tyTypeDesc}).kind: + of tyString, tyCString: c.gABI(n, opcLenStr, dest, tmp, 1) else: c.gABI(n, opcLenSeq, dest, tmp, 1) From 43ddb4806b4acd0e9a4170a47020ee16d31f5f72 Mon Sep 17 00:00:00 2001 From: Simon Hafner Date: Sun, 1 Feb 2015 04:36:17 -0600 Subject: [PATCH 007/250] added tests from issue #497 --- tests/macros/macro_bug.nim | 17 +++++++++++++++++ tests/macros/tsame_name_497.nim | 5 +++++ 2 files changed, 22 insertions(+) create mode 100644 tests/macros/macro_bug.nim create mode 100644 tests/macros/tsame_name_497.nim diff --git a/tests/macros/macro_bug.nim b/tests/macros/macro_bug.nim new file mode 100644 index 0000000000..0d0fa76ac8 --- /dev/null +++ b/tests/macros/macro_bug.nim @@ -0,0 +1,17 @@ +import macros + +macro macro_bug*(s: stmt): stmt {.immediate.} = + s.expectKind({nnkProcDef, nnkMethodDef}) + + var params = s.params + + let genericParams = s[2] + result = newNimNode(nnkProcDef).add( + s.name, s[1], genericParams, params, pragma(s), newEmptyNode()) + + var body = body(s) + + # Fails here. + var call = newCall("macro_bug", s.params[1][0]) + body.insert(0, call) + result.add(body) diff --git a/tests/macros/tsame_name_497.nim b/tests/macros/tsame_name_497.nim new file mode 100644 index 0000000000..e49f9f6d8e --- /dev/null +++ b/tests/macros/tsame_name_497.nim @@ -0,0 +1,5 @@ +import macro_bug + +type TObj = object + +proc f(o: TObj) {.macro_bug.} = discard From a6082b2a2013a38ec78a07a62cd04b535689aff4 Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 1 Feb 2015 11:57:13 +0100 Subject: [PATCH 008/250] slightly better docs for re module --- lib/impure/re.nim | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/impure/re.nim b/lib/impure/re.nim index a7bebb81c6..7d5ff8948b 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -9,6 +9,12 @@ ## Regular expression support for Nim. Consider using the pegs module ## instead. +## +## **Note:** The 're' proc defaults to the **extended regular expression +## syntax** which lets you use whitespace freely to make your regexes readable. +## However, this means to match whitespace ``\s`` or something similar has +## to be used. +## ## This module is implemented by providing a wrapper around the ## `PRCE (Perl-Compatible Regular Expressions) `_ ## C library. This means that your application will depend on the PRCE From 903ca78289dc0460e07bd449a972a4d203d9a09b Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 1 Feb 2015 11:58:24 +0100 Subject: [PATCH 009/250] fixes #1989 --- compiler/vm.nim | 8 +++++--- compiler/vmdef.nim | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index 7edbb3fd20..b682b4e253 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1364,9 +1364,11 @@ var globalCtx: PCtx proc setupGlobalCtx(module: PSym) = - if globalCtx.isNil: globalCtx = newCtx(module) - else: refresh(globalCtx, module) - registerAdditionalOps(globalCtx) + if globalCtx.isNil: + globalCtx = newCtx(module) + registerAdditionalOps(globalCtx) + else: + refresh(globalCtx, module) proc myOpen(module: PSym): PPassContext = #var c = newEvalContext(module, emRepl) diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 3d49cb130d..90b9f2517a 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -213,6 +213,7 @@ proc newCtx*(module: PSym): PCtx = proc refresh*(c: PCtx, module: PSym) = c.module = module c.prc = PProc(blocks: @[]) + c.loopIterations = MaxLoopIterations proc registerCallback*(c: PCtx; name: string; callback: VmCallback) = c.callbacks.add((name, callback)) From 1ae4d535cd8ed6b797cf0525eaab9e0c889e0c6d Mon Sep 17 00:00:00 2001 From: def Date: Sun, 1 Feb 2015 18:29:01 +0100 Subject: [PATCH 010/250] Add nextPermutation and prevPermutation Fits best into algorithm module I guess. These are the most general ways, an iterator could easily be implemented from this. Same algorithm as in Rust: http://web.mit.edu/rust-lang_v0.11/doc/src/collections/var/tmp/alexp/rust/rust-0.11.0/src/libcollections/slice.rs.html#644 --- lib/pure/algorithm.nim | 59 ++++++++++++++++++++++++++++++++++ tests/stdlib/tpermutations.nim | 17 ++++++++++ 2 files changed, 76 insertions(+) create mode 100644 tests/stdlib/tpermutations.nim diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 0358a9a819..20bfc5c7c7 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -220,3 +220,62 @@ proc product*[T](x: openArray[seq[T]]): seq[seq[T]] = result.add(res) index = 0 indexes[index] -=1 + +proc nextPermutation*[T](x: var openarray[T]): bool {.discardable.} = + ## Calculates the next lexicographic permutation, directly modifying ``x``. + ## The result is whether a permutation happened, otherwise we have reached + ## the last-ordered permutation. + ## + ## .. code-block:: nim + ## + ## var v = @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + ## v.nextPermutation() + ## echo v + if x.len < 2: + return false + + var i = x.high + while i > 0 and x[i-1] >= x[i]: + dec i + + if i == 0: + return false + + var j = x.high + while j >= i and x[j] <= x[i-1]: + dec j + + swap x[j], x[i-1] + x.reverse(i, x.high) + + result = true + +proc prevPermutation*[T](x: var openarray[T]): bool {.discardable.} = + ## Calculates the previous lexicographic permutation, directly modifying + ## ``x``. The result is whether a permutation happened, otherwise we have + ## reached the first-ordered permutation. + ## + ## .. code-block:: nim + ## + ## var v = @[0, 1, 2, 3, 4, 5, 6, 7, 9, 8] + ## v.prevPermutation() + ## echo v + if x.len < 2: + return false + + var i = x.high + while i > 0 and x[i-1] <= x[i]: + dec i + + if i == 0: + return false + + x.reverse(i, x.high) + + var j = x.high + while j >= i and x[j-1] < x[i-1]: + dec j + + swap x[i-1], x[j] + + result = true diff --git a/tests/stdlib/tpermutations.nim b/tests/stdlib/tpermutations.nim new file mode 100644 index 0000000000..99bc424cd2 --- /dev/null +++ b/tests/stdlib/tpermutations.nim @@ -0,0 +1,17 @@ +discard """ + output: '''@[0, 1, 2, 3, 4, 5, 6, 7, 9, 8] +@[0, 1, 2, 3, 4, 5, 6, 8, 7, 9] +@[0, 1, 2, 3, 4, 5, 6, 8, 9, 7] +@[0, 1, 2, 3, 4, 5, 6, 8, 7, 9] +@[0, 1, 2, 3, 4, 5, 6, 7, 9, 8] +@[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]''' +""" +import algorithm + +var v = @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +for i in 1..3: + v.nextPermutation() + echo v +for i in 1..3: + v.prevPermutation() + echo v From fc5700619bfcab56fcfe7f62cf87906d1d012e8a Mon Sep 17 00:00:00 2001 From: Simon Hafner Date: Sun, 1 Feb 2015 23:24:43 -0600 Subject: [PATCH 011/250] report how to create a compiler stacktrace #1280 --- compiler/msgs.nim | 5 ++++- lib/system/excpt.nim | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 35a1217692..8d1a18b444 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -715,7 +715,10 @@ type proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) = template quit = if defined(debug) or gVerbosity >= 3 or msg == errInternal: - writeStackTrace() + if stackTraceAvailable(): + writeStackTrace() + else: + stderr.writeln("No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp c ") quit 1 if msg >= fatalMin and msg <= fatalMax: diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 417a8634f6..1b3471978a 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -175,6 +175,8 @@ proc auxWriteStackTrace(f: PFrame, s: var string) = add(s, tempFrames[j].procname) add(s, "\n") +proc stackTraceAvailable*(): bool + when hasSomeStackTrace: proc rawWriteStackTrace(s: var string) = when NimStackTrace: @@ -188,6 +190,18 @@ when hasSomeStackTrace: auxWriteStackTraceWithBacktrace(s) else: add(s, "No stack traceback available\n") + proc stackTraceAvailable(): bool = + when NimStackTrace: + if framePtr == nil: + result = false + else: + result = true + elif defined(nativeStackTrace) and nativeStackTraceSupported: + result = true + else: + result = false +else: + proc stackTraceAvailable*(): bool = result = false proc quitOrDebug() {.inline.} = when not defined(endb): From 03db4d2930bb5265da1d966cd32d7f5faccb6056 Mon Sep 17 00:00:00 2001 From: def Date: Mon, 2 Feb 2015 08:06:19 +0100 Subject: [PATCH 012/250] Adapt the tester for permutations Uses the bool return value now --- tests/stdlib/tpermutations.nim | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/stdlib/tpermutations.nim b/tests/stdlib/tpermutations.nim index 99bc424cd2..a6e07ded6f 100644 --- a/tests/stdlib/tpermutations.nim +++ b/tests/stdlib/tpermutations.nim @@ -1,17 +1,19 @@ discard """ - output: '''@[0, 1, 2, 3, 4, 5, 6, 7, 9, 8] -@[0, 1, 2, 3, 4, 5, 6, 8, 7, 9] -@[0, 1, 2, 3, 4, 5, 6, 8, 9, 7] -@[0, 1, 2, 3, 4, 5, 6, 8, 7, 9] -@[0, 1, 2, 3, 4, 5, 6, 7, 9, 8] -@[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]''' + output: '''@[0, 2, 1] +@[1, 0, 2] +@[1, 2, 0] +@[2, 0, 1] +@[2, 1, 0] +@[2, 0, 1] +@[1, 2, 0] +@[1, 0, 2] +@[0, 2, 1] +@[0, 1, 2]''' """ import algorithm -var v = @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] -for i in 1..3: - v.nextPermutation() +var v = @[0, 1, 2] +while v.nextPermutation(): echo v -for i in 1..3: - v.prevPermutation() +while v.prevPermutation(): echo v From 07f42fa612db998ec88dade7ea3140ba6a15fb5b Mon Sep 17 00:00:00 2001 From: dumndummer Date: Mon, 2 Feb 2015 14:42:00 +0000 Subject: [PATCH 013/250] Changed name 'pred' to 'op' in mapIt template --- lib/pure/collections/sequtils.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index a0e9280f54..b527b93687 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -397,7 +397,7 @@ template mapIt*(seq1, typ, op: expr): expr = ## assert strings == @["4", "8", "12", "16"] var result {.gensym.}: seq[typ] = @[] for it {.inject.} in items(seq1): - result.add(pred) + result.add(op) result template mapIt*(varSeq, op: expr) = @@ -413,7 +413,7 @@ template mapIt*(varSeq, op: expr) = ## assert nums[0] + nums[3] == 15 for i in 0 .. Date: Mon, 2 Feb 2015 17:57:31 +0000 Subject: [PATCH 014/250] Update macros.nim minor doc comment spelling correction --- lib/core/macros.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 3e0da79be6..22b9c49073 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -238,7 +238,7 @@ proc genSym*(kind: TNimrodSymKind = nskLet; ident = ""): PNimrodNode {. ## needs to occur in a declaration context. proc callsite*(): PNimrodNode {.magic: "NCallSite", gcsafe.} - ## returns the AST if the invokation expression that invoked this macro. + ## returns the AST of the invocation expression that invoked this macro. proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} = ## converts the AST `n` to the concrete Nimrod code and wraps that From 39839fda8a428d0d1626d9f2520b79ab68fa472b Mon Sep 17 00:00:00 2001 From: def Date: Tue, 3 Feb 2015 09:04:24 +0100 Subject: [PATCH 015/250] Rename *.nimrod.cfg to *.nim.cfg --- compiler/{nim.nimrod.cfg => nim.nim.cfg} | 0 koch.nimrod.cfg => koch.nim.cfg | 0 lib/{nimrtl.nimrod.cfg => nimrtl.nim.cfg} | 0 lib/pure/{asyncdispatch.nimrod.cfg => asyncdispatch.nim.cfg} | 0 lib/pure/{nimprof.nimrod.cfg => nimprof.nim.cfg} | 0 lib/pure/{smtp.nimrod.cfg => smtp.nim.cfg} | 0 tests/dll/{client.nimrod.cfg => client.nim.cfg} | 0 tests/dll/{server.nimrod.cfg => server.nim.cfg} | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename compiler/{nim.nimrod.cfg => nim.nim.cfg} (100%) rename koch.nimrod.cfg => koch.nim.cfg (100%) rename lib/{nimrtl.nimrod.cfg => nimrtl.nim.cfg} (100%) rename lib/pure/{asyncdispatch.nimrod.cfg => asyncdispatch.nim.cfg} (100%) rename lib/pure/{nimprof.nimrod.cfg => nimprof.nim.cfg} (100%) rename lib/pure/{smtp.nimrod.cfg => smtp.nim.cfg} (100%) rename tests/dll/{client.nimrod.cfg => client.nim.cfg} (100%) rename tests/dll/{server.nimrod.cfg => server.nim.cfg} (100%) diff --git a/compiler/nim.nimrod.cfg b/compiler/nim.nim.cfg similarity index 100% rename from compiler/nim.nimrod.cfg rename to compiler/nim.nim.cfg diff --git a/koch.nimrod.cfg b/koch.nim.cfg similarity index 100% rename from koch.nimrod.cfg rename to koch.nim.cfg diff --git a/lib/nimrtl.nimrod.cfg b/lib/nimrtl.nim.cfg similarity index 100% rename from lib/nimrtl.nimrod.cfg rename to lib/nimrtl.nim.cfg diff --git a/lib/pure/asyncdispatch.nimrod.cfg b/lib/pure/asyncdispatch.nim.cfg similarity index 100% rename from lib/pure/asyncdispatch.nimrod.cfg rename to lib/pure/asyncdispatch.nim.cfg diff --git a/lib/pure/nimprof.nimrod.cfg b/lib/pure/nimprof.nim.cfg similarity index 100% rename from lib/pure/nimprof.nimrod.cfg rename to lib/pure/nimprof.nim.cfg diff --git a/lib/pure/smtp.nimrod.cfg b/lib/pure/smtp.nim.cfg similarity index 100% rename from lib/pure/smtp.nimrod.cfg rename to lib/pure/smtp.nim.cfg diff --git a/tests/dll/client.nimrod.cfg b/tests/dll/client.nim.cfg similarity index 100% rename from tests/dll/client.nimrod.cfg rename to tests/dll/client.nim.cfg diff --git a/tests/dll/server.nimrod.cfg b/tests/dll/server.nim.cfg similarity index 100% rename from tests/dll/server.nimrod.cfg rename to tests/dll/server.nim.cfg From b594c332cacf5294d8d6e3139f3100a307567ed4 Mon Sep 17 00:00:00 2001 From: def Date: Tue, 3 Feb 2015 17:27:29 +0100 Subject: [PATCH 016/250] Add termios wrapper --- lib/posix/termios.nim | 255 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 lib/posix/termios.nim diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim new file mode 100644 index 0000000000..492a1456f4 --- /dev/null +++ b/lib/posix/termios.nim @@ -0,0 +1,255 @@ +{.deadCodeElim: on.} +import posix + +type + Speed* = cuint + Tcflag* = cuint + +const + NCCS* = 32 + +type + Termios* = object {.importc: "struct termios", header: "termios.h>", final, pure.} + iflag*: Tcflag # input mode flags + oflag*: Tcflag # output mode flags + cflag*: Tcflag # control mode flags + lflag*: Tcflag # local mode flags + line*: cuchar # line discipline + cc*: array[NCCS, cuchar] # control characters + ispeed*: Speed # input speed + ospeed*: Speed # output speed + + +# cc characters + +const + VINTR* = 0 + VQUIT* = 1 + VERASE* = 2 + VKILL* = 3 + VEOF* = 4 + VTIME* = 5 + VMIN* = 6 + VSWTC* = 7 + VSTART* = 8 + VSTOP* = 9 + VSUSP* = 10 + VEOL* = 11 + VREPRINT* = 12 + VDISCARD* = 13 + VWERASE* = 14 + VLNEXT* = 15 + VEOL2* = 16 + +# iflag bits + +const + IGNBRK* = 1 + BRKINT* = 2 + IGNPAR* = 4 + PARMRK* = 10 + INPCK* = 20 + ISTRIP* = 40 + INLCR* = 100 + IGNCR* = 200 + ICRNL* = 400 + IUCLC* = 1000 + IXON* = 2000 + IXANY* = 4000 + IXOFF* = 10000 + IMAXBEL* = 20000 + IUTF8* = 40000 + +# oflag bits + +const + OPOST* = 1 + OLCUC* = 2 + ONLCR* = 4 + OCRNL* = 10 + ONOCR* = 20 + ONLRET* = 40 + OFILL* = 100 + OFDEL* = 200 + NLDLY* = 400 + NL0* = 0 + NL1* = 400 + CRDLY* = 3000 + CR0* = 0 + CR1* = 1000 + CR2* = 2000 + CR3* = 3000 + TABDLY* = 14000 + TAB0* = 0 + TAB1* = 4000 + TAB2* = 10000 + TAB3* = 14000 + BSDLY* = 20000 + BS0* = 0 + BS1* = 20000 + FFDLY* = 0o000000100000 + FF0* = 0 + FF1* = 0o000000100000 + VTDLY* = 40000 + VT0* = 0 + VT1* = 40000 + XTABS* = 14000 + +# cflag bit meaning + +const + CBAUD* = 10017 + B0* = 0 + B50* = 1 + B75* = 2 + B110* = 3 + B134* = 4 + B150* = 5 + B200* = 6 + B300* = 7 + B600* = 10 + B1200* = 11 + B1800* = 12 + B2400* = 13 + B4800* = 14 + B9600* = 15 + B19200* = 16 + B38400* = 17 + EXTA* = B19200 + EXTB* = B38400 + CSIZE* = 60 + CS5* = 0 + CS6* = 20 + CS7* = 40 + CS8* = 60 + CSTOPB* = 100 + CREAD* = 200 + PARENB* = 400 + PARODD* = 1000 + HUPCL* = 2000 + CLOCAL* = 4000 + CBAUDEX* = 10000 + B57600* = 10001 + B115200* = 10002 + B230400* = 10003 + B460800* = 10004 + B500000* = 10005 + B576000* = 10006 + B921600* = 10007 + B1000000* = 10010 + B1152000* = 10011 + B1500000* = 10012 + B2000000* = 10013 + B2500000* = 10014 + B3000000* = 10015 + B3500000* = 10016 + B4000000* = 10017 + MAX_BAUD* = B4000000 + CIBAUD* = 2003600000 + CMSPAR* = 0o010000000000 + CRTSCTS* = 0o020000000000 + +# lflag bits + +const + ISIG* = 1 + ICANON* = 2 + XCASE* = 4 + ECHO* = 10 + ECHOE* = 20 + ECHOK* = 40 + ECHONL* = 100 + NOFLSH* = 200 + TOSTOP* = 400 + ECHOCTL* = 1000 + ECHOPRT* = 2000 + ECHOKE* = 4000 + FLUSHO* = 10000 + PENDIN* = 40000 + IEXTEN* = 0o000000100000 + EXTPROC* = 0o000000200000 + +# tcflow() and TCXONC use these + +const + TCOOFF* = 0 + TCOON* = 1 + TCIOFF* = 2 + TCION* = 3 + +# tcflush() and TCFLSH use these + +const + TCIFLUSH* = 0 + TCOFLUSH* = 1 + TCIOFLUSH* = 2 + +# tcsetattr uses these + +const + TCSANOW* = 0 + TCSADRAIN* = 1 + TCSAFLUSH* = 2 + +# Compare a character C to a value VAL from the `cc' array in a +# `struct termios'. If VAL is _POSIX_VDISABLE, no character can match it. + +template CCEQ*(val, c: expr): expr = + ((c) == (val) and (val) != POSIX_VDISABLE) + +# Return the output baud rate stored in *TERMIOS_P. + +proc cfgetospeed*(termios: ptr Termios): Speed {.importc: "cfgetospeed", + header: "".} +# Return the input baud rate stored in *TERMIOS_P. + +proc cfgetispeed*(termios: ptr Termios): Speed {.importc: "cfgetispeed", + header: "".} +# Set the output baud rate stored in *TERMIOS_P to SPEED. + +proc cfsetospeed*(termios: ptr Termios; speed: Speed): cint {. + importc: "cfsetospeed", header: "".} +# Set the input baud rate stored in *TERMIOS_P to SPEED. + +proc cfsetispeed*(termios: ptr Termios; speed: Speed): cint {. + importc: "cfsetispeed", header: "".} +# Set both the input and output baud rates in *TERMIOS_OP to SPEED. + +proc cfsetspeed*(termios: ptr Termios; speed: Speed): cint {. + importc: "cfsetspeed", header: "".} +# Put the state of FD into *TERMIOS_P. + +proc tcgetattr*(fd: cint; termios: ptr Termios): cint {. + importc: "tcgetattr", header: "".} +# Set the state of FD to *TERMIOS_P. +# Values for OPTIONAL_ACTIONS (TCSA*) are in . + +proc tcsetattr*(fd: cint; optional_actions: cint; termios: ptr Termios): cint {. + importc: "tcsetattr", header: "".} +# Set *TERMIOS_P to indicate raw mode. + +proc cfmakeraw*(termios: ptr Termios) {.importc: "cfmakeraw", + header: "".} +# Send zero bits on FD. + +proc tcsendbreak*(fd: cint; duration: cint): cint {.importc: "tcsendbreak", + header: "".} +# Wait for pending output to be written on FD. +# +# This function is a cancellation point and therefore not marked with +# . + +proc tcdrain*(fd: cint): cint {.importc: "tcdrain", header: "".} +# Flush pending data on FD. +# Values for QUEUE_SELECTOR (TC{I,O,IO}FLUSH) are in . + +proc tcflush*(fd: cint; queue_selector: cint): cint {.importc: "tcflush", + header: "".} +# Suspend or restart transmission on FD. +# Values for ACTION (TC[IO]{OFF,ON}) are in . + +proc tcflow*(fd: cint; action: cint): cint {.importc: "tcflow", + header: "".} +# Get process group ID for session leader for controlling terminal FD. + +proc tcgetsid*(fd: cint): TPid {.importc: "tcgetsid", header: "".} From f3124e6de43fd98800c32cdfc956134ab00cb1a4 Mon Sep 17 00:00:00 2001 From: def Date: Tue, 3 Feb 2015 17:27:59 +0100 Subject: [PATCH 017/250] Add terminal.getch to get a single character --- lib/pure/terminal.nim | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 8607066f3e..b0c822c57d 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -45,6 +45,21 @@ when defined(windows): var oldAttr = getAttributes() + proc winGetch(): cint {.header: "", importc: "_getch".} +else: + import termios, unsigned + + proc setRaw(fd: FileHandle, time: cint = TCSAFLUSH) = + var mode: Termios + discard fd.tcgetattr(addr mode) + mode.iflag = mode.iflag and not Tcflag(BRKINT or ICRNL or INPCK or ISTRIP or IXON) + mode.oflag = mode.oflag and not Tcflag(OPOST) + mode.cflag = (mode.cflag and not Tcflag(CSIZE or PARENB)) or CS8 + mode.lflag = mode.lflag and not Tcflag(ECHO or ICANON or IEXTEN or ISIG) + mode.cc[VMIN] = 1.cuchar + mode.cc[VTIME] = 0.cuchar + discard fd.tcsetattr(time, addr mode) + proc setCursorPos*(x, y: int) = ## sets the terminal's cursor to the (x,y) position. (0,0) is the ## upper left of the screen. @@ -349,6 +364,17 @@ macro styledEcho*(m: varargs[expr]): stmt = result.add(newCall(bindSym"write", bindSym"stdout", newStrLitNode("\n"))) result.add(newCall(bindSym"resetAttributes")) +proc getch*(): char = + when defined(windows): + result = winGetch().char + else: + let fd = getFileHandle(stdin) + var oldMode: Termios + discard fd.tcgetattr(addr oldMode) + fd.setRaw() + result = stdin.readChar() + discard fd.tcsetattr(TCSADRAIN, addr oldMode) + when isMainModule: system.addQuitProc(resetAttributes) write(stdout, "never mind") From e7eab49e14e4764cecaf6e415d71556238f5642b Mon Sep 17 00:00:00 2001 From: def Date: Tue, 3 Feb 2015 17:29:09 +0100 Subject: [PATCH 018/250] Add copyright header --- lib/posix/termios.nim | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim index 492a1456f4..88aed73c8d 100644 --- a/lib/posix/termios.nim +++ b/lib/posix/termios.nim @@ -1,3 +1,12 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2015 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + {.deadCodeElim: on.} import posix From 3b68d9e93c603117a301aa5048bfd61774434eb2 Mon Sep 17 00:00:00 2001 From: def Date: Tue, 3 Feb 2015 17:29:09 +0100 Subject: [PATCH 019/250] Add copyright header --- lib/posix/termios.nim | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim index 492a1456f4..88aed73c8d 100644 --- a/lib/posix/termios.nim +++ b/lib/posix/termios.nim @@ -1,3 +1,12 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2015 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + {.deadCodeElim: on.} import posix From dcd23ae1f1b52f48f3d32a753ae4db065b3985f8 Mon Sep 17 00:00:00 2001 From: def Date: Tue, 3 Feb 2015 17:47:27 +0100 Subject: [PATCH 020/250] Add readPasswordFromStdin to rdstdin --- lib/impure/rdstdin.nim | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim index 07ef13fd97..258da22072 100644 --- a/lib/impure/rdstdin.nim +++ b/lib/impure/rdstdin.nim @@ -31,9 +31,27 @@ when defined(Windows): stdout.write(prompt) result = readLine(stdin, line) + proc getch(): cint {.header: "", importc: "_getch".} + + proc readPasswordFromStdin*(prompt: string, password: var TaintedString) = + ## Reads a `password` from stdin without printing it. `password` must not + ## be ``nil``! + password.setLen(0) + var c: char + echo prompt + while true: + c = getch().char + case c + of '\r', chr(0xA): + break + of '\b': + password.setLen(result.len - 1) + else: + password.add(c) + else: - import readline, history - + import readline, history, termios, unsigned + proc readLineFromStdin*(prompt: string): TaintedString {. tags: [ReadIOEffect, WriteIOEffect].} = var buffer = readline.readLine(prompt) @@ -55,8 +73,24 @@ else: result = true # initialization: - # disable auto-complete: + # disable auto-complete: proc doNothing(a, b: cint): cint {.cdecl, procvar.} = discard - + discard readline.bind_key('\t'.ord, doNothing) + proc readPasswordFromStdin*(prompt: string, password: var TaintedString) = + password.setLen(0) + let fd = stdin.getFileHandle() + var cur, old: Termios + discard fd.tcgetattr(cur.addr) + old = cur + cur.lflag = cur.lflag and not Tcflag(ECHO) + discard fd.tcsetattr(TCSADRAIN, cur.addr) + stdout.write prompt + discard stdin.readLine(password) + discard fd.tcsetattr(TCSADRAIN, old.addr) + +proc readPasswordFromStdin*(prompt: string): TaintedString = + ## Reads a password from stdin without printing it. + result = TaintedString("") + readPasswordFromStdin(prompt, result) From a400e8f7f39b1bb29245323c6d999f01b46f22c3 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 3 Feb 2015 13:19:33 +0100 Subject: [PATCH 021/250] better error message for auto-deref --- compiler/semcall.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index cdfdfc9d02..5cb7130305 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -315,6 +315,8 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode, var r = resolveOverloads(c, n, nOrig, filter, errors) if r.state == csMatch: result = semResolvedCall(c, n, r) else: + # get rid of the deref again for a better error message: + n.sons[1] = n.sons[1].sons[0] notFoundError(c, n, errors) else: notFoundError(c, n, errors) From e75e4219121e9120edc4c53eef6af46de9c6eb50 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 3 Feb 2015 13:21:05 +0100 Subject: [PATCH 022/250] C++ support: codegen generates C++'s references and avoids copies --- compiler/ast.nim | 6 +-- compiler/ccgcalls.nim | 76 +++++++++++++++++++++----------- compiler/ccgexprs.nim | 23 +++++++--- compiler/ccgstmts.nim | 13 +++++- compiler/ccgtypes.nim | 96 ++++++++++++++++++++--------------------- compiler/cgen.nim | 34 +++++++++------ lib/system/dyncalls.nim | 9 +++- 7 files changed, 156 insertions(+), 101 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index d487b5380a..f7c1a07eda 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -655,7 +655,6 @@ type locGlobalVar, # location is a global variable locParam, # location is a parameter locField, # location is a record field - locArrayElem, # location is an array element locExpr, # "location" is really an expression locProc, # location is a proc (an address of a procedure) locData, # location is a constant @@ -669,14 +668,15 @@ type lfDynamicLib, # link symbol to dynamic library lfExportLib, # export symbol for dynamic library generation lfHeader, # include header file for symbol - lfImportCompilerProc # ``importc`` of a compilerproc + lfImportCompilerProc, # ``importc`` of a compilerproc + lfSingleUse # no location yet and will only be used once TStorageLoc* = enum OnUnknown, # location is unknown (stack, heap or static) OnStack, # location is on hardware stack OnHeap # location is on heap or global # (reference counting needed) TLocFlags* = set[TLocFlag] - TLoc*{.final.} = object + TLoc* = object k*: TLocKind # kind of location s*: TStorageLoc flags*: TLocFlags # location's flags diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index cb8dcc25b3..ad9d182571 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -45,12 +45,20 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, genAssignment(p, d, tmp, {}) # no need for deep copying else: app(pl, ~")") - if d.k == locNone: getTemp(p, typ.sons[0], d) - assert(d.t != nil) # generate an assignment to d: - var list: TLoc - initLoc(list, locCall, d.t, OnUnknown) - list.r = pl - genAssignment(p, d, list, {}) # no need for deep copying + if p.module.compileToCpp and lfSingleUse in d.flags: + # do not generate spurious temporaries for C++! For C we're better off + # with them to prevent undefined behaviour and because the codegen + # is free to emit expressions multiple times! + d.k = locCall + d.r = pl + excl d.flags, lfSingleUse + else: + if d.k == locNone: getTemp(p, typ.sons[0], d) + assert(d.t != nil) # generate an assignment to d: + var list: TLoc + initLoc(list, locCall, d.t, OnUnknown) + list.r = pl + genAssignment(p, d, list, {}) # no need for deep copying else: app(pl, ~");$n") line(p, cpsStmts, pl) @@ -90,7 +98,8 @@ proc openArrayLoc(p: BProc, n: PNode): PRope = of tyOpenArray, tyVarargs, tyArray, tyArrayConstr: "($1)+($2), ($3)-($2)+1" of tyString, tySequence: - if skipTypes(n.typ, abstractInst).kind == tyVar: + if skipTypes(n.typ, abstractInst).kind == tyVar and + not compileToCpp(p.module): "(*$1)->data+($2), ($3)-($2)+1" else: "$1->data+($2), ($3)-($2)+1" @@ -102,7 +111,8 @@ proc openArrayLoc(p: BProc, n: PNode): PRope = of tyOpenArray, tyVarargs: result = ropef("$1, $1Len0", [rdLoc(a)]) of tyString, tySequence: - if skipTypes(n.typ, abstractInst).kind == tyVar: + if skipTypes(n.typ, abstractInst).kind == tyVar and + not compileToCpp(p.module): result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField(p)]) else: result = ropef("$1->data, $1->$2", [a.rdLoc, lenField(p)]) @@ -123,10 +133,14 @@ proc genArg(p: BProc, n: PNode, param: PSym): PRope = var n = if n.kind != nkHiddenAddr: n else: n.sons[0] result = openArrayLoc(p, n) elif ccgIntroducedPtr(param): - initLocExpr(p, n, a) + initLocExprSingleUse(p, n, a) result = addrLoc(a) + elif p.module.compileToCpp and param.typ.kind == tyVar and + n.kind == nkHiddenAddr: + initLocExprSingleUse(p, n.sons[0], a) + result = rdLoc(a) else: - initLocExpr(p, n, a) + initLocExprSingleUse(p, n, a) result = rdLoc(a) proc genArgNoParam(p: BProc, n: PNode): PRope = @@ -134,7 +148,7 @@ proc genArgNoParam(p: BProc, n: PNode): PRope = if n.kind == nkStringToCString: result = genArgStringToCString(p, n) else: - initLocExpr(p, n, a) + initLocExprSingleUse(p, n, a) result = rdLoc(a) proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) = @@ -274,26 +288,28 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): PRope = assert(typ.n.sons[i].kind == nkSym) # if the parameter is lying (tyVar) and thus we required an additional deref, # skip the deref: + var ri = ri[i] + while ri.kind == nkObjDownConv: ri = ri[0] if typ.sons[i].kind == tyVar: - let x = if ri[i].kind == nkHiddenAddr: ri[i][0] else: ri[i] - if x.kind in {nkHiddenDeref, nkDerefExpr}: - result = genArgNoParam(p, x[0]) - result.app("->") - elif x.typ.kind in {tyVar, tyPtr}: + let x = if ri.kind == nkHiddenAddr: ri[0] else: ri + if x.typ.kind == tyPtr: result = genArgNoParam(p, x) result.app("->") + elif x.kind in {nkHiddenDeref, nkDerefExpr}: + result = genArgNoParam(p, x[0]) + result.app("->") else: result = genArgNoParam(p, x) result.app(".") elif typ.sons[i].kind == tyPtr: - if ri.sons[i].kind in {nkAddr, nkHiddenAddr}: - result = genArgNoParam(p, ri.sons[i][0]) + if ri.kind in {nkAddr, nkHiddenAddr}: + result = genArgNoParam(p, ri[0]) result.app(".") else: - result = genArgNoParam(p, ri.sons[i]) + result = genArgNoParam(p, ri) result.app("->") else: - result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym) + result = genArgNoParam(p, ri) #, typ.n.sons[i].sym) result.app(".") proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope = @@ -367,12 +383,20 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = # simpler version of 'fixupCall' that works with the pl+params combination: var typ = skipTypes(ri.sons[0].typ, abstractInst) if typ.sons[0] != nil: - if d.k == locNone: getTemp(p, typ.sons[0], d) - assert(d.t != nil) # generate an assignment to d: - var list: TLoc - initLoc(list, locCall, d.t, OnUnknown) - list.r = pl - genAssignment(p, d, list, {}) # no need for deep copying + if p.module.compileToCpp and lfSingleUse in d.flags: + # do not generate spurious temporaries for C++! For C we're better off + # with them to prevent undefined behaviour and because the codegen + # is free to emit expressions multiple times! + d.k = locCall + d.r = pl + excl d.flags, lfSingleUse + else: + if d.k == locNone: getTemp(p, typ.sons[0], d) + assert(d.t != nil) # generate an assignment to d: + var list: TLoc + initLoc(list, locCall, d.t, OnUnknown) + list.r = pl + genAssignment(p, d, list, {}) # no need for deep copying else: app(pl, ~";$n") line(p, cpsStmts, pl) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 93bb5dbf56..e0261f92c5 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -662,9 +662,13 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8), getSimpleTypeDesc(p.module, e.typ)])) +proc isCppRef(p: BProc; typ: PType): bool {.inline.} = + result = p.module.compileToCpp and + skipTypes(typ, abstractInst).kind == tyVar + proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) = let mt = mapType(e.sons[0].typ) - if mt in {ctArray, ctPtrToArray} and not enforceDeref: + if (mt in {ctArray, ctPtrToArray} and not enforceDeref): # XXX the amount of hacks for C's arrays is incredible, maybe we should # simply wrap them in a struct? --> Losing auto vectorization then? #if e[0].kind != nkBracketExpr: @@ -672,12 +676,15 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) = expr(p, e.sons[0], d) else: var a: TLoc - initLocExpr(p, e.sons[0], a) + initLocExprSingleUse(p, e.sons[0], a) case skipTypes(a.t, abstractInst).kind of tyRef: d.s = OnHeap of tyVar: d.s = OnUnknown + if p.module.compileToCpp: + putIntoDest(p, d, e.typ, rdLoc(a)) + return of tyPtr: d.s = OnUnknown # BUGFIX! else: internalError(e.info, "genDeref " & $a.t.kind) @@ -698,7 +705,7 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) = initLocExpr(p, e.sons[0], a) putIntoDest(p, d, e.typ, con("&", a.r)) #Message(e.info, warnUser, "HERE NEW &") - elif mapType(e.sons[0].typ) == ctArray: + elif mapType(e.sons[0].typ) == ctArray or isCppRef(p, e.sons[0].typ): expr(p, e.sons[0], d) else: var a: TLoc @@ -1236,7 +1243,8 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = var t = skipTypes(a.t, abstractInst) while t.kind in {tyVar, tyPtr, tyRef}: if t.kind != tyVar: nilCheck = r - r = rfmt(nil, "(*$1)", r) + if t.kind != tyVar or not p.module.compileToCpp: + r = rfmt(nil, "(*$1)", r) t = skipTypes(t.lastSon, typedescInst) if not p.module.compileToCpp: while t.kind == tyObject and t.sons[0] != nil: @@ -1863,7 +1871,8 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) = var t = skipTypes(a.t, abstractInst) while t.kind in {tyVar, tyPtr, tyRef}: if t.kind != tyVar: nilCheck = r - r = ropef("(*$1)", [r]) + if t.kind != tyVar or not p.module.compileToCpp: + r = ropef("(*$1)", [r]) t = skipTypes(t.lastSon, abstractInst) if not p.module.compileToCpp: while t.kind == tyObject and t.sons[0] != nil: @@ -2073,9 +2082,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = genAsgn(p, n, fastAsgn=p.prc != nil) of nkDiscardStmt: if n.sons[0].kind != nkEmpty: - var a: TLoc genLineDir(p, n) - initLocExpr(p, n.sons[0], a) + var a: TLoc + initLocExprSingleUse(p, n.sons[0], a) of nkAsmStmt: genAsmStmt(p, n) of nkTryStmt: if p.module.compileToCpp: genTryCpp(p, n, d) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index f0870a5df6..5d348c4e4b 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -202,8 +202,19 @@ proc genSingleVar(p: BProc, a: PNode) = genVarPrototypeAux(generatedHeader, v) registerGcRoot(p, v) else: + let imm = isAssignedImmediately(a.sons[2]) + if imm and p.module.compileToCpp: + # C++ really doesn't like things like 'Foo f; f = x' as that invokes a + # parameterless constructor followed by an assignment operator. So we + # generate better code here: + genLineDir(p, a) + let decl = localVarDecl(p, v) + var tmp: TLoc + initLocExprSingleUse(p, a.sons[2], tmp) + lineF(p, cpsStmts, "$# = $#;$n", decl, tmp.rdLoc) + return assignLocalVar(p, v) - initLocalVar(p, v, isAssignedImmediately(a.sons[2])) + initLocalVar(p, v, imm) if a.sons[2].kind != nkEmpty: genLineDir(targetProc, a) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 90996d9cdb..823e3bc1b3 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -161,7 +161,13 @@ proc mapType(typ: PType): TCTypeKind = proc mapReturnType(typ: PType): TCTypeKind = if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr else: result = mapType(typ) - + +proc isImportedType(t: PType): bool = + result = t.sym != nil and sfImportc in t.sym.flags + +proc isImportedCppType(t: PType): bool = + result = t.sym != nil and sfInfixCall in t.sym.flags + proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope proc needsComplexAssignment(typ: PType): bool = result = containsGarbageCollectedRef(typ) @@ -170,19 +176,20 @@ proc isObjLackingTypeField(typ: PType): bool {.inline.} = result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and (typ.sons[0] == nil) or isPureObject(typ)) -proc isInvalidReturnType(rettype: PType): bool = +proc isInvalidReturnType(rettype: PType): bool = # Arrays and sets cannot be returned by a C procedure, because C is # such a poor programming language. # We exclude records with refs too. This enhances efficiency and # is necessary for proper code generation of assignments. if rettype == nil: result = true - else: + else: case mapType(rettype) - of ctArray: + of ctArray: result = not (skipTypes(rettype, typedescInst).kind in {tyVar, tyRef, tyPtr}) of ctStruct: let t = skipTypes(rettype, typedescInst) + if rettype.isImportedCppType or t.isImportedCppType: return false result = needsComplexAssignment(t) or (t.kind == tyObject and not isObjLackingTypeField(t)) else: result = false @@ -297,12 +304,6 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope, else: app(params, ")") params = con("(", params) -proc isImportedType(t: PType): bool = - result = t.sym != nil and sfImportc in t.sym.flags - -proc isImportedCppType(t: PType): bool = - result = t.sym != nil and sfInfixCall in t.sym.flags - proc typeNameOrLiteral(t: PType, literal: string): PRope = if (t.sym != nil) and (sfImportc in t.sym.flags) and (t.sym.magic == mNone): result = getTypeName(t) @@ -421,14 +422,18 @@ proc genRecordFieldsAux(m: BModule, n: PNode, if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname]) else: ae = sname fillLoc(field.loc, locField, field.typ, ae, OnUnknown) - let fieldType = field.loc.t.skipTypes(abstractInst) - if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags: - appf(result, "$1 $2[SEQ_DECL_SIZE];$n", - [getTypeDescAux(m, fieldType.elemType, check), sname]) - else: - # don't use fieldType here because we need the - # tyGenericInst for C++ template support - appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname]) + # for importcpp'ed objects, we only need to set field.loc, but don't + # have to recurse via 'getTypeDescAux'. And not doing so prevents problems + # with heavily templatized C++ code: + if not isImportedCppType(rectype): + let fieldType = field.loc.t.skipTypes(abstractInst) + if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags: + appf(result, "$1 $2[SEQ_DECL_SIZE];$n", + [getTypeDescAux(m, fieldType.elemType, check), sname]) + else: + # don't use fieldType here because we need the + # tyGenericInst for C++ template support + appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname]) else: internalError(n.info, "genRecordFieldsAux()") proc getRecordFields(m: BModule, typ: PType, check: var IntSet): PRope = @@ -493,13 +498,15 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope = if t.sym != nil: useHeader(m, t.sym) result = getTypePre(m, t) if result != nil: return - if containsOrIncl(check, t.id): + if containsOrIncl(check, t.id): + if isImportedCppType(typ) or isImportedCppType(t): return internalError("cannot generate C type for: " & typeToString(typ)) # XXX: this BUG is hard to fix -> we need to introduce helper structs, # but determining when this needs to be done is hard. We should split # C type generation into an analysis and a code generation phase somehow. case t.kind of tyRef, tyPtr, tyVar: + let star = if t.kind == tyVar and compileToCpp(m): "&" else: "*" var et = t.lastSon var etB = et.skipTypes(abstractInst) if etB.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}: @@ -510,12 +517,12 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope = case etB.kind of tyObject, tyTuple: if isImportedCppType(etB) and et.kind == tyGenericInst: - result = con(getTypeDescAux(m, et, check), "*") + result = con(getTypeDescAux(m, et, check), star) else: # no restriction! We have a forward declaration for structs let x = getUniqueType(etB) let name = getTypeForward(m, x) - result = con(name, "*") + result = con(name, star) idTablePut(m.typeCache, t, result) pushType(m, x) of tySequence: @@ -527,7 +534,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope = pushType(m, x) else: # else we have a strong dependency :-( - result = con(getTypeDescAux(m, et, check), "*") + result = con(getTypeDescAux(m, et, check), star) idTablePut(m.typeCache, t, result) of tyOpenArray, tyVarargs: result = con(getTypeDescAux(m, t.sons[0], check), "*") @@ -696,16 +703,7 @@ proc getNimNode(m: BModule): PRope = result = ropef("$1[$2]", [m.typeNodesName, toRope(m.typeNodes)]) inc(m.typeNodes) -when false: - proc getNimType(m: BModule): PRope = - result = ropef("$1[$2]", [m.nimTypesName, toRope(m.nimTypes)]) - inc(m.nimTypes) - - proc allocMemTI(m: BModule, typ: PType, name: PRope) = - var tmp = getNimType(m) - appf(m.s[cfsTypeInit2], "$2 = &$1;$n", [tmp, name]) - -proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) = +proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: PRope) = var nimtypeKind: int #allocMemTI(m, typ, name) if isObjLackingTypeField(typ): @@ -715,6 +713,7 @@ proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) = var size: PRope if tfIncompleteStruct in typ.flags: size = toRope"void*" + elif m.compileToCpp: size = getTypeDesc(m, origType) else: size = getTypeDesc(m, typ) appf(m.s[cfsTypeInit3], "$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n", @@ -730,13 +729,13 @@ proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) = appf(m.s[cfsVars], "TNimType $1; /* $2 */$n", [name, toRope(typeToString(typ))]) -proc genTypeInfoAux(m: BModule, typ: PType, name: PRope) = +proc genTypeInfoAux(m: BModule, typ, origType: PType, name: PRope) = var base: PRope if (sonsLen(typ) > 0) and (typ.sons[0] != nil): base = genTypeInfo(m, typ.sons[0]) else: base = toRope("0") - genTypeInfoAuxBase(m, typ, name, base) + genTypeInfoAuxBase(m, typ, origType, name, base) proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope = # bugfix: we need to search the type that contains the discriminator: @@ -814,11 +813,12 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: PRope) = field.loc.r, genTypeInfo(m, field.typ), makeCString(field.name.s)]) else: internalError(n.info, "genObjectFields") -proc genObjectInfo(m: BModule, typ: PType, name: PRope) = - if typ.kind == tyObject: genTypeInfoAux(m, typ, name) - else: genTypeInfoAuxBase(m, typ, name, toRope("0")) +proc genObjectInfo(m: BModule, typ, origType: PType, name: PRope) = + if typ.kind == tyObject: genTypeInfoAux(m, typ, origType, name) + else: genTypeInfoAuxBase(m, typ, origType, name, toRope("0")) var tmp = getNimNode(m) - genObjectFields(m, typ, typ.n, tmp) + if not isImportedCppType(typ): + genObjectFields(m, typ, typ.n, tmp) appf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp]) var t = typ.sons[0] while t != nil: @@ -827,7 +827,7 @@ proc genObjectInfo(m: BModule, typ: PType, name: PRope) = t = t.sons[0] proc genTupleInfo(m: BModule, typ: PType, name: PRope) = - genTypeInfoAuxBase(m, typ, name, toRope("0")) + genTypeInfoAuxBase(m, typ, typ, name, toRope("0")) var expr = getNimNode(m) var length = sonsLen(typ) if length > 0: @@ -854,7 +854,7 @@ proc genEnumInfo(m: BModule, typ: PType, name: PRope) = # optimizations here: The ``typ`` field is never set, as it is redundant # anyway. We generate a cstring array and a loop over it. Exceptional # positions will be reset after the loop. - genTypeInfoAux(m, typ, name) + genTypeInfoAux(m, typ, typ, name) var nodePtrs = getTempName() var length = sonsLen(typ.n) appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", @@ -894,13 +894,13 @@ proc genEnumInfo(m: BModule, typ: PType, name: PRope) = proc genSetInfo(m: BModule, typ: PType, name: PRope) = assert(typ.sons[0] != nil) - genTypeInfoAux(m, typ, name) + genTypeInfoAux(m, typ, typ, name) var tmp = getNimNode(m) appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n", [tmp, toRope(firstOrd(typ)), name]) proc genArrayInfo(m: BModule, typ: PType, name: PRope) = - genTypeInfoAuxBase(m, typ, name, genTypeInfo(m, typ.sons[1])) + genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1])) proc fakeClosureType(owner: PSym): PType = # we generate the same RTTI as for a tuple[pointer, ref tuple[]] @@ -946,23 +946,23 @@ proc genTypeInfo(m: BModule, t: PType): PRope = case t.kind of tyEmpty: result = toRope"0" of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar: - genTypeInfoAuxBase(m, t, result, toRope"0") + genTypeInfoAuxBase(m, t, t, result, toRope"0") of tyProc: if t.callConv != ccClosure: - genTypeInfoAuxBase(m, t, result, toRope"0") + genTypeInfoAuxBase(m, t, t, result, toRope"0") else: genTupleInfo(m, fakeClosureType(t.owner), result) of tySequence, tyRef: - genTypeInfoAux(m, t, result) + genTypeInfoAux(m, t, t, result) if gSelectedGC >= gcMarkAndSweep: let markerProc = genTraverseProc(m, t, tiNew) appf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc]) - of tyPtr, tyRange: genTypeInfoAux(m, t, result) + of tyPtr, tyRange: genTypeInfoAux(m, t, t, result) of tyArrayConstr, tyArray: genArrayInfo(m, t, result) of tySet: genSetInfo(m, t, result) of tyEnum: genEnumInfo(m, t, result) - of tyObject: genObjectInfo(m, t, result) - of tyTuple: + of tyObject: genObjectInfo(m, t, origType, result) + of tyTuple: # if t.n != nil: genObjectInfo(m, t, result) # else: # BUGFIX: use consistently RTTI without proper field names; otherwise diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 480c131ae6..e16d5d0ce0 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -402,11 +402,8 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) = proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = inc(p.labels) - if gCmd == cmdCompileToLLVM: - result.r = con("%LOC", toRope(p.labels)) - else: - result.r = con("LOC", toRope(p.labels)) - linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r) + result.r = con("LOC", toRope(p.labels)) + linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r) result.k = locTemp #result.a = - 1 result.t = getUniqueType(t) @@ -494,22 +491,26 @@ proc localDebugInfo(p: BProc, s: PSym) = inc(p.maxFrameLen) inc p.blocks[p.blocks.len-1].frameLen -proc assignLocalVar(p: BProc, s: PSym) = - #assert(s.loc.k == locNone) // not yet assigned - # this need not be fullfilled for inline procs; they are regenerated - # for each module that uses them! +proc localVarDecl(p: BProc; s: PSym): PRope = if s.loc.k == locNone: fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack) if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy) - var decl = getTypeDesc(p.module, s.loc.t) + result = getTypeDesc(p.module, s.loc.t) if s.constraint.isNil: - if sfRegister in s.flags: app(decl, " register") + if sfRegister in s.flags: app(result, " register") #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds: # app(decl, " GC_GUARD") - if sfVolatile in s.flags: app(decl, " volatile") - appf(decl, " $1;$n", [s.loc.r]) + if sfVolatile in s.flags: app(result, " volatile") + app(result, " ") + app(result, s.loc.r) else: - decl = ropef(s.cgDeclFrmt & ";$n", decl, s.loc.r) + result = ropef(s.cgDeclFrmt, result, s.loc.r) + +proc assignLocalVar(p: BProc, s: PSym) = + #assert(s.loc.k == locNone) // not yet assigned + # this need not be fullfilled for inline procs; they are regenerated + # for each module that uses them! + let decl = localVarDecl(p, s).con(";" & tnl) line(p, cpsLocals, decl) localDebugInfo(p, s) @@ -586,6 +587,11 @@ proc initLocExpr(p: BProc, e: PNode, result: var TLoc) = initLoc(result, locNone, e.typ, OnUnknown) expr(p, e, result) +proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) = + initLoc(result, locNone, e.typ, OnUnknown) + result.flags.incl lfSingleUse + expr(p, e, result) + proc lenField(p: BProc): PRope = result = toRope(if p.module.compileToCpp: "len" else: "Sup.len") diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim index e0d99cf88a..aab2a7b61c 100644 --- a/lib/system/dyncalls.nim +++ b/lib/system/dyncalls.nim @@ -80,8 +80,13 @@ elif defined(windows) or defined(dos): # Native Windows Implementation # ======================================================================= # - type - THINSTANCE {.importc: "HINSTANCE".} = pointer + when defined(cpp): + type + THINSTANCE {.importc: "HINSTANCE".} = object + x: pointer + else: + type + THINSTANCE {.importc: "HINSTANCE".} = pointer proc freeLibrary(lib: THINSTANCE) {. importc: "FreeLibrary", header: "", stdcall.} From a0d3bd16e73c98840c65ab890064e1aa750b7060 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 3 Feb 2015 23:16:58 +0100 Subject: [PATCH 023/250] fixes stupid regression --- compiler/ccgexprs.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index e0261f92c5..bd116d6fba 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2084,7 +2084,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = if n.sons[0].kind != nkEmpty: genLineDir(p, n) var a: TLoc - initLocExprSingleUse(p, n.sons[0], a) + initLocExpr(p, n.sons[0], a) of nkAsmStmt: genAsmStmt(p, n) of nkTryStmt: if p.module.compileToCpp: genTryCpp(p, n, d) From 769652ac9060a9a382bae679d819f320eaec936b Mon Sep 17 00:00:00 2001 From: Flaviu Tamas Date: Tue, 3 Feb 2015 21:21:32 -0500 Subject: [PATCH 024/250] Expose exception parent This can be safely exposed because a proc accessor can be created if the representation changes. --- lib/system.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system.nim b/lib/system.nim index 12c5c63036..958372bb53 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -343,7 +343,7 @@ type ## ## Each exception has to inherit from `Exception`. See the full `exception ## hierarchy`_. - parent: ref Exception ## parent exception (can be used as a stack) + parent*: ref Exception ## parent exception (can be used as a stack) name: cstring ## The exception's name is its Nim identifier. ## This field is filled automatically in the ## ``raise`` statement. From c3ca9bf79e1ec05ae99728f19d66869e1c675819 Mon Sep 17 00:00:00 2001 From: Flaviu Tamas Date: Tue, 3 Feb 2015 21:22:28 -0500 Subject: [PATCH 025/250] Change formatting according to style guide --- lib/system.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 958372bb53..a6939472b4 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -343,10 +343,10 @@ type ## ## Each exception has to inherit from `Exception`. See the full `exception ## hierarchy`_. - parent*: ref Exception ## parent exception (can be used as a stack) - name: cstring ## The exception's name is its Nim identifier. - ## This field is filled automatically in the - ## ``raise`` statement. + parent*: ref Exception ## parent exception (can be used as a stack) + name: cstring ## The exception's name is its Nim identifier. + ## This field is filled automatically in the + ## ``raise`` statement. msg* {.exportc: "message".}: string ## the exception's message. Not ## providing an exception message ## is bad style. From 4712c6951280befa162687cc98611e052fe71788 Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 11:18:24 +0100 Subject: [PATCH 026/250] Fix typo --- lib/posix/termios.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim index 88aed73c8d..94258772fb 100644 --- a/lib/posix/termios.nim +++ b/lib/posix/termios.nim @@ -18,7 +18,7 @@ const NCCS* = 32 type - Termios* = object {.importc: "struct termios", header: "termios.h>", final, pure.} + Termios* = object {.importc: "struct termios", header: "", final, pure.} iflag*: Tcflag # input mode flags oflag*: Tcflag # output mode flags cflag*: Tcflag # control mode flags From 8f18c936c3e15c71141323c1cbdca757938bcc0a Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 11:25:58 +0100 Subject: [PATCH 027/250] Change termios proc capitalization --- lib/posix/termios.nim | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim index 94258772fb..2a44624764 100644 --- a/lib/posix/termios.nim +++ b/lib/posix/termios.nim @@ -204,61 +204,61 @@ const # `struct termios'. If VAL is _POSIX_VDISABLE, no character can match it. template CCEQ*(val, c: expr): expr = - ((c) == (val) and (val) != POSIX_VDISABLE) + c == val and val != POSIX_VDISABLE # Return the output baud rate stored in *TERMIOS_P. -proc cfgetospeed*(termios: ptr Termios): Speed {.importc: "cfgetospeed", +proc cfGetOspeed*(termios: ptr Termios): Speed {.importc: "cfgetospeed", header: "".} # Return the input baud rate stored in *TERMIOS_P. -proc cfgetispeed*(termios: ptr Termios): Speed {.importc: "cfgetispeed", +proc cfGetIspeed*(termios: ptr Termios): Speed {.importc: "cfgetispeed", header: "".} # Set the output baud rate stored in *TERMIOS_P to SPEED. -proc cfsetospeed*(termios: ptr Termios; speed: Speed): cint {. +proc cfSetOspeed*(termios: ptr Termios; speed: Speed): cint {. importc: "cfsetospeed", header: "".} # Set the input baud rate stored in *TERMIOS_P to SPEED. -proc cfsetispeed*(termios: ptr Termios; speed: Speed): cint {. +proc cfSetIspeed*(termios: ptr Termios; speed: Speed): cint {. importc: "cfsetispeed", header: "".} # Set both the input and output baud rates in *TERMIOS_OP to SPEED. -proc cfsetspeed*(termios: ptr Termios; speed: Speed): cint {. +proc cfSetSpeed*(termios: ptr Termios; speed: Speed): cint {. importc: "cfsetspeed", header: "".} # Put the state of FD into *TERMIOS_P. -proc tcgetattr*(fd: cint; termios: ptr Termios): cint {. +proc tcGetAttr*(fd: cint; termios: ptr Termios): cint {. importc: "tcgetattr", header: "".} # Set the state of FD to *TERMIOS_P. # Values for OPTIONAL_ACTIONS (TCSA*) are in . -proc tcsetattr*(fd: cint; optional_actions: cint; termios: ptr Termios): cint {. +proc tcSetAttr*(fd: cint; optional_actions: cint; termios: ptr Termios): cint {. importc: "tcsetattr", header: "".} # Set *TERMIOS_P to indicate raw mode. -proc cfmakeraw*(termios: ptr Termios) {.importc: "cfmakeraw", +proc cfMakeRaw*(termios: ptr Termios) {.importc: "cfmakeraw", header: "".} # Send zero bits on FD. -proc tcsendbreak*(fd: cint; duration: cint): cint {.importc: "tcsendbreak", +proc tcSendBreak*(fd: cint; duration: cint): cint {.importc: "tcsendbreak", header: "".} # Wait for pending output to be written on FD. # # This function is a cancellation point and therefore not marked with # . -proc tcdrain*(fd: cint): cint {.importc: "tcdrain", header: "".} +proc tcDrain*(fd: cint): cint {.importc: "tcdrain", header: "".} # Flush pending data on FD. # Values for QUEUE_SELECTOR (TC{I,O,IO}FLUSH) are in . -proc tcflush*(fd: cint; queue_selector: cint): cint {.importc: "tcflush", +proc tcFlush*(fd: cint; queue_selector: cint): cint {.importc: "tcflush", header: "".} # Suspend or restart transmission on FD. # Values for ACTION (TC[IO]{OFF,ON}) are in . -proc tcflow*(fd: cint; action: cint): cint {.importc: "tcflow", +proc tcFlow*(fd: cint; action: cint): cint {.importc: "tcflow", header: "".} # Get process group ID for session leader for controlling terminal FD. -proc tcgetsid*(fd: cint): TPid {.importc: "tcgetsid", header: "".} +proc tcGetSid*(fd: cint): TPid {.importc: "tcgetsid", header: "".} From 61e5f0dc51c42bd0a48db68bb5ba9f16e5d69404 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 4 Feb 2015 10:48:11 +0100 Subject: [PATCH 028/250] fixes #2061 --- koch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index bc7631bcc4..782a55e018 100644 --- a/koch.nim +++ b/koch.nim @@ -40,7 +40,7 @@ Options: --help, -h shows this help and quits Possible Commands: boot [options] bootstraps with given command line options - install [bindir] installs to given directory + install [bindir] installs to given directory; Unix only! clean cleans Nimrod project; removes generated files web [options] generates the website and the full documentation website [options] generates only the website From b5f1957588c37fc5cef6e26a708f643cc8d0fc70 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 4 Feb 2015 12:40:23 +0100 Subject: [PATCH 029/250] fixes #2057 --- compiler/semexprs.nim | 3 ++- compiler/sempass2.nim | 2 +- compiler/semstmts.nim | 13 +++++++++---- compiler/semtypes.nim | 28 ++++++++++++++-------------- tests/template/t2do.nim | 22 ++++++++++++++++++++++ 5 files changed, 48 insertions(+), 20 deletions(-) create mode 100644 tests/template/t2do.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index ab1b759945..5761e9e880 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2113,7 +2113,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkCurly: result = semSetConstr(c, n) of nkBracket: result = semArrayConstr(c, n, flags) of nkObjConstr: result = semObjConstr(c, n, flags) - of nkLambdaKinds: result = semLambda(c, n, flags) + of nkLambda: result = semLambda(c, n, flags) + of nkDo: result = semDo(c, n, flags) of nkDerefExpr: result = semDeref(c, n) of nkAddr: result = n diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index dcebf86acc..ede556a707 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -230,7 +230,7 @@ proc getEbase(): PType = proc excType(n: PNode): PType = # reraise is like raising E_Base: - let t = if n.kind == nkEmpty: getEbase() else: n.typ + let t = if n.kind == nkEmpty or n.typ.isNil: getEbase() else: n.typ result = skipTypes(t, skipPtrs) proc createRaise(n: PNode): PNode = diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 3fe3e40f09..b4790e4212 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -813,8 +813,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = # we have a list of implicit type parameters: n.sons[genericParamsPos] = gp else: - s.typ = newTypeS(tyProc, c) - rawAddSon(s.typ, nil) + s.typ = newProcType(c, n.info) if n.sons[pragmasPos].kind != nkEmpty: pragma(c, s, n.sons[pragmasPos], lambdaPragmas) s.options = gOptions @@ -839,6 +838,13 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = popOwner() result.typ = s.typ +proc semDo(c: PContext, n: PNode, flags: TExprFlags): PNode = + # 'do' without params produces a stmt: + if n[genericParamsPos].kind == nkEmpty and n[paramsPos].kind == nkEmpty: + result = semStmt(c, n[bodyPos]) + else: + result = semLambda(c, n, flags) + proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode = var n = n @@ -988,8 +994,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, # check for semantics again: # semParamList(c, n.sons[ParamsPos], nil, s) else: - s.typ = newTypeS(tyProc, c) - rawAddSon(s.typ, nil) + s.typ = newProcType(c, n.info) if n.sons[patternPos].kind != nkEmpty: n.sons[patternPos] = semPattern(c, n.sons[patternPos]) if s.kind in skIterators: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 8d16555932..7908742dbe 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -856,25 +856,25 @@ proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType = else: result = semTypeNode(c, n, nil) -proc semProcTypeNode(c: PContext, n, genericParams: PNode, - prev: PType, kind: TSymKind; isType=false): PType = - # for historical reasons (code grows) this is invoked for parameter - # lists too and then 'isType' is false. - var - res: PNode - cl: IntSet - checkMinSonsLen(n, 1) +proc newProcType(c: PContext; info: TLineInfo; prev: PType = nil): PType = result = newOrPrevType(tyProc, prev, c) result.callConv = lastOptionEntry(c).defaultCC - result.n = newNodeI(nkFormalParams, n.info) - if genericParams != nil and sonsLen(genericParams) == 0: - cl = initIntSet() + result.n = newNodeI(nkFormalParams, info) rawAddSon(result, nil) # return type # result.n[0] used to be `nkType`, but now it's `nkEffectList` because # the effects are now stored in there too ... this is a bit hacky, but as # usual we desperately try to save memory: - res = newNodeI(nkEffectList, n.info) - addSon(result.n, res) + addSon(result.n, newNodeI(nkEffectList, info)) + +proc semProcTypeNode(c: PContext, n, genericParams: PNode, + prev: PType, kind: TSymKind; isType=false): PType = + # for historical reasons (code grows) this is invoked for parameter + # lists too and then 'isType' is false. + var cl: IntSet + checkMinSonsLen(n, 1) + result = newProcType(c, n.info, prev) + if genericParams != nil and sonsLen(genericParams) == 0: + cl = initIntSet() var check = initIntSet() var counter = 0 for i in countup(1, n.len - 1): @@ -956,7 +956,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, # we don't need to change the return type to iter[T] if not r.isInlineIterator: r = newTypeWithSons(c, tyIter, @[r]) result.sons[0] = r - res.typ = r + result.n.typ = r if genericParams != nil: for n in genericParams: diff --git a/tests/template/t2do.nim b/tests/template/t2do.nim new file mode 100644 index 0000000000..b87e3328c2 --- /dev/null +++ b/tests/template/t2do.nim @@ -0,0 +1,22 @@ +discard """ + output: "8.0" +""" + +# bug #2057 + +proc mpf_get_d(x: int): float = float(x) +proc mpf_cmp_d(a: int; b: float): int = 0 + +template toFloatHelper(result: expr; tooSmall, tooLarge: stmt) {.immediate.} = + result = mpf_get_d(a) + if result == 0.0 and mpf_cmp_d(a,0.0) != 0: + tooSmall + if result == Inf: + tooLarge + +proc toFloat*(a: int): float = + toFloatHelper(result) + do: raise newException(ValueError, "number too small"): + raise newException(ValueError, "number too large") + +echo toFloat(8) From 12ad32e951374c31ff951c8023ef683f454277bc Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 13:01:11 +0100 Subject: [PATCH 030/250] Typos --- compiler/msgs.nim | 2 +- compiler/nimconf.nim | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 35a1217692..a80f4a4982 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -460,7 +460,7 @@ type TLineInfo*{.final.} = object # This is designed to be as small as possible, # because it is used - # in syntax nodes. We safe space here by using + # in syntax nodes. We save space here by using # two int16 and an int32. # On 64 bit and on 32 bit systems this is # only 8 bytes. diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index bcf9b53596..cd1fa784ff 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -14,7 +14,7 @@ import options, idents, wordrecg # ---------------- configuration file parser ----------------------------- -# we use Nim's scanner here to safe space and work +# we use Nim's scanner here to save space and work proc ppGetTok(L: var TLexer, tok: var TToken) = # simple filter @@ -157,7 +157,7 @@ proc checkSymbol(L: TLexer, tok: TToken) = proc parseAssignment(L: var TLexer, tok: var TToken) = if tok.ident.id == getIdent("-").id or tok.ident.id == getIdent("--").id: confTok(L, tok) # skip unnecessary prefix - var info = getLineInfo(L, tok) # safe for later in case of an error + var info = getLineInfo(L, tok) # save for later in case of an error checkSymbol(L, tok) var s = tokToStr(tok) confTok(L, tok) # skip symbol From 2b9d7068cbb38fd9281dde00936eac6d48fe91b1 Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 13:01:21 +0100 Subject: [PATCH 031/250] Add support for nimcfg and warning for nimrod.cfg --- compiler/nimconf.nim | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index cd1fa784ff..5304dc2659 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -246,6 +246,11 @@ proc loadConfigs*(cfg: string) = if gProjectName.len != 0: # new project wide config file: - let projectConfig = changeFileExt(gProjectFull, "nim.cfg") - if fileExists(projectConfig): readConfigFile(projectConfig) - else: readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg")) + var projectConfig = changeFileExt(gProjectFull, "nimcfg") + if not fileExists(projectConfig): + projectConfig = changeFileExt(gProjectFull, "nim.cfg") + if not fileExists(projectConfig): + projectConfig = changeFileExt(gProjectFull, "nimrod.cfg") + if fileExists(projectConfig): + rawMessage(warnDeprecated, projectConfig) + readConfigFile(projectConfig) From 8640efcd4053353fe97da1a1950ad1c370565a4b Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 14:10:58 +0100 Subject: [PATCH 032/250] Document terminal.getch --- lib/pure/terminal.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index b0c822c57d..e0e2aa247f 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -365,6 +365,8 @@ macro styledEcho*(m: varargs[expr]): stmt = result.add(newCall(bindSym"resetAttributes")) proc getch*(): char = + ## Read a single character from the terminal, blocking until it is entered. + ## The character is not printed to the terminal. when defined(windows): result = winGetch().char else: From 5b26c1360b5f56368f533aa26690431eb5ae5f7c Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 19:18:09 +0100 Subject: [PATCH 033/250] Rename termios template CCEQ to cceq --- lib/posix/termios.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim index 2a44624764..830e8a2076 100644 --- a/lib/posix/termios.nim +++ b/lib/posix/termios.nim @@ -203,7 +203,7 @@ const # Compare a character C to a value VAL from the `cc' array in a # `struct termios'. If VAL is _POSIX_VDISABLE, no character can match it. -template CCEQ*(val, c: expr): expr = +template cceq*(val, c: expr): expr = c == val and val != POSIX_VDISABLE # Return the output baud rate stored in *TERMIOS_P. From f3922bc4e5f2d01e8b594fbe30f24b2619bec993 Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 19:27:56 +0100 Subject: [PATCH 034/250] Fix documentation and toJson signature --- lib/pure/json.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 1b4b135b63..0dc7991d10 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -644,7 +644,7 @@ proc `%`*(elements: openArray[JsonNode]): JsonNode = newSeq(result.elems, elements.len) for i, p in pairs(elements): result.elems[i] = p -proc toJson(x: expr): expr {.compiletime.} = +proc toJson(x: PNimrodNode): PNimrodNode {.compiletime.} = case x.kind of nnkBracket: result = newNimNode(nnkBracket) @@ -663,7 +663,7 @@ proc toJson(x: expr): expr {.compiletime.} = result = prefix(result, "%") macro `%*`*(x: expr): expr = - ## Convert an expression to a JsonParser directly, without having to specify + ## Convert an expression to a JsonNode directly, without having to specify ## `%` for every element. result = toJson(x) From d91368c8d0602b343546e16c26c8ad297d48d188 Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 19:47:58 +0100 Subject: [PATCH 035/250] Add test for #1836 --- tests/iter/tconcat.nim | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/iter/tconcat.nim diff --git a/tests/iter/tconcat.nim b/tests/iter/tconcat.nim new file mode 100644 index 0000000000..c0dab57190 --- /dev/null +++ b/tests/iter/tconcat.nim @@ -0,0 +1,17 @@ +discard """ + output: '''DabcD''' +""" + +proc toIter*[T](s: Slice[T]): iterator: T = + iterator it: T {.closure.} = + for x in s.a..s.b: + yield x + return it + +iterator concat*[T](its: varargs[T, toIter]): auto = + for i in its: + for x in i(): + yield x + +for i in concat(1..4, 20..23): + echo i From 69b794cd7dcfe553ab19ad78630d0b237c096050 Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 19:53:50 +0100 Subject: [PATCH 036/250] Add test for #1259 --- tests/template/tscope.nim | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/template/tscope.nim diff --git a/tests/template/tscope.nim b/tests/template/tscope.nim new file mode 100644 index 0000000000..2d5841af39 --- /dev/null +++ b/tests/template/tscope.nim @@ -0,0 +1,12 @@ +discard """ + errormsg: "redefinition of 'x'" +""" + +var x = 1 +template quantity(): stmt {.immediate.} = + # Causes internal error in compiler/sem.nim + proc unit*(x = 1.0): float = 12 + # Throws the correct error: redefinition of 'x' + #proc unit*(y = 1.0): float = 12 +quantity() +var x = 2 From 402ada8f1d84c9a3dbdbb1bc73d8c512e97b04c3 Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 20:00:28 +0100 Subject: [PATCH 037/250] Add test for #1877 --- tests/static/tmatrix.nim | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/static/tmatrix.nim diff --git a/tests/static/tmatrix.nim b/tests/static/tmatrix.nim new file mode 100644 index 0000000000..d8cc5d14db --- /dev/null +++ b/tests/static/tmatrix.nim @@ -0,0 +1,19 @@ +discard """ + output: "111" +""" + +type Matrix[M,N: static[int]] = array[M, array[N, float]] + +let a = [[1.0, 1.0, 1.0, 1.0], + [2.0, 4.0, 8.0, 16.0], + [3.0, 9.0, 27.0, 81.0], + [4.0, 16.0, 64.0, 256.0]] + +proc `$`(m: Matrix): string = + result = "" + +proc `*`[M,N,M2,N2](a: Matrix[M,N2]; b: Matrix[M2,N]): Matrix[M,N] = + discard + +echo a * a + From c3989f64ef9fb0bfe54dad576144536259e8d03c Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 20:08:26 +0100 Subject: [PATCH 038/250] Add test for #1459 --- tests/cpp/ttypeinfo.nim | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 tests/cpp/ttypeinfo.nim diff --git a/tests/cpp/ttypeinfo.nim b/tests/cpp/ttypeinfo.nim new file mode 100644 index 0000000000..e72883dbf2 --- /dev/null +++ b/tests/cpp/ttypeinfo.nim @@ -0,0 +1,5 @@ +discard """ + cmd: "nim cpp $target" +""" + +import typeinfo From 19993d73ed6e4b5ddfea704897bb9b20e72895dd Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 20:10:50 +0100 Subject: [PATCH 039/250] Add test for #1460 --- tests/cpp/trawsockets.nim | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 tests/cpp/trawsockets.nim diff --git a/tests/cpp/trawsockets.nim b/tests/cpp/trawsockets.nim new file mode 100644 index 0000000000..d034245d00 --- /dev/null +++ b/tests/cpp/trawsockets.nim @@ -0,0 +1,5 @@ +discard """ + cmd: "nim cpp $target" +""" + +import rawsockets From 1b91b3a2a516479b16288c0b8b02ef4a84549f0e Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 20:10:57 +0100 Subject: [PATCH 040/250] Disable rodfiles tests for now --- tests/testament/categories.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index 5cd5c15457..54e9626932 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -330,8 +330,9 @@ proc `&?.`(a, b: string): string = proc processCategory(r: var TResults, cat: Category, options: string) = case cat.string.normalize of "rodfiles": - compileRodFiles(r, cat, options) - runRodFiles(r, cat, options) + discard # Disabled for now + #compileRodFiles(r, cat, options) + #runRodFiles(r, cat, options) of "js": # XXX JS doesn't need to be special anymore jsTests(r, cat, options) From e0ae9f524840cade68f6293a2b2731b7b66c9649 Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 20:22:58 +0100 Subject: [PATCH 041/250] Clean up tests/stdlib 2 tests still fail: - tircbot would need a benign pragma because of the locks - tgetfileinfo uses os.getFileInfo() on nil, which segfaults instead of throwing an exception as the tester expects --- tests/stdlib/tdialogs.nim | 8 +++--- tests/stdlib/tgetfileinfo.nim | 9 ++++-- tests/stdlib/tircbot.nim | 53 ++++++++++++++++++----------------- 3 files changed, 37 insertions(+), 33 deletions(-) diff --git a/tests/stdlib/tdialogs.nim b/tests/stdlib/tdialogs.nim index d161a976de..f0203d3197 100644 --- a/tests/stdlib/tdialogs.nim +++ b/tests/stdlib/tdialogs.nim @@ -4,7 +4,7 @@ import dialogs, gtk2 gtk2.nimrod_init() -var x = ChooseFilesToOpen(nil) +var x = chooseFilesToOpen(nil) for a in items(x): writeln(stdout, a) @@ -12,6 +12,6 @@ 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)) +writeln(stdout, chooseFileToOpen(nil)) +writeln(stdout, chooseFileToSave(nil)) +writeln(stdout, chooseDir(nil)) diff --git a/tests/stdlib/tgetfileinfo.nim b/tests/stdlib/tgetfileinfo.nim index 49a0190619..c8e496cc1e 100644 --- a/tests/stdlib/tgetfileinfo.nim +++ b/tests/stdlib/tgetfileinfo.nim @@ -32,7 +32,7 @@ proc caseOneAndTwo(followLink: bool) = try: discard getFileInfo(getAppFilename(), followLink) #echo("String : Existing File : Symlink $# : Success" % $followLink) - except EOS: + except OSError: echo("String : Existing File : Symlink $# : Failure" % $followLink) proc caseThreeAndFour(followLink: bool) = @@ -40,7 +40,8 @@ proc caseThreeAndFour(followLink: bool) = try: discard getFileInfo(invalidName, true) echo("String : Non-existing File : Symlink $# : Failure" % $followLink) - except EOS: + except OSError: + discard #echo("String : Non-existing File : Symlink $# : Success" % $followLink) proc testGetFileInfo = @@ -82,12 +83,14 @@ proc testGetFileInfo = discard getFileInfo(testFile) echo("Handle : Invalid File : Failure") except EIO, EOS: + discard #echo("Handle : Invalid File : Success") try: discard getFileInfo(testHandle) echo("Handle : Invalid File : Failure") except EIO, EOS: + discard #echo("Handle : Invalid File : Success") -testGetFileInfo() \ No newline at end of file +testGetFileInfo() diff --git a/tests/stdlib/tircbot.nim b/tests/stdlib/tircbot.nim index b91300762a..6b209dce3e 100644 --- a/tests/stdlib/tircbot.nim +++ b/tests/stdlib/tircbot.nim @@ -2,7 +2,7 @@ import irc, sockets, asyncio, json, os, strutils, times, redis type TDb* = object - r*: TRedis + r*: Redis lastPing: float TBuildResult* = enum @@ -15,20 +15,20 @@ type TCommit* = object commitMsg*, username*, hash*: string - date*: TTime + date*: Time TPlatform* = object buildResult*: TBuildResult testResult*: TTestResult failReason*, platform*: string - total*, passed*, skipped*, failed*: biggestInt + total*, passed*, skipped*, failed*: BiggestInt csources*: bool const listName = "commits" - failOnExisting = False + failOnExisting = false -proc open*(host = "localhost", port: TPort): TDb = +proc open*(host = "localhost", port: Port): TDb = result.r = redis.open(host, port) result.lastPing = epochTime() @@ -80,7 +80,7 @@ proc getCommits*(database: TDb, for key, value in database.r.hPairs(c): case normalize(key) of "commitmsg": commit.commitMsg = value - of "date": commit.date = TTime(parseInt(value)) + of "date": commit.date = Time(parseInt(value)) of "username": commit.username = value else: echo(key) @@ -157,21 +157,21 @@ proc `[]`*(p: seq[TPlatform], name: string): TPlatform = for platform in items(p): if platform.platform == name: return platform - raise newException(EInvalidValue, name & " platforms not found in commits.") + raise newException(ValueError, name & " platforms not found in commits.") proc contains*(p: seq[TPlatform], s: string): bool = for i in items(p): if i.platform == s: - return True + return true type PState = ref TState - TState = object of TObject - dispatcher: PDispatcher - sock: PAsyncSocket + TState = object of RootObj + dispatcher: Dispatcher + sock: AsyncSocket ircClient: PAsyncIRC - hubPort: TPort + hubPort: Port database: TDb dbConnected: bool @@ -181,7 +181,7 @@ type TSeen = object nick: string channel: string - timestamp: TTime + timestamp: Time case kind*: TSeenType of PSeenJoin: nil of PSeenPart, PSeenQuit, PSeenMsg: @@ -218,11 +218,12 @@ proc getSeen(d: TDb, nick: string, s: var TSeen): bool = for key, value in d.r.hPairs("seen:" & nick): case normalize(key) of "type": + discard #s.kind = value.parseInt.TSeenType of "channel": s.channel = value of "timestamp": - s.timestamp = TTime(value.parseInt) + s.timestamp = Time(value.parseInt) of "msg": s.msg = value of "newnick": @@ -235,7 +236,7 @@ template createSeen(typ: TSeenType, n, c: string): stmt {.immediate, dirty.} = seenNick.channel = c seenNick.timestamp = getTime() -proc parseReply(line: string, expect: string): Bool = +proc parseReply(line: string, expect: string): bool = var jsonDoc = parseJson(line) return jsonDoc["reply"].str == expect @@ -272,14 +273,14 @@ proc handleWebMessage(state: PState, line: string) = message.add(limitCommitMsg(commit["message"].str)) # Send message to #nim. - state.ircClient.privmsg(joinChans[0], message) + discard state.ircClient.privmsg(joinChans[0], message) elif json.hasKey("redisinfo"): assert json["redisinfo"].hasKey("port") #let redisPort = json["redisinfo"]["port"].num state.dbConnected = true proc hubConnect(state: PState) -proc handleConnect(s: PAsyncSocket, state: PState) = +proc handleConnect(s: AsyncSocket, state: PState) = try: # Send greeting var obj = newJObject() @@ -295,7 +296,7 @@ proc handleConnect(s: PAsyncSocket, state: PState) = doAssert parseReply(line, "OK") echo("The hub accepted me!") else: - raise newException(EInvalidValue, + raise newException(ValueError, "Hub didn't accept me. Waited 1.5 seconds.") # ask for the redis info @@ -303,35 +304,35 @@ proc handleConnect(s: PAsyncSocket, state: PState) = riobj["do"] = newJString("redisinfo") state.sock.send($riobj & "\c\L") - except EOS: + except OsError: echo(getCurrentExceptionMsg()) s.close() echo("Waiting 5 seconds...") sleep(5000) state.hubConnect() -proc handleRead(s: PAsyncSocket, state: PState) = +proc handleRead(s: AsyncSocket, state: PState) = var line = "" if state.sock.recvLine(line): if line != "": # Handle the message state.handleWebMessage(line) else: - echo("Disconnected from hub: ", OSErrorMsg()) + echo("Disconnected from hub: ", osErrorMsg()) s.close() echo("Reconnecting...") state.hubConnect() else: - echo(OSErrorMsg()) + echo(osErrorMsg()) proc hubConnect(state: PState) = - state.sock = AsyncSocket() + state.sock = asyncSocket() state.sock.connect("127.0.0.1", state.hubPort) state.sock.handleConnect = - proc (s: PAsyncSocket) = + proc (s: AsyncSocket) = handleConnect(s, state) state.sock.handleRead = - proc (s: PAsyncSocket) = + proc (s: AsyncSocket) = handleRead(s, state) state.dispatcher.register(state.sock) @@ -426,7 +427,7 @@ proc handleIrc(irc: PAsyncIRC, event: TIRCEvent, state: PState) = else: discard # TODO: ? -proc open(port: TPort = TPort(5123)): PState = +proc open(port: Port = Port(5123)): PState = var res: PState new(res) res.dispatcher = newDispatcher() From 4fbf47ca5eef09060038eeea0d945b5d7afdd2f2 Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 20:30:09 +0100 Subject: [PATCH 042/250] Clean up tests/assert 1 test still fails: - tunittests uses utemplates, which seems broken. not sure what it's supposed to do --- tests/assert/tfailedassert.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/assert/tfailedassert.nim b/tests/assert/tfailedassert.nim index d03d3136bd..8766321bf6 100644 --- a/tests/assert/tfailedassert.nim +++ b/tests/assert/tfailedassert.nim @@ -3,7 +3,7 @@ discard """ WARNING: false first assertion from bar ERROR: false second assertion from bar -1 -tfailedassert.nim:27 false assertion from foo +tests/assert/tfailedassert.nim:27 false assertion from foo ''' """ From be33e55518705d8368921366e87c2c0c30f5ab0d Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 20:32:54 +0100 Subject: [PATCH 043/250] Clean up tests/bind --- tests/bind/tnicerrorforsymchoice.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bind/tnicerrorforsymchoice.nim b/tests/bind/tnicerrorforsymchoice.nim index e1ff090dd8..bf6d92927f 100644 --- a/tests/bind/tnicerrorforsymchoice.nim +++ b/tests/bind/tnicerrorforsymchoice.nim @@ -1,6 +1,6 @@ discard """ line: 18 - errormsg: "type mismatch: got (proc (TScgi) | proc (AsyncSocket, StringTableRef, string){.gcsafe.})" + errormsg: "type mismatch: got (proc (TScgi) | proc (AsyncSocket, StringTableRef, string)" """ #bug #442 From c58573b34a058ed82f3c3673a0050b8545b93b6c Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 20:41:27 +0100 Subject: [PATCH 044/250] Fix name of generated C file in tester - Makes tests/ccgbugs/tmissingvolatile work again --- tests/testament/tester.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim index 865ba9c757..45643be10e 100644 --- a/tests/testament/tester.nim +++ b/tests/testament/tester.nim @@ -134,7 +134,7 @@ proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest) = proc generatedFile(path, name: string, target: TTarget): string = let ext = targetToExt[target] result = path / "nimcache" / - (if target == targetJS: path.splitPath.tail & "_" else: "") & + (if target == targetJS: path.splitPath.tail & "_" else: "compiler_") & name.changeFileExt(ext) proc codegenCheck(test: TTest, check: string, given: var TSpec) = From 8a7f405eeae2334ed47f0d4d8e86d5fc81b8c40a Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 20:42:37 +0100 Subject: [PATCH 045/250] Clear up tests/clearmsg --- tests/clearmsg/ta.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/clearmsg/ta.nim b/tests/clearmsg/ta.nim index b21522d127..38449c319e 100644 --- a/tests/clearmsg/ta.nim +++ b/tests/clearmsg/ta.nim @@ -1,5 +1,5 @@ discard """ - errormsg: 'type mismatch: got (mc.typ)' + errormsg: "type mismatch: got (mc.typ)" line: 12 """ From d4c32102d829ffdbca117da27d2bbe876b4ad10f Mon Sep 17 00:00:00 2001 From: Simon Hafner Date: Wed, 4 Feb 2015 14:15:52 -0600 Subject: [PATCH 046/250] use dynamic message destination --- compiler/msgs.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 8d1a18b444..59789df6c3 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -718,7 +718,7 @@ proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) = if stackTraceAvailable(): writeStackTrace() else: - stderr.writeln("No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp c ") + msgWriteln("No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp c ") quit 1 if msg >= fatalMin and msg <= fatalMax: From 546acfaf4e9ed8ea68d45e15e1942b6c7f9849b6 Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 21:20:01 +0100 Subject: [PATCH 047/250] Clean up tests/effects --- tests/effects/teffects1.nim | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/effects/teffects1.nim b/tests/effects/teffects1.nim index 27f89f5fa1..ea1ea7b211 100644 --- a/tests/effects/teffects1.nim +++ b/tests/effects/teffects1.nim @@ -1,5 +1,4 @@ discard """ - line: 2166 file: "system.nim" errormsg: "can raise an unlisted exception: ref IOError" """ From 0b4557b2ce6cfbf05faa2f68317983e3b5b32a84 Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 21:40:33 +0100 Subject: [PATCH 048/250] Clean up tests/iter --- tests/iter/tconcat.nim | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/iter/tconcat.nim b/tests/iter/tconcat.nim index c0dab57190..477ac5e268 100644 --- a/tests/iter/tconcat.nim +++ b/tests/iter/tconcat.nim @@ -1,5 +1,12 @@ discard """ - output: '''DabcD''' + output: '''1 +2 +3 +4 +20 +21 +22 +23''' """ proc toIter*[T](s: Slice[T]): iterator: T = From 416456cefef9120019924067adeb814b0ceaaf79 Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 21:44:25 +0100 Subject: [PATCH 049/250] Try to fix unittest for JS backend, still not working --- lib/pure/unittest.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 8dc9fe0d4b..f4e42ee63f 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -39,6 +39,7 @@ when declared(stdout): when not defined(ECMAScript): import terminal + system.addQuitProc(resetAttributes) type TestStatus* = enum OK, FAILED @@ -234,5 +235,3 @@ if envOutLvl.len > 0: if $opt == envOutLvl: outputLevel = opt break - -system.addQuitProc(resetAttributes) From 1c34f30bbb4e6c12e48814e7524e7e5faba72970 Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 21:56:45 +0100 Subject: [PATCH 050/250] Clean up tests/manyloc named_argument_bug still fails --- .../dependencies/chipmunk/chipmunk.nim | 70 +++++++++---------- .../keineschweine/dependencies/enet/enet.nim | 2 +- .../dependencies/genpacket/genpacket_enet.nim | 11 +-- .../keineschweine/dependencies/sfml/sfml.nim | 22 +++--- .../dependencies/sfml/sfml_audio.nim | 6 +- .../keineschweine/enet_server/enet_client.nim | 1 + tests/manyloc/keineschweine/keineschweine.nim | 24 +++---- .../keineschweine/lib/game_objects.nim | 2 +- tests/manyloc/keineschweine/lib/gl.nim | 64 ++++++++--------- .../manyloc/keineschweine/lib/map_filter.nim | 10 +-- tests/manyloc/keineschweine/lib/sg_assets.nim | 8 +-- .../manyloc/keineschweine/lib/sg_packets.nim | 6 +- tests/manyloc/keineschweine/lib/vehicles.nim | 8 +-- 13 files changed, 113 insertions(+), 121 deletions(-) diff --git a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim index d079a2e72d..08f1dad505 100644 --- a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim +++ b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim @@ -74,7 +74,7 @@ type contacts*: PContact stamp*: TTimestamp handler*: PCollisionHandler - swappedColl*: bool32 + swappedColl*: Bool32 state*: TArbiterState PCollisionHandler* = ptr TCollisionHandler TCollisionHandler*{.pf.} = object @@ -108,7 +108,7 @@ type #/ Collision begin event function callback type. #/ Returning false from a begin callback causes the collision to be ignored until #/ the the separate callback is called when the objects stop colliding. - TCollisionBeginFunc* = proc (arb: PArbiter; space: PSpace; data: pointer): Bool{. + TCollisionBeginFunc* = proc (arb: PArbiter; space: PSpace; data: pointer): bool{. cdecl.} #/ Collision pre-solve event function callback type. #/ Returning false from a pre-step callback causes the collision to be ignored until the next step. @@ -142,14 +142,14 @@ type PSpatialIndex = ptr TSpatialIndex TSpatialIndex{.pf.} = object klass: PSpatialIndexClass - bbfunc: TSpatialIndexBBFunc + bbfun: TSpatialIndexBBFunc staticIndex: PSpatialIndex dynamicIndex: PSpatialIndex TSpatialIndexDestroyImpl* = proc (index: PSpatialIndex){.cdecl.} TSpatialIndexCountImpl* = proc (index: PSpatialIndex): cint{.cdecl.} TSpatialIndexEachImpl* = proc (index: PSpatialIndex; - func: TSpatialIndexIteratorFunc; data: pointer){. + fun: TSpatialIndexIteratorFunc; data: pointer){. cdecl.} TSpatialIndexContainsImpl* = proc (index: PSpatialIndex; obj: pointer; hashid: THashValue): Bool32 {.cdecl.} @@ -161,15 +161,15 @@ type TSpatialIndexReindexObjectImpl* = proc (index: PSpatialIndex; obj: pointer; hashid: THashValue){.cdecl.} TSpatialIndexReindexQueryImpl* = proc (index: PSpatialIndex; - func: TSpatialIndexQueryFunc; data: pointer){.cdecl.} + fun: TSpatialIndexQueryFunc; data: pointer){.cdecl.} TSpatialIndexPointQueryImpl* = proc (index: PSpatialIndex; point: TVector; - func: TSpatialIndexQueryFunc; + fun: TSpatialIndexQueryFunc; data: pointer){.cdecl.} TSpatialIndexSegmentQueryImpl* = proc (index: PSpatialIndex; obj: pointer; - a: TVector; b: TVector; t_exit: CpFloat; func: TSpatialIndexSegmentQueryFunc; + a: TVector; b: TVector; t_exit: CpFloat; fun: TSpatialIndexSegmentQueryFunc; data: pointer){.cdecl.} TSpatialIndexQueryImpl* = proc (index: PSpatialIndex; obj: pointer; - bb: TBB; func: TSpatialIndexQueryFunc; + bb: TBB; fun: TSpatialIndexQueryFunc; data: pointer){.cdecl.} PSpatialIndexClass* = ptr TSpatialIndexClass TSpatialIndexClass*{.pf.} = object @@ -286,7 +286,7 @@ type CP_CIRCLE_SHAPE, CP_SEGMENT_SHAPE, CP_POLY_SHAPE, CP_NUM_SHAPES TShapeCacheDataImpl* = proc (shape: PShape; p: TVector; rot: TVector): TBB{.cdecl.} TShapeDestroyImpl* = proc (shape: PShape){.cdecl.} - TShapePointQueryImpl* = proc (shape: PShape; p: TVector): bool32 {.cdecl.} + TShapePointQueryImpl* = proc (shape: PShape; p: TVector): Bool32 {.cdecl.} TShapeSegmentQueryImpl* = proc (shape: PShape; a: TVector; b: TVector; info: PSegmentQueryInfo){.cdecl.} PShapeClass* = ptr TShapeClass @@ -427,7 +427,7 @@ defGetter(PSpace, CpFloat, currDt, CurrentTimeStep) #/ returns true from inside a callback and objects cannot be added/removed. -proc isLocked*(space: PSpace): Bool{.inline.} = +proc isLocked*(space: PSpace): bool{.inline.} = result = space.locked.bool #/ Set a default collision handler for this space. @@ -478,24 +478,24 @@ proc removeBody*(space: PSpace; body: PBody){. proc RemoveConstraint*(space: PSpace; constraint: PConstraint){. cdecl, importc: "cpSpaceRemoveConstraint", dynlib: Lib.} #/ Test if a collision shape has been added to the space. -proc containsShape*(space: PSpace; shape: PShape): Bool{. +proc containsShape*(space: PSpace; shape: PShape): bool{. cdecl, importc: "cpSpaceContainsShape", dynlib: Lib.} #/ Test if a rigid body has been added to the space. -proc containsBody*(space: PSpace; body: PBody): Bool{. +proc containsBody*(space: PSpace; body: PBody): bool{. cdecl, importc: "cpSpaceContainsBody", dynlib: Lib.} #/ Test if a constraint has been added to the space. -proc containsConstraint*(space: PSpace; constraint: PConstraint): Bool{. +proc containsConstraint*(space: PSpace; constraint: PConstraint): bool{. cdecl, importc: "cpSpaceContainsConstraint", dynlib: Lib.} #/ Schedule a post-step callback to be called when cpSpaceStep() finishes. #/ @c obj is used a key, you can only register one callback per unique value for @c obj -proc addPostStepCallback*(space: PSpace; func: TPostStepFunc; +proc addPostStepCallback*(space: PSpace; fun: TPostStepFunc; obj: pointer; data: pointer){. cdecl, importc: "cpSpaceAddPostStepCallback", dynlib: Lib.} #/ Query the space at a point and call @c func for each shape found. proc pointQuery*(space: PSpace; point: TVector; layers: TLayers; - group: TGroup; func: TSpacePointQueryFunc; data: pointer){. + group: TGroup; fun: TSpacePointQueryFunc; data: pointer){. cdecl, importc: "cpSpacePointQuery", dynlib: Lib.} #/ Query the space at a point and return the first shape found. Returns NULL if no shapes were found. @@ -506,7 +506,7 @@ proc pointQueryFirst*(space: PSpace; point: TVector; layers: TLayers; #/ Perform a directed line segment query (like a raycast) against the space calling @c func for each shape intersected. proc segmentQuery*(space: PSpace; start: TVector; to: TVector; layers: TLayers; group: TGroup; - func: TSpaceSegmentQueryFunc; data: pointer){. + fun: TSpaceSegmentQueryFunc; data: pointer){. cdecl, importc: "cpSpaceSegmentQuery", dynlib: Lib.} #/ Perform a directed line segment query (like a raycast) against the space and return the first shape hit. Returns NULL if no shapes were hit. proc segmentQueryFirst*(space: PSpace; start: TVector; to: TVector; @@ -517,26 +517,26 @@ proc segmentQueryFirst*(space: PSpace; start: TVector; to: TVector; #/ Perform a fast rectangle query on the space calling @c func for each shape found. #/ Only the shape's bounding boxes are checked for overlap, not their full shape. proc BBQuery*(space: PSpace; bb: TBB; layers: TLayers; group: TGroup; - func: TSpaceBBQueryFunc; data: pointer){. + fun: TSpaceBBQueryFunc; data: pointer){. cdecl, importc: "cpSpaceBBQuery", dynlib: Lib.} #/ Query a space for any shapes overlapping the given shape and call @c func for each shape found. -proc shapeQuery*(space: PSpace; shape: PShape; func: TSpaceShapeQueryFunc; data: pointer): Bool {. +proc shapeQuery*(space: PSpace; shape: PShape; fun: TSpaceShapeQueryFunc; data: pointer): bool {. cdecl, importc: "cpSpaceShapeQuery", dynlib: Lib.} #/ Call cpBodyActivate() for any shape that is overlaps the given shape. proc activateShapesTouchingShape*(space: PSpace; shape: PShape){. cdecl, importc: "cpSpaceActivateShapesTouchingShape", dynlib: Lib.} #/ Call @c func for each body in the space. -proc eachBody*(space: PSpace; func: TSpaceBodyIteratorFunc; data: pointer){. +proc eachBody*(space: PSpace; fun: TSpaceBodyIteratorFunc; data: pointer){. cdecl, importc: "cpSpaceEachBody", dynlib: Lib.} #/ Call @c func for each shape in the space. -proc eachShape*(space: PSpace; func: TSpaceShapeIteratorFunc; +proc eachShape*(space: PSpace; fun: TSpaceShapeIteratorFunc; data: pointer){. cdecl, importc: "cpSpaceEachShape", dynlib: Lib.} #/ Call @c func for each shape in the space. -proc eachConstraint*(space: PSpace; func: TSpaceConstraintIteratorFunc; +proc eachConstraint*(space: PSpace; fun: TSpaceConstraintIteratorFunc; data: pointer){. cdecl, importc: "cpSpaceEachConstraint", dynlib: Lib.} #/ Update the collision detection info for the static shapes in the space. @@ -674,7 +674,7 @@ proc dist*(v1, v2: TVector): CpFloat {.inline.} = proc distsq*(v1, v2: TVector): CpFloat {.inline.} = result = (v1 - v2).lenSq #vlengthsq(vsub(v1, v2)) #/ Returns true if the distance between v1 and v2 is less than dist. -proc near*(v1, v2: TVector; dist: CpFloat): Bool{.inline.} = +proc near*(v1, v2: TVector; dist: CpFloat): bool{.inline.} = result = v1.distSq(v2) < dist * dist @@ -706,13 +706,13 @@ proc Sleep*(body: PBody){.importc: "cpBodySleep", dynlib: Lib.} proc SleepWithGroup*(body: PBody; group: PBody){. importc: "cpBodySleepWithGroup", dynlib: Lib.} #/ Returns true if the body is sleeping. -proc isSleeping*(body: PBody): Bool {.inline.} = +proc isSleeping*(body: PBody): bool {.inline.} = return body.node.root != nil #/ Returns true if the body is static. proc isStatic*(body: PBody): bool {.inline.} = return body.node.idleTime == CpInfinity #/ Returns true if the body has not been added to a space. -proc isRogue*(body: PBody): Bool {.inline.} = +proc isRogue*(body: PBody): bool {.inline.} = return body.space == nil # #define CP_DefineBodyStructGetter(type, member, name) \ @@ -808,15 +808,15 @@ proc kineticEnergy*(body: PBOdy): CpFloat = result = (body.v.dot(body.v) * body.m) + (body.w * body.w * body.i) #/ Call @c func once for each shape attached to @c body and added to the space. -proc eachShape*(body: PBody; func: TBodyShapeIteratorFunc; +proc eachShape*(body: PBody; fun: TBodyShapeIteratorFunc; data: pointer){. cdecl, importc: "cpBodyEachShape", dynlib: Lib.} #/ Call @c func once for each constraint attached to @c body and added to the space. -proc eachConstraint*(body: PBody; func: TBodyConstraintIteratorFunc; +proc eachConstraint*(body: PBody; fun: TBodyConstraintIteratorFunc; data: pointer) {. cdecl, importc: "cpBodyEachConstraint", dynlib: Lib.} #/ Call @c func once for each arbiter that is currently active on the body. -proc eachArbiter*(body: PBody; func: TBodyArbiterIteratorFunc; +proc eachArbiter*(body: PBody; fun: TBodyArbiterIteratorFunc; data: pointer){. cdecl, importc: "cpBodyEachArbiter", dynlib: Lib.} #/ Allocate a spatial hash. @@ -824,10 +824,10 @@ proc SpaceHashAlloc*(): PSpaceHash{. cdecl, importc: "cpSpaceHashAlloc", dynlib: Lib.} #/ Initialize a spatial hash. proc SpaceHashInit*(hash: PSpaceHash; celldim: CpFloat; numcells: cint; - bbfunc: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{. + bbfun: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{. cdecl, importc: "cpSpaceHashInit", dynlib: Lib.} #/ Allocate and initialize a spatial hash. -proc SpaceHashNew*(celldim: CpFloat; cells: cint; bbfunc: TSpatialIndexBBFunc; +proc SpaceHashNew*(celldim: CpFloat; cells: cint; bbfun: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{. cdecl, importc: "cpSpaceHashNew", dynlib: Lib.} #/ Change the cell dimensions and table size of the spatial hash to tune it. @@ -842,18 +842,18 @@ proc SpaceHashResize*(hash: PSpaceHash; celldim: CpFloat; numcells: cint){. #/ Allocate a bounding box tree. proc BBTreeAlloc*(): PBBTree{.cdecl, importc: "cpBBTreeAlloc", dynlib: Lib.} #/ Initialize a bounding box tree. -proc BBTreeInit*(tree: PBBTree; bbfunc: TSpatialIndexBBFunc; +proc BBTreeInit*(tree: PBBTree; bbfun: TSpatialIndexBBFunc; staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{.cdecl, importc: "cpBBTreeInit", dynlib: Lib.} #/ Allocate and initialize a bounding box tree. -proc BBTreeNew*(bbfunc: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{. +proc BBTreeNew*(bbfun: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{. cdecl, importc: "cpBBTreeNew", dynlib: Lib.} #/ Perform a static top down optimization of the tree. proc BBTreeOptimize*(index: PSpatialIndex){. cdecl, importc: "cpBBTreeOptimize", dynlib: Lib.} #/ Set the velocity function for the bounding box tree to enable temporal coherence. -proc BBTreeSetVelocityFunc*(index: PSpatialIndex; func: TBBTreeVelocityFunc){. +proc BBTreeSetVelocityFunc*(index: PSpatialIndex; fun: TBBTreeVelocityFunc){. cdecl, importc: "cpBBTreeSetVelocityFunc", dynlib: Lib.} #MARK: Single Axis Sweep @@ -864,12 +864,12 @@ proc Sweep1DAlloc*(): ptr TSweep1D{.cdecl, importc: "cpSweep1DAlloc", dynlib: Lib.} #/ Initialize a 1D sort and sweep broadphase. -proc Sweep1DInit*(sweep: ptr TSweep1D; bbfunc: TSpatialIndexBBFunc; +proc Sweep1DInit*(sweep: ptr TSweep1D; bbfun: TSpatialIndexBBFunc; staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{.cdecl, importc: "cpSweep1DInit", dynlib: Lib.} #/ Allocate and initialize a 1D sort and sweep broadphase. -proc Sweep1DNew*(bbfunc: TSpatialIndexBBFunc; staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{. +proc Sweep1DNew*(bbfun: TSpatialIndexBBFunc; staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{. cdecl, importc: "cpSweep1DNew", dynlib: Lib.} @@ -1359,7 +1359,7 @@ defCProp(SlideJoint, TVector, anchr2, Anchr2) defCProp(SlideJoint, CpFloat, min, Min) defCProp(SlideJoint, CpFloat, max, Max) -proc pivotJointGetClass*(): PConstraintClass {. +proc PivotJointGetClass*(): PConstraintClass {. cdecl, importc: "cpPivotJointGetClass", dynlib: Lib.} #/ Allocate a pivot joint diff --git a/tests/manyloc/keineschweine/dependencies/enet/enet.nim b/tests/manyloc/keineschweine/dependencies/enet/enet.nim index df1b743ee0..93857207a2 100644 --- a/tests/manyloc/keineschweine/dependencies/enet/enet.nim +++ b/tests/manyloc/keineschweine/dependencies/enet/enet.nim @@ -20,7 +20,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. const Lib = "libenet.so.1(|.0.3)" -{.deadCodeElim: ON.} +{.deadCodeElim: on.} const ENET_VERSION_MAJOR* = 1 ENET_VERSION_MINOR* = 3 diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim index 44d00db53d..4f2fb1ea3c 100644 --- a/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim +++ b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim @@ -9,15 +9,6 @@ template defPacketImports*(): stmt {.immediate, dirty.} = import macros, macro_dsl, estreams from strutils import format -proc `$`*[T](x: seq[T]): string = - result = "[seq len=" - result.add($x.len) - result.add ':' - for i in 0.. Date: Wed, 4 Feb 2015 22:09:42 +0100 Subject: [PATCH 051/250] Clean up tests/modules --- tests/modules/tmismatchedvisibility.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/modules/tmismatchedvisibility.nim b/tests/modules/tmismatchedvisibility.nim index 6f2f79282c..325c729c05 100644 --- a/tests/modules/tmismatchedvisibility.nim +++ b/tests/modules/tmismatchedvisibility.nim @@ -1,9 +1,9 @@ discard """ line: 8 - errormsg: "public implementation 'tmismatchedvisibility.foo(a: int): int' has non-public forward declaration in tmismatchedvisibility.nim(6,5)" + errormsg: "public implementation 'tmismatchedvisibility.foo(a: int)' has non-public forward declaration in " """ proc foo(a: int): int proc foo*(a: int): int = - result = a + a \ No newline at end of file + result = a + a From 1c4153790bbdad0dbd6144e43cf92fc07d08bf5f Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 22:15:30 +0100 Subject: [PATCH 052/250] Clean up tests/osproc --- tests/osproc/tstdin.nim | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/osproc/tstdin.nim b/tests/osproc/tstdin.nim index 2ea9399924..b491c25000 100644 --- a/tests/osproc/tstdin.nim +++ b/tests/osproc/tstdin.nim @@ -4,13 +4,16 @@ discard """ """ import osproc, os, streams -doAssert fileExists(getCurrentDir() / "tests" / "osproc" / "ta.exe") +const filename = when defined(Windows): "ta.exe" else: "ta" -var p = startProcess("ta.exe", getCurrentDir() / "tests" / "osproc") +doAssert fileExists(getCurrentDir() / "tests" / "osproc" / filename) + +var p = startProcess(filename, getCurrentDir() / "tests" / "osproc") p.inputStream.write("5\n") +p.inputStream.flush() while true: let line = p.outputStream.readLine() if line != "": echo line else: - break \ No newline at end of file + break From 25cee6e05b197cec458653b38e78c7027d0dff78 Mon Sep 17 00:00:00 2001 From: def Date: Wed, 4 Feb 2015 22:18:06 +0100 Subject: [PATCH 053/250] Clean up tests/static tstaticparammacro still fails --- tests/static/tmatrix.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/static/tmatrix.nim b/tests/static/tmatrix.nim index d8cc5d14db..a143e2bc9e 100644 --- a/tests/static/tmatrix.nim +++ b/tests/static/tmatrix.nim @@ -1,5 +1,5 @@ discard """ - output: "111" + output: "" """ type Matrix[M,N: static[int]] = array[M, array[N, float]] From c795a469bcc70f912363f1639a323465e5176f5b Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 5 Feb 2015 02:27:43 +0100 Subject: [PATCH 054/250] fixes #2011 --- lib/system.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/system.nim b/lib/system.nim index 12c5c63036..8948c62a1c 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2194,7 +2194,8 @@ elif hostOS != "standalone": inc(i) {.pop.} -proc echo*(x: varargs[expr, `$`]) {.magic: "Echo", tags: [WriteIOEffect], benign.} +proc echo*(x: varargs[expr, `$`]) {.magic: "Echo", tags: [WriteIOEffect], + benign, sideEffect.} ## Writes and flushes the parameters to the standard output. ## ## Special built-in that takes a variable number of arguments. Each argument From b44ee119c83923fb8c8d6c5671952f710b5425a5 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 5 Feb 2015 12:23:12 +0100 Subject: [PATCH 055/250] list CC executions properly again for --parallelBuild:1 --- compiler/extccomp.nim | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index bc888315ff..8e40cca394 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -428,13 +428,17 @@ proc addFileToLink*(filename: string) = prependStr(toLink, filename) # BUGFIX: was ``appendStr`` -proc execExternalProgram*(cmd: string, prettyCmd = "") = +proc execWithEcho(cmd: string, prettyCmd = ""): int = if optListCmd in gGlobalOptions or gVerbosity > 0: if prettyCmd != "": msgWriteln(prettyCmd) else: msgWriteln(cmd) - if execCmd(cmd) != 0: rawMessage(errExecutionOfProgramFailed, "") + result = execCmd(cmd) + +proc execExternalProgram*(cmd: string, prettyCmd = "") = + if execWithEcho(cmd, prettyCmd) != 0: + rawMessage(errExecutionOfProgramFailed, "") proc generateScript(projectFile: string, script: PRope) = let (dir, name, ext) = splitFile(projectFile) @@ -622,7 +626,7 @@ proc callCCompiler*(projectfile: string) = if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors() var res = 0 if gNumberOfProcessors <= 1: - for i in countup(0, high(cmds)): res = max(execCmd(cmds[i]), res) + for i in countup(0, high(cmds)): res = max(execWithEcho(cmds[i]), res) elif optListCmd in gGlobalOptions or gVerbosity > 1: res = execProcesses(cmds, {poEchoCmd, poUseShell, poParentStreams}, gNumberOfProcessors) From 53f4c7758b0c9d3df562795eeca0a553eb22e219 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 5 Feb 2015 13:12:20 +0100 Subject: [PATCH 056/250] fixes #1601 --- compiler/main.nim | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/main.nim b/compiler/main.nim index 06dcad7b0e..42a782c027 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -251,7 +251,6 @@ proc mainCommand* = commandCompileToC() of "cpp", "compiletocpp": gCmd = cmdCompileToCpp - if cCompiler == ccGcc: setCC("gcc") defineSymbol("cpp") commandCompileToC() of "objc", "compiletooc": From 65ce08f38c6a8ae05df5529a5b2d51de7aaec2d6 Mon Sep 17 00:00:00 2001 From: Charles Blake Date: Fri, 6 Feb 2015 09:24:20 -0500 Subject: [PATCH 057/250] Add hcode. Re-factor rawGet. Fix infinite loop. Replace state enum with a cached hash code which has the same memory overhead and locality as the enum, but can really speed things up with non-integer-like keys (keys for which either hash() or == take more than couple cycles, or where the key data is "indirect" and might incur another cache miss). To function as both empty/filled state and a hash code cache, it only needs to be ensured that hash codes are non-zero for any real key. That is done at the one place in the whole file hash() is called. Keep convention clear via isFilled() & isEmpty(). An isDeleted state will no longer be necessary as per below excl/inf loop fix. Since some use sites know hc and some do not, re-factor rawGet into two forms - one with known hash code and one with an unknown HC that returns it. Both forms still return <0 on missing, but returns the much more informative "-1 - index". That return can be quickly inverted by -1 - result to recover the index where insert should happen, provided no modifications are made to the table in the meantime. This protocol retains the prior <0 interface and also makes it easy to avoid unnecessary duplicate search work in procs like containsOrInclImpl (which formerly searched in the initial get and AGAIN in rawInsert). Strip the searching part out of rawInsert to "make it even more raw". swap(s.data, n) a bit earlier so rawGet and rawGetKnownHC can have similar parameter lists and integrate well with rawInsert/code sharing between Set and OrderedSet impls. This PR also fixes infinite looping upon too many deletes. [ The deleted state (aka "tombstone") approach is vulnerable to the table filling up with deleted items which forces giant scans for missing keys which could be anywhere. In the version prior to this PR, table wraparound wasn't even detected yielding infinite loops. ] This PR changes excl() from marking slots as deleted to Knuth algo 6.4R, "local/incremental moveback rehashing" - adapted from Knuth's h->h-1 to the cache-friendlier h->h+1 probe sequence and adapted from "gotos" to a new doWhile template. This method restores the table to a state that would have resulted from pure inserts (in some order). Update nextTry accordingly. Since linear probing can degrade a little faster, 50% rather than 66% may be a better default growth threshold, but users should be able to adjust threshold anyway. Old unit tests all pass. More extensive testing in this module is probably warranted before taking similar enhancements over to collections.tables. --- lib/pure/collections/sets.nim | 135 +++++++++++++++++++++++----------- 1 file changed, 94 insertions(+), 41 deletions(-) diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 4cc46149ed..72fd5cd811 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -24,9 +24,12 @@ import when not defined(nimhygiene): {.pragma: dirty.} +# For "integer-like A" that are too big for intsets/bit-vectors to be practical, +# it would be best to shrink hcode to the same size as the integer. Larger +# codes should never be needed, and this can pack more entries per cache-line. +# Losing hcode entirely is also possible - if some element value is forbidden. type - SlotEnum = enum seEmpty, seFilled, seDeleted - KeyValuePair[A] = tuple[slot: SlotEnum, key: A] + KeyValuePair[A] = tuple[hcode: THash, key: A] KeyValuePairSeq[A] = seq[KeyValuePair[A]] HashSet* {.myShallow.}[A] = object ## \ ## A generic hash set. @@ -38,6 +41,14 @@ type {.deprecated: [TSet: HashSet].} +# hcode for real keys cannot be zero. hcode==0 signifies an empty slot. These +# two procs retain clarity of that encoding without the space cost of an enum. +proc isEmpty(hcode: THash): bool {.inline.} = + result = hcode == 0 + +proc isFilled(hcode: THash): bool {.inline.} = + result = hcode != 0 + proc isValid*[A](s: HashSet[A]): bool = ## Returns `true` if the set has been initialized with `initSet <#initSet>`_. ## @@ -94,7 +105,7 @@ iterator items*[A](s: HashSet[A]): A = ## # --> {(a: 1, b: 3), (a: 0, b: 4)} assert s.isValid, "The set needs to be initialized." for h in 0..high(s.data): - if s.data[h].slot == seFilled: yield s.data[h].key + if isFilled(s.data[h].hcode): yield s.data[h].key const growthFactor = 2 @@ -104,24 +115,34 @@ proc mustRehash(length, counter: int): bool {.inline.} = result = (length * 2 < counter * 3) or (length - counter < 4) proc nextTry(h, maxHash: THash): THash {.inline.} = - result = ((5 * h) + 1) and maxHash + result = (h + 1) and maxHash -template rawGetImpl() {.dirty.} = - var h: THash = hash(key) and high(s.data) # start with real hash value - while s.data[h].slot != seEmpty: - if s.data[h].key == key and s.data[h].slot == seFilled: +template rawGetKnownHCImpl() {.dirty.} = + var h: THash = hc and high(s.data) # start with real hash value + while isFilled(s.data[h].hcode): + # Compare hc THEN key with boolean short circuit. This makes the common case + # zero ==key's for missing (e.g.inserts) and exactly one ==key for present. + # It does slow down succeeding lookups by one extra THash cmp&and..usually + # just a few clock cycles, generally worth it for any non-integer-like A. + if s.data[h].hcode == hc and s.data[h].key == key: # compare hc THEN key return h h = nextTry(h, high(s.data)) - result = -1 + result = -1 - h # < 0 => MISSING; insert idx = -1 - result + +template rawGetImpl() {.dirty.} = + hc = hash(key) + if hc == 0: # This almost never taken branch should be very predictable. + hc = 314159265 # Value doesn't matter; Any non-zero favorite is fine. + rawGetKnownHCImpl() template rawInsertImpl() {.dirty.} = - var h: THash = hash(key) and high(data) - while data[h].slot == seFilled: - h = nextTry(h, high(data)) data[h].key = key - data[h].slot = seFilled + data[h].hcode = hc -proc rawGet[A](s: HashSet[A], key: A): int = +proc rawGetKnownHC[A](s: HashSet[A], key: A, hc: THash): int {.inline.} = + rawGetKnownHCImpl() + +proc rawGet[A](s: HashSet[A], key: A, hc: var THash): int {.inline.} = rawGetImpl() proc mget*[A](s: var HashSet[A], key: A): var A = @@ -130,7 +151,8 @@ proc mget*[A](s: var HashSet[A], key: A): var A = ## when one overloaded 'hash' and '==' but still needs reference semantics ## for sharing. assert s.isValid, "The set needs to be initialized." - var index = rawGet(s, key) + var hc: THash + var index = rawGet(s, key, hc) if index >= 0: result = s.data[index].key else: raise newException(KeyError, "key not found: " & $key) @@ -147,33 +169,43 @@ proc contains*[A](s: HashSet[A], key: A): bool = ## values.excl(2) ## assert(not values.contains(2)) assert s.isValid, "The set needs to be initialized." - var index = rawGet(s, key) + var hc: THash + var index = rawGet(s, key, hc) result = index >= 0 -proc rawInsert[A](s: var HashSet[A], data: var KeyValuePairSeq[A], key: A) = +proc rawInsert[A](s: var HashSet[A], data: var KeyValuePairSeq[A], key: A, + hc: THash, h: THash) = rawInsertImpl() proc enlarge[A](s: var HashSet[A]) = var n: KeyValuePairSeq[A] newSeq(n, len(s.data) * growthFactor) - for i in countup(0, high(s.data)): - if s.data[i].slot == seFilled: rawInsert(s, n, s.data[i].key) - swap(s.data, n) + swap(s.data, n) # n is now old seq + for i in countup(0, high(n)): + if isFilled(n[i].hcode): + var j = -1 - rawGetKnownHC(s, n[i].key, n[i].hcode) + rawInsert(s, s.data, n[i].key, n[i].hcode, j) template inclImpl() {.dirty.} = - var index = rawGet(s, key) + var hc: THash + var index = rawGet(s, key, hc) if index < 0: - if mustRehash(len(s.data), s.counter): enlarge(s) - rawInsert(s, s.data, key) + if mustRehash(len(s.data), s.counter): + enlarge(s) + index = rawGetKnownHC(s, key, hc) + rawInsert(s, s.data, key, hc, -1 - index) inc(s.counter) template containsOrInclImpl() {.dirty.} = - var index = rawGet(s, key) + var hc: THash + var index = rawGet(s, key, hc) if index >= 0: result = true else: - if mustRehash(len(s.data), s.counter): enlarge(s) - rawInsert(s, s.data, key) + if mustRehash(len(s.data), s.counter): + enlarge(s) + index = rawGetKnownHC(s, key, hc) + rawInsert(s, s.data, key, hc, -1 - index) inc(s.counter) proc incl*[A](s: var HashSet[A], key: A) = @@ -204,6 +236,10 @@ proc incl*[A](s: var HashSet[A], other: HashSet[A]) = assert other.isValid, "The set `other` needs to be initialized." for item in other: incl(s, item) +template doWhile(a: expr, b: stmt): stmt = + b + while a: b + proc excl*[A](s: var HashSet[A], key: A) = ## Excludes `key` from the set `s`. ## @@ -215,10 +251,22 @@ proc excl*[A](s: var HashSet[A], key: A) = ## s.excl(2) ## assert s.len == 3 assert s.isValid, "The set needs to be initialized." - var index = rawGet(s, key) - if index >= 0: - s.data[index].slot = seDeleted + var hc: THash + var i = rawGet(s, key, hc) + var msk = high(s.data) + if i >= 0: + s.data[i].hcode = 0 dec(s.counter) + while true: # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1 + var j = i # The correctness of this depends on (h+1) in nextTry, + var r = j # though may be adaptable to other simple sequences. + s.data[i].hcode = 0 # mark current EMPTY + doWhile ((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)): + i = (i + 1) and msk # increment mod table size + if isEmpty(s.data[i].hcode): # end of collision cluster; So all done + return + r = s.data[i].hcode and msk # "home" location of key@i + s.data[j] = s.data[i] # data[j] will be marked EMPTY next loop proc excl*[A](s: var HashSet[A], other: HashSet[A]) = ## Excludes everything in `other` from `s`. @@ -494,7 +542,7 @@ proc map*[A, B](data: HashSet[A], op: proc (x: A): B {.closure.}): HashSet[B] = type OrderedKeyValuePair[A] = tuple[ - slot: SlotEnum, next: int, key: A] + hcode: THash, next: int, key: A] OrderedKeyValuePairSeq[A] = seq[OrderedKeyValuePair[A]] OrderedSet* {.myShallow.}[A] = object ## \ ## A generic hash set that remembers insertion order. @@ -546,7 +594,7 @@ template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} = var h = s.first while h >= 0: var nxt = s.data[h].next - if s.data[h].slot == seFilled: yieldStmt + if isFilled(s.data[h].hcode): yieldStmt h = nxt iterator items*[A](s: OrderedSet[A]): A = @@ -571,7 +619,10 @@ iterator items*[A](s: OrderedSet[A]): A = forAllOrderedPairs: yield s.data[h].key -proc rawGet[A](s: OrderedSet[A], key: A): int = +proc rawGetKnownHC[A](s: OrderedSet[A], key: A, hc: THash): int {.inline.} = + rawGetKnownHCImpl() + +proc rawGet[A](s: OrderedSet[A], key: A, hc: var THash): int {.inline.} = rawGetImpl() proc contains*[A](s: OrderedSet[A], key: A): bool = @@ -585,11 +636,12 @@ proc contains*[A](s: OrderedSet[A], key: A): bool = ## values.incl(2) ## assert values.contains(2) assert s.isValid, "The set needs to be initialized." - var index = rawGet(s, key) + var hc: THash + var index = rawGet(s, key, hc) result = index >= 0 -proc rawInsert[A](s: var OrderedSet[A], - data: var OrderedKeyValuePairSeq[A], key: A) = +proc rawInsert[A](s: var OrderedSet[A], data: var OrderedKeyValuePairSeq[A], + key: A, hc: THash, h: THash) = rawInsertImpl() data[h].next = -1 if s.first < 0: s.first = h @@ -602,12 +654,13 @@ proc enlarge[A](s: var OrderedSet[A]) = var h = s.first s.first = -1 s.last = -1 - while h >= 0: - var nxt = s.data[h].next - if s.data[h].slot == seFilled: - rawInsert(s, n, s.data[h].key) - h = nxt swap(s.data, n) + while h >= 0: + var nxt = n[h].next + if isFilled(n[h].hcode): + var j = -1 - rawGetKnownHC(s, n[h].key, n[h].hcode) + rawInsert(s, s.data, n[h].key, n[h].hcode, j) + h = nxt proc incl*[A](s: var OrderedSet[A], key: A) = ## Includes an element `key` in `s`. @@ -726,7 +779,7 @@ proc `==`*[A](s, t: OrderedSet[A]): bool = while h >= 0 and g >= 0: var nxh = s.data[h].next var nxg = t.data[g].next - if s.data[h].slot == seFilled and s.data[g].slot == seFilled: + if isFilled(s.data[h].hcode) and isFilled(s.data[g].hcode): if s.data[h].key == s.data[g].key: inc compared else: From 99b14c8d8d189987d0478263c50c7d2b0dc0e625 Mon Sep 17 00:00:00 2001 From: Fabio Cevasco Date: Fri, 6 Feb 2015 22:40:21 +0100 Subject: [PATCH 058/250] newRollingFileLogger - fmtStr is always set to defaultFmtStr --- lib/pure/logging.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index bb1835ed77..de733b75ca 100644 --- a/lib/pure/logging.nim +++ b/lib/pure/logging.nim @@ -186,7 +186,7 @@ proc newRollingFileLogger*(filename = defaultFilename(), ## a new log file will be started and the old will be renamed. new(result) result.levelThreshold = levelThreshold - result.fmtStr = defaultFmtStr + result.fmtStr = fmtStr result.maxLines = maxLines result.f = open(filename, mode) result.curLine = 0 From e84834db79854c6ccc89263ec20d3749b8a87a05 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 6 Feb 2015 21:26:40 +0100 Subject: [PATCH 059/250] lots of C++ codegen improvements --- compiler/ccgcalls.nim | 24 ++++++---- compiler/ccgexprs.nim | 4 +- compiler/ccgstmts.nim | 23 +++++---- compiler/ccgtypes.nim | 5 +- compiler/cgen.nim | 100 ++++------------------------------------ compiler/cgendata.nim | 3 ++ compiler/transf.nim | 1 + lib/pure/os.nim | 8 +++- lib/system/dyncalls.nim | 6 ++- lib/system/sysio.nim | 16 +++++-- 10 files changed, 71 insertions(+), 119 deletions(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index ad9d182571..5e8bbc3351 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -124,8 +124,8 @@ proc genArgStringToCString(p: BProc, n: PNode): PRope {.inline.} = var a: TLoc initLocExpr(p, n.sons[0], a) result = ropef("$1->data", [a.rdLoc]) - -proc genArg(p: BProc, n: PNode, param: PSym): PRope = + +proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): PRope = var a: TLoc if n.kind == nkStringToCString: result = genArgStringToCString(p, n) @@ -138,7 +138,15 @@ proc genArg(p: BProc, n: PNode, param: PSym): PRope = elif p.module.compileToCpp and param.typ.kind == tyVar and n.kind == nkHiddenAddr: initLocExprSingleUse(p, n.sons[0], a) - result = rdLoc(a) + # if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still + # means '*T'. See posix.nim for lots of examples that do that in the wild. + let callee = call.sons[0] + if callee.kind == nkSym and + {sfImportC, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportC} and + {lfHeader, lfNoDecl} * callee.sym.loc.flags != {}: + result = addrLoc(a) + else: + result = rdLoc(a) else: initLocExprSingleUse(p, n, a) result = rdLoc(a) @@ -166,7 +174,7 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) = if params != nil: app(params, ~", ") if i < sonsLen(typ): assert(typ.n.sons[i].kind == nkSym) - app(params, genArg(p, ri.sons[i], typ.n.sons[i].sym)) + app(params, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri)) else: app(params, genArgNoParam(p, ri.sons[i])) fixupCall(p, le, ri, d, op.r, params) @@ -192,7 +200,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = assert(sonsLen(typ) == sonsLen(typ.n)) if i < sonsLen(typ): assert(typ.n.sons[i].kind == nkSym) - app(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym)) + app(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri)) else: app(pl, genArgNoParam(p, ri.sons[i])) if i < length - 1: app(pl, ~", ") @@ -424,12 +432,12 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = assert(sonsLen(typ) == sonsLen(typ.n)) if length > 1: - app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym)) + app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri)) app(pl, ~" ") app(pl, op.r) if length > 2: app(pl, ~": ") - app(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym)) + app(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri)) for i in countup(3, length-1): assert(sonsLen(typ) == sonsLen(typ.n)) if i >= sonsLen(typ): @@ -439,7 +447,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = app(pl, ~" ") app(pl, param.name.s) app(pl, ~": ") - app(pl, genArg(p, ri.sons[i], param)) + app(pl, genArg(p, ri.sons[i], param, ri)) if typ.sons[0] != nil: if isInvalidReturnType(typ.sons[0]): if sonsLen(ri) > 1: app(pl, ~" ") diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index bd116d6fba..591dd96ec4 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -682,7 +682,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) = d.s = OnHeap of tyVar: d.s = OnUnknown - if p.module.compileToCpp: + if p.module.compileToCpp and e.kind == nkHiddenDeref: putIntoDest(p, d, e.typ, rdLoc(a)) return of tyPtr: @@ -923,6 +923,7 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) = L: TLabel tmp: TLoc getTemp(p, e.typ, tmp) # force it into a temp! + inc p.splitDecls expr(p, e.sons[1], tmp) L = getLabel(p) if m == mOr: @@ -935,6 +936,7 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) = d = tmp else: genAssignment(p, d, tmp, {}) # no need for deep copying + dec p.splitDecls proc genEcho(p: BProc, n: PNode) = # this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)`` diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 5d348c4e4b..f5a2c0ef4a 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -203,7 +203,7 @@ proc genSingleVar(p: BProc, a: PNode) = registerGcRoot(p, v) else: let imm = isAssignedImmediately(a.sons[2]) - if imm and p.module.compileToCpp: + if imm and p.module.compileToCpp and p.splitDecls == 0: # C++ really doesn't like things like 'Foo f; f = x' as that invokes a # parameterless constructor followed by an assignment operator. So we # generate better code here: @@ -262,7 +262,7 @@ proc genConstStmt(p: BProc, t: PNode) = else: appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n", [getTypeDesc(p.module, c.typ), c.loc.r, genConstExpr(p, c.ast)]) - + proc genIf(p: BProc, n: PNode, d: var TLoc) = # # { if (!expr1) goto L1; @@ -286,17 +286,22 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) = let it = n.sons[i] if it.len == 2: when newScopeForIf: startBlock(p) - initLocExpr(p, it.sons[0], a) + initLocExprSingleUse(p, it.sons[0], a) lelse = getLabel(p) inc(p.labels) - lineFF(p, cpsStmts, "if (!$1) goto $2;$n", - "br i1 $1, label %LOC$3, label %$2$nLOC$3: $n", - [rdLoc(a), lelse, toRope(p.labels)]) + lineF(p, cpsStmts, "if (!$1) goto $2;$n", + [rdLoc(a), lelse]) when not newScopeForIf: startBlock(p) - expr(p, it.sons[1], d) + if p.module.compileToCpp: + # avoid "jump to label crosses initialization" error: + app(p.s(cpsStmts), "{") + expr(p, it.sons[1], d) + app(p.s(cpsStmts), "}") + else: + expr(p, it.sons[1], d) endBlock(p) if sonsLen(n) > 1: - lineFF(p, cpsStmts, "goto $1;$n", "br label %$1$n", [lend]) + lineF(p, cpsStmts, "goto $1;$n", [lend]) fixLabel(p, lelse) elif it.len == 1: startBlock(p) @@ -355,7 +360,7 @@ proc genReturnStmt(p: BProc, t: PNode) = # consume it before we return. var safePoint = p.finallySafePoints[p.finallySafePoints.len-1] linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", safePoint) - lineFF(p, cpsStmts, "goto BeforeRet;$n", "br label %BeforeRet$n", []) + lineF(p, cpsStmts, "goto BeforeRet;$n", []) proc genComputedGoto(p: BProc; n: PNode) = # first pass: Generate array of computed labels: diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 823e3bc1b3..ce17da17e4 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -506,7 +506,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope = # C type generation into an analysis and a code generation phase somehow. case t.kind of tyRef, tyPtr, tyVar: - let star = if t.kind == tyVar and compileToCpp(m): "&" else: "*" + var star = if t.kind == tyVar and compileToCpp(m): "&" else: "*" var et = t.lastSon var etB = et.skipTypes(abstractInst) if etB.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}: @@ -514,6 +514,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope = # ``var set[char]`` in `getParamTypeDesc` et = elemType(etB) etB = et.skipTypes(abstractInst) + star[0] = '*' case etB.kind of tyObject, tyTuple: if isImportedCppType(etB) and et.kind == tyGenericInst: @@ -529,7 +530,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope = # no restriction! We have a forward declaration for structs let x = getUniqueType(etB) let name = getTypeForward(m, x) - result = con(name, "**") + result = con(name, "*" & star) idTablePut(m.typeCache, t, result) pushType(m, x) else: diff --git a/compiler/cgen.nim b/compiler/cgen.nim index e16d5d0ce0..6768059582 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -137,79 +137,8 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope = if i - 1 >= start: app(result, substr(frmt, start, i - 1)) -const compileTimeRopeFmt = false - -when compileTimeRopeFmt: - import macros - - type TFmtFragmentKind = enum - ffSym, - ffLit, - ffParam - - type TFragment = object - case kind: TFmtFragmentKind - of ffSym, ffLit: - value: string - of ffParam: - intValue: int - - iterator fmtStringFragments(s: string): tuple[kind: TFmtFragmentKind, - value: string, - intValue: int] = - # This is a bit less featured version of the ropecg's algorithm - # (be careful when replacing ropecg calls) - var - i = 0 - length = s.len - - while i < length: - var start = i - case s[i] - of '$': - let n = s[i+1] - case n - of '$': - inc i, 2 - of '0'..'9': - # XXX: use the new case object construction syntax when it's ready - yield (kind: ffParam, value: "", intValue: n.ord - ord('1')) - inc i, 2 - start = i - else: - inc i - of '#': - inc i - var j = i - while s[i] in IdentChars: inc i - yield (kind: ffSym, value: substr(s, j, i-1), intValue: 0) - start = i - else: discard - - while i < length: - if s[i] != '$' and s[i] != '#': inc i - else: break - - if i - 1 >= start: - yield (kind: ffLit, value: substr(s, start, i-1), intValue: 0) - - macro rfmt(m: BModule, fmt: static[string], args: varargs[PRope]): expr = - ## Experimental optimized rope-formatting operator - ## The run-time code it produces will be very fast, but will it speed up - ## the compilation of nimrod itself or will the macro execution time - ## offset the gains? - result = newCall(bindSym"ropeConcat") - for frag in fmtStringFragments(fmt): - case frag.kind - of ffSym: - result.add(newCall(bindSym"cgsym", m, newStrLitNode(frag.value))) - of ffLit: - result.add(newCall(bindSym"~", newStrLitNode(frag.value))) - of ffParam: - result.add(args[frag.intValue]) -else: - template rfmt(m: BModule, fmt: string, args: varargs[PRope]): expr = - ropecg(m, fmt, args) +template rfmt(m: BModule, fmt: string, args: varargs[PRope]): expr = + ropecg(m, fmt, args) proc appcg(m: BModule, c: var PRope, frmt: TFormatStr, args: varargs[PRope]) = @@ -242,24 +171,14 @@ proc lineCg(p: BProc, s: TCProcSection, frmt: TFormatStr, args: varargs[PRope]) = app(p.s(s), indentLine(p, ropecg(p.module, frmt, args))) -when compileTimeRopeFmt: - template linefmt(p: BProc, s: TCProcSection, frmt: TFormatStr, - args: varargs[PRope]) = - line(p, s, rfmt(p.module, frmt, args)) -else: - proc linefmt(p: BProc, s: TCProcSection, frmt: TFormatStr, - args: varargs[PRope]) = - app(p.s(s), indentLine(p, ropecg(p.module, frmt, args))) +proc linefmt(p: BProc, s: TCProcSection, frmt: TFormatStr, + args: varargs[PRope]) = + app(p.s(s), indentLine(p, ropecg(p.module, frmt, args))) proc appLineCg(p: BProc, r: var PRope, frmt: TFormatStr, args: varargs[PRope]) = app(r, indentLine(p, ropecg(p.module, frmt, args))) -proc lineFF(p: BProc, s: TCProcSection, cformat, llvmformat: string, - args: varargs[PRope]) = - if gCmd == cmdCompileToLLVM: lineF(p, s, llvmformat, args) - else: lineF(p, s, cformat, args) - proc safeLineNm(info: TLineInfo): int = result = toLinenumber(info) if result < 0: result = 0 # negative numbers are not allowed in #line @@ -723,13 +642,13 @@ proc cgsym(m: BModule, name: string): PRope = rawMessage(errSystemNeeds, name) result = sym.loc.r -proc generateHeaders(m: BModule) = +proc generateHeaders(m: BModule) = app(m.s[cfsHeaders], tnl & "#include \"nimbase.h\"" & tnl) var it = PStrEntry(m.headerFiles.head) - while it != nil: + while it != nil: if it.data[0] notin {'\"', '<'}: appf(m.s[cfsHeaders], "$N#include \"$1\"$N", [toRope(it.data)]) - else: + else: appf(m.s[cfsHeaders], "$N#include $1$N", [toRope(it.data)]) it = PStrEntry(it.next) @@ -809,9 +728,10 @@ proc genProcAux(m: BModule, prc: PSym) = if (optProfiler in prc.options) and (gCmd != cmdCompileToLLVM): # invoke at proc entry for recursion: appcg(p, cpsInit, "\t#nimProfile();$n", []) + if p.beforeRetNeeded: app(generatedProc, "{") app(generatedProc, p.s(cpsInit)) app(generatedProc, p.s(cpsStmts)) - if p.beforeRetNeeded: app(generatedProc, ~"\tBeforeRet: ;$n") + if p.beforeRetNeeded: app(generatedProc, ~"\t}BeforeRet: ;$n") app(generatedProc, deinitGCFrame(p)) if optStackTrace in prc.options: app(generatedProc, deinitFrame(p)) app(generatedProc, returnStmt) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 508f980747..bb98454a7f 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -82,6 +82,9 @@ type maxFrameLen*: int # max length of frame descriptor module*: BModule # used to prevent excessive parameter passing withinLoop*: int # > 0 if we are within a loop + splitDecls*: int # > 0 if we are in some context for C++ that + # requires 'T x = T()' to become 'T x; x = T()' + # (yes, C++ is weird like that) gcFrameId*: Natural # for the GC stack marking gcFrameType*: PRope # the struct {} we put the GC markers into diff --git a/compiler/transf.nim b/compiler/transf.nim index f511ed69fc..cf13630fd2 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -321,6 +321,7 @@ proc transformYield(c: PTransf, n: PNode): PTransNode = proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode = result = transformSons(c, n) + if gCmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags: return var n = result.PNode case n.sons[0].kind of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64: diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 147614d3de..f01343673d 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1074,8 +1074,12 @@ when defined(windows): # because we support Windows GUI applications, things get really # messy here... when useWinUnicode: - proc strEnd(cstr: WideCString, c = 0'i32): WideCString {. - importc: "wcschr", header: "".} + when defined(cpp): + proc strEnd(cstr: WideCString, c = 0'i32): WideCString {. + importcpp: "(NI16*)wcschr((const wchar_t *)#, #)", header: "".} + else: + proc strEnd(cstr: WideCString, c = 0'i32): WideCString {. + importc: "wcschr", header: "".} else: proc strEnd(cstr: cstring, c = 0'i32): cstring {. importc: "strchr", header: "".} diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim index aab2a7b61c..539e37aaff 100644 --- a/lib/system/dyncalls.nim +++ b/lib/system/dyncalls.nim @@ -84,16 +84,18 @@ elif defined(windows) or defined(dos): type THINSTANCE {.importc: "HINSTANCE".} = object x: pointer + proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {. + importcpp: "(void*)GetProcAddress(@)", header: "", stdcall.} else: type THINSTANCE {.importc: "HINSTANCE".} = pointer + proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {. + importc: "GetProcAddress", header: "", stdcall.} proc freeLibrary(lib: THINSTANCE) {. importc: "FreeLibrary", header: "", stdcall.} proc winLoadLibrary(path: cstring): THINSTANCE {. importc: "LoadLibraryA", header: "", stdcall.} - proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {. - importc: "GetProcAddress", header: "", stdcall.} proc nimUnloadLibrary(lib: TLibHandle) = freeLibrary(cast[THINSTANCE](lib)) diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim index 7908fbe4dd..2e254c87b8 100644 --- a/lib/system/sysio.nim +++ b/lib/system/sysio.nim @@ -183,11 +183,17 @@ proc rawEchoNL() {.inline, compilerproc.} = write(stdout, "\n") when (defined(windows) and not defined(useWinAnsi)) or defined(nimdoc): include "system/widestrs" -when defined(windows) and not defined(useWinAnsi): - proc wfopen(filename, mode: WideCString): pointer {. - importc: "_wfopen", nodecl.} - proc wfreopen(filename, mode: WideCString, stream: File): File {. - importc: "_wfreopen", nodecl.} +when defined(windows) and not defined(useWinAnsi): + when defined(cpp): + proc wfopen(filename, mode: WideCString): pointer {. + importcpp: "_wfopen((const wchar_t*)#, (const wchar_t*)#)", nodecl.} + proc wfreopen(filename, mode: WideCString, stream: File): File {. + importc: "_wfreopen((const wchar_t*)#, (const wchar_t*)#)", nodecl.} + else: + proc wfopen(filename, mode: WideCString): pointer {. + importc: "_wfopen", nodecl.} + proc wfreopen(filename, mode: WideCString, stream: File): File {. + importc: "_wfreopen", nodecl.} proc fopen(filename, mode: cstring): pointer = var f = newWideCString(filename) From 74c6c8c903a2eb497ee74aaf9ba741b1abf40c88 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 7 Feb 2015 01:06:25 +0100 Subject: [PATCH 060/250] compiler distinguishes between 2 different 'var' types for C++ interop; code cleanups --- compiler/ast.nim | 9 ++--- compiler/ccgexprs.nim | 9 +++-- compiler/ccgtypes.nim | 38 ++++++------------ compiler/cgen.nim | 89 +++++++++++-------------------------------- compiler/semexprs.nim | 1 + lib/pure/strtabs.nim | 2 +- todo.txt | 1 - 7 files changed, 45 insertions(+), 104 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index f7c1a07eda..1a5ae8aab7 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -459,7 +459,7 @@ type tfNeedsInit, # type constains a "not nil" constraint somewhere or some # other type so that it requires inititalization - tfHasShared, # type constains a "shared" constraint modifier somewhere + tfVarIsPtr, # 'var' type is translated like 'ptr' even in C++ mode tfHasMeta, # type contains "wildcard" sub-types such as generic params # or other type classes tfHasGCedMem, # type contains GC'ed memory @@ -522,7 +522,7 @@ const skError* = skUnknown # type flags that are essential for type equality: - eqTypeFlags* = {tfIterator, tfShared, tfNotNil} + eqTypeFlags* = {tfIterator, tfShared, tfNotNil, tfVarIsPtr} type TMagic* = enum # symbols that require compiler magic: @@ -1348,7 +1348,7 @@ proc isGCedMem*(t: PType): bool {.inline.} = proc propagateToOwner*(owner, elem: PType) = const HaveTheirOwnEmpty = {tySequence, tySet} - owner.flags = owner.flags + (elem.flags * {tfHasShared, tfHasMeta}) + owner.flags = owner.flags + (elem.flags * {tfHasMeta}) if tfNotNil in elem.flags: if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvokation}: owner.flags.incl tfNotNil @@ -1359,9 +1359,6 @@ proc propagateToOwner*(owner, elem: PType) = if owner.kind in HaveTheirOwnEmpty: discard else: owner.flags.incl tfNeedsInit - if tfShared in elem.flags: - owner.flags.incl tfHasShared - if elem.isMetaType: owner.flags.incl tfHasMeta diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 591dd96ec4..32678d4725 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -664,7 +664,8 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = proc isCppRef(p: BProc; typ: PType): bool {.inline.} = result = p.module.compileToCpp and - skipTypes(typ, abstractInst).kind == tyVar + skipTypes(typ, abstractInst).kind == tyVar and + tfVarIsPtr notin skipTypes(typ, abstractInst).flags proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) = let mt = mapType(e.sons[0].typ) @@ -677,12 +678,14 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) = else: var a: TLoc initLocExprSingleUse(p, e.sons[0], a) - case skipTypes(a.t, abstractInst).kind + let typ = skipTypes(a.t, abstractInst) + case typ.kind of tyRef: d.s = OnHeap of tyVar: d.s = OnUnknown - if p.module.compileToCpp and e.kind == nkHiddenDeref: + if tfVarIsPtr notin typ.flags and p.module.compileToCpp and + e.kind == nkHiddenDeref: putIntoDest(p, d, e.typ, rdLoc(a)) return of tyPtr: diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index ce17da17e4..0220d2066e 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -27,17 +27,7 @@ proc isKeyword(w: PIdent): bool = proc mangleName(s: PSym): PRope = result = s.loc.r - if result == nil: - if gCmd == cmdCompileToLLVM: - case s.kind - of skProc, skMethod, skConverter, skConst, skIterators: - result = ~"@" - of skVar, skForVar, skResult, skLet: - if sfGlobal in s.flags: result = ~"@" - else: result = ~"%" - of skTemp, skParam, skType, skEnumField, skModule: - result = ~"%" - else: internalError(s.info, "mangleName") + if result == nil: when oKeepVariableNames: let keepOrigName = s.kind in skLocalVars - {skForVar} and {sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and @@ -103,13 +93,11 @@ proc typeName(typ: PType): PRope = else: ~"TY" proc getTypeName(typ: PType): PRope = - if (typ.sym != nil) and ({sfImportc, sfExportc} * typ.sym.flags != {}) and - (gCmd != cmdCompileToLLVM): + if typ.sym != nil and {sfImportc, sfExportc} * typ.sym.flags != {}: result = typ.sym.loc.r else: if typ.loc.r == nil: - typ.loc.r = if gCmd != cmdCompileToLLVM: con(typ.typeName, typ.id.toRope) - else: con([~"%", typ.typeName, typ.id.toRope]) + typ.loc.r = con(typ.typeName, typ.id.toRope) result = typ.loc.r if result == nil: internalError("getTypeName: " & $typ.kind) @@ -200,9 +188,6 @@ const "N_SYSCALL", # this is probably not correct for all platforms, # but one can #define it to what one wants "N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_CLOSURE", "N_NOCONV"] - CallingConvToStrLLVM: array[TCallingConvention, string] = ["fastcc $1", - "stdcall $1", "ccc $1", "safecall $1", "syscall $1", "$1 alwaysinline", - "$1 noinline", "fastcc $1", "ccc $1", "$1"] proc cacheGetType(tab: TIdTable, key: PType): PRope = # returns nil if we need to declare this type @@ -284,23 +269,23 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope, # this fixes the 'sort' bug: if param.typ.kind == tyVar: param.loc.s = OnUnknown # need to pass hidden parameter: - appff(params, ", NI $1Len$2", ", @NI $1Len$2", [param.loc.r, j.toRope]) + appf(params, ", NI $1Len$2", [param.loc.r, j.toRope]) inc(j) arr = arr.sons[0] - if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]): + if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]): var arr = t.sons[0] if params != nil: app(params, ", ") app(params, getTypeDescAux(m, arr, check)) - if (mapReturnType(t.sons[0]) != ctArray) or (gCmd == cmdCompileToLLVM): + if (mapReturnType(t.sons[0]) != ctArray): app(params, "*") - appff(params, " Result", " @Result", []) + appf(params, " Result", []) if t.callConv == ccClosure and declareEnvironment: if params != nil: app(params, ", ") app(params, "void* ClEnv") if tfVarargs in t.flags: if params != nil: app(params, ", ") app(params, "...") - if params == nil and gCmd != cmdCompileToLLVM: app(params, "void)") + if params == nil: app(params, "void)") else: app(params, ")") params = con("(", params) @@ -505,8 +490,9 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope = # but determining when this needs to be done is hard. We should split # C type generation into an analysis and a code generation phase somehow. case t.kind - of tyRef, tyPtr, tyVar: - var star = if t.kind == tyVar and compileToCpp(m): "&" else: "*" + of tyRef, tyPtr, tyVar: + var star = if t.kind == tyVar and tfVarIsPtr notin typ.flags and + compileToCpp(m): "&" else: "*" var et = t.lastSon var etB = et.skipTypes(abstractInst) if etB.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}: @@ -678,7 +664,7 @@ proc genProcHeader(m: BModule, prc: PSym): PRope = rettype, params: PRope genCLineDir(result, prc.info) # using static is needed for inline procs - if gCmd != cmdCompileToLLVM and lfExportLib in prc.loc.flags: + if lfExportLib in prc.loc.flags: if m.isHeaderFile: result.app "N_LIB_IMPORT " else: diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 6768059582..a606cb5b96 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -25,15 +25,6 @@ when options.hasTinyCBackend: var generatedHeader: BModule -proc ropeff(cformat, llvmformat: string, args: varargs[PRope]): PRope = - if gCmd == cmdCompileToLLVM: result = ropef(llvmformat, args) - else: result = ropef(cformat, args) - -proc appff(dest: var PRope, cformat, llvmformat: string, - args: varargs[PRope]) = - if gCmd == cmdCompileToLLVM: appf(dest, llvmformat, args) - else: appf(dest, cformat, args) - proc addForwardedProc(m: BModule, prc: PSym) = m.forwardedProcs.add(prc) inc(gForwardedProcsCounter) @@ -186,8 +177,8 @@ proc safeLineNm(info: TLineInfo): int = proc genCLineDir(r: var PRope, filename: string, line: int) = assert line >= 0 if optLineDir in gOptions: - appff(r, "$N#line $2 $1$N", "; line $2 \"$1\"$n", - [toRope(makeSingleLineCString(filename)), toRope(line)]) + appf(r, "$N#line $2 $1$N", + [toRope(makeSingleLineCString(filename)), toRope(line)]) proc genCLineDir(r: var PRope, info: TLineInfo) = genCLineDir(r, info.toFullPath, info.safeLineNm) @@ -362,29 +353,6 @@ proc deinitGCFrame(p: BProc): PRope = if p.gcFrameId > 0: result = ropecg(p.module, "if (((NU)&GCFRAME) < 4096) #nimGCFrame(&GCFRAME);$n") - -proc cstringLit(p: BProc, r: var PRope, s: string): PRope = - if gCmd == cmdCompileToLLVM: - inc(p.module.labels) - inc(p.labels) - result = ropef("%LOC$1", [toRope(p.labels)]) - appf(p.module.s[cfsData], "@C$1 = private constant [$2 x i8] $3$n", - [toRope(p.module.labels), toRope(len(s)), makeLLVMString(s)]) - appf(r, "$1 = getelementptr [$2 x i8]* @C$3, %NI 0, %NI 0$n", - [result, toRope(len(s)), toRope(p.module.labels)]) - else: - result = makeCString(s) - -proc cstringLit(m: BModule, r: var PRope, s: string): PRope = - if gCmd == cmdCompileToLLVM: - inc(m.labels, 2) - result = ropef("%MOC$1", [toRope(m.labels - 1)]) - appf(m.s[cfsData], "@MOC$1 = private constant [$2 x i8] $3$n", - [toRope(m.labels), toRope(len(s)), makeLLVMString(s)]) - appf(r, "$1 = getelementptr [$2 x i8]* @MOC$3, %NI 0, %NI 0$n", - [result, toRope(len(s)), toRope(m.labels)]) - else: - result = makeCString(s) proc allocParam(p: BProc, s: PSym) = assert(s.kind == skParam) @@ -426,7 +394,7 @@ proc localVarDecl(p: BProc; s: PSym): PRope = result = ropef(s.cgDeclFrmt, result, s.loc.r) proc assignLocalVar(p: BProc, s: PSym) = - #assert(s.loc.k == locNone) // not yet assigned + #assert(s.loc.k == locNone) # not yet assigned # this need not be fullfilled for inline procs; they are regenerated # for each module that uses them! let decl = localVarDecl(p, s).con(";" & tnl) @@ -472,13 +440,11 @@ proc assignGlobalVar(p: BProc, s: PSym) = {optStackTrace, optEndb}: appcg(p.module, p.module.s[cfsDebugInit], "#dbgRegisterGlobal($1, &$2, $3);$n", - [cstringLit(p, p.module.s[cfsDebugInit], - normalize(s.owner.name.s & '.' & s.name.s)), + [makeCString(normalize(s.owner.name.s & '.' & s.name.s)), s.loc.r, genTypeInfo(p.module, s.typ)]) proc assignParam(p: BProc, s: PSym) = assert(s.loc.r != nil) - if sfAddrTaken in s.flags and gCmd == cmdCompileToLLVM: allocParam(p, s) localDebugInfo(p, s) proc fillProcLoc(sym: PSym) = @@ -572,7 +538,6 @@ proc symInDynamicLib(m: BModule, sym: PSym) = let isCall = isGetProcAddr(lib) var extname = sym.loc.r if not isCall: loadDynamicLib(m, lib) - if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect) var tmp = mangleDynLibProc(sym) sym.loc.r = tmp # from now on we only need the internal name sym.typ.sym = nil # generate a new name @@ -588,7 +553,7 @@ proc symInDynamicLib(m: BModule, sym: PSym) = params.app(", ") let load = ropef("\t$1 = ($2) ($3$4));$n", [tmp, getTypeDesc(m, sym.typ), - params, cstringLit(m, m.s[cfsDynLibInit], ropeToStr(extname))]) + params, makeCString(ropeToStr(extname))]) var last = lastSon(n) if last.kind == nkHiddenStdConv: last = last.sons[1] internalAssert(last.kind == nkStrLit) @@ -603,10 +568,8 @@ proc symInDynamicLib(m: BModule, sym: PSym) = appcg(m, m.s[cfsDynLibInit], "\t$1 = ($2) #nimGetProcAddr($3, $4);$n", [tmp, getTypeDesc(m, sym.typ), - lib.name, cstringLit(m, m.s[cfsDynLibInit], ropeToStr(extname))]) - appff(m.s[cfsVars], "$2 $1;$n", - "$1 = linkonce global $2 zeroinitializer$n", - [sym.loc.r, getTypeDesc(m, sym.loc.t)]) + lib.name, makeCString(ropeToStr(extname))]) + appf(m.s[cfsVars], "$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)]) proc varInDynamicLib(m: BModule, sym: PSym) = var lib = sym.annex @@ -619,7 +582,7 @@ proc varInDynamicLib(m: BModule, sym: PSym) = appcg(m, m.s[cfsDynLibInit], "$1 = ($2*) #nimGetProcAddr($3, $4);$n", [tmp, getTypeDesc(m, sym.typ), - lib.name, cstringLit(m, m.s[cfsDynLibInit], ropeToStr(extname))]) + lib.name, makeCString(ropeToStr(extname))]) appf(m.s[cfsVars], "$2* $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)]) @@ -721,11 +684,11 @@ proc genProcAux(m: BModule, prc: PSym) = app(generatedProc, initGCFrame(p)) if optStackTrace in prc.options: app(generatedProc, p.s(cpsLocals)) - var procname = cstringLit(p, generatedProc, prc.name.s) + var procname = makeCString(prc.name.s) app(generatedProc, initFrame(p, procname, prc.info.quotedFilename)) else: app(generatedProc, p.s(cpsLocals)) - if (optProfiler in prc.options) and (gCmd != cmdCompileToLLVM): + if optProfiler in prc.options: # invoke at proc entry for recursion: appcg(p, cpsInit, "\t#nimProfile();$n", []) if p.beforeRetNeeded: app(generatedProc, "{") @@ -751,7 +714,6 @@ proc genProcPrototype(m: BModule, sym: PSym) = not containsOrIncl(m.declaredThings, sym.id): app(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n", getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym))) - if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect) elif not containsOrIncl(m.declaredProtos, sym.id): var header = genProcHeader(m, sym) if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym): @@ -849,21 +811,17 @@ proc addIntTypes(result: var PRope) {.inline.} = proc getCopyright(cfile: string): PRope = if optCompileOnly in gGlobalOptions: - result = ropeff("/* Generated by Nim Compiler v$1 */$N" & + result = ropef("/* Generated by Nim Compiler v$1 */$N" & "/* (c) 2015 Andreas Rumpf */$N" & "/* The generated code is subject to the original license. */$N", - "; Generated by Nim Compiler v$1$N" & - "; (c) 2012 Andreas Rumpf$N", [toRope(VersionAsString)]) + [toRope(VersionAsString)]) else: - result = ropeff("/* Generated by Nim Compiler v$1 */$N" & + result = ropef("/* Generated by Nim Compiler v$1 */$N" & "/* (c) 2015 Andreas Rumpf */$N" & "/* The generated code is subject to the original license. */$N" & "/* Compiled for: $2, $3, $4 */$N" & "/* Command for C compiler:$n $5 */$N", - "; Generated by Nim Compiler v$1$N" & - "; (c) 2015 Andreas Rumpf$N" & - "; Compiled for: $2, $3, $4$N" & - "; Command for LLVM compiler:$N $5$N", [toRope(VersionAsString), + [toRope(VersionAsString), toRope(platform.OS[targetOS].name), toRope(platform.CPU[targetCPU].name), toRope(extccomp.CC[extccomp.cCompiler].name), @@ -1014,13 +972,11 @@ proc registerModuleToMain(m: PSym) = var init = m.getInitName datInit = m.getDatInitName - appff(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", - "declare void $1() noinline$N", [init]) - appff(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", - "declare void $1() noinline$N", [datInit]) + appf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [init]) + appf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [datInit]) if sfSystemModule notin m.flags: - appff(mainDatInit, "\t$1();$N", "call void ()* $1$n", [datInit]) - let initCall = ropeff("\t$1();$N", "call void ()* $1$n", [init]) + appf(mainDatInit, "\t$1();$N", [datInit]) + let initCall = ropef("\t$1();$N", [init]) if sfMainModule in m.flags: app(mainModInit, initCall) else: @@ -1028,8 +984,7 @@ proc registerModuleToMain(m: PSym) = proc genInitCode(m: BModule) = var initname = getInitName(m.module) - var prc = ropeff("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", - "define void $1() noinline {$n", [initname]) + var prc = ropef("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", [initname]) if m.typeNodes > 0: appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n", [m.typeNodesName, toRope(m.typeNodes)]) @@ -1050,7 +1005,7 @@ proc genInitCode(m: BModule) = # declare it nevertheless: m.frameDeclared = true if not m.preventStackTrace: - var procname = cstringLit(m.initProc, prc, m.module.name.s) + var procname = makeCString(m.module.name.s) app(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename)) else: app(prc, ~"\tTFrame F; F.len = 0;$N") @@ -1071,8 +1026,8 @@ proc genInitCode(m: BModule) = app(prc, deinitGCFrame(m.initProc)) appf(prc, "}$N$N") - prc.appff("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", - "define void $1() noinline {$n", [getDatInitName(m.module)]) + prc.appf("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", + [getDatInitName(m.module)]) for i in cfsTypeInit1..cfsDynLibInit: app(prc, genSectionStart(i)) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 5761e9e880..26ca542391 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1209,6 +1209,7 @@ proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} = if x.typ.kind == tyVar and x.kind == nkSym and x.sym.kind == skResult: n.sons[0] = x # 'result[]' --> 'result' n.sons[1] = takeImplicitAddr(c, ri) + x.typ.flags.incl tfVarIsPtr template resultTypeIsInferrable(typ: PType): expr = typ.isMetaType and typ.kind != tyTypeDesc diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 5b7149d8e3..cce55bed7c 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -112,7 +112,7 @@ proc `[]`*(t: StringTableRef, key: string): string {.rtl, extern: "nstGet".} = proc mget*(t: StringTableRef, key: string): var string {. rtl, extern: "nstTake".} = ## retrieves the location at ``t[key]``. If `key` is not in `t`, the - ## ``EInvalidKey`` exception is raised. + ## ``KeyError`` exception is raised. var index = rawGet(t, key) if index >= 0: result = t.data[index].val else: raise newException(KeyError, "key does not exist: " & key) diff --git a/todo.txt b/todo.txt index d64f4fdd4a..17b8b3a212 100644 --- a/todo.txt +++ b/todo.txt @@ -25,7 +25,6 @@ Low priority: - support for exception propagation? (hard to implement) - the copying of the 'ref Promise' into the thead local storage only happens to work due to the write barrier's implementation -- clean up the C code generator. Full of cruft. Misc From d933fde40d1232004c9eaa260dc6bd3dc376c272 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 7 Feb 2015 02:15:50 +0100 Subject: [PATCH 061/250] yet another C++ bugfix --- compiler/semexprs.nim | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 26ca542391..eeada00063 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -578,11 +578,12 @@ proc skipObjConv(n: PNode): PNode = proc isAssignable(c: PContext, n: PNode): TAssignableResult = result = parampatterns.isAssignable(c.p.owner, n) -proc newHiddenAddrTaken(c: PContext, n: PNode): PNode = - if n.kind == nkHiddenDeref: +proc newHiddenAddrTaken(c: PContext, n: PNode): PNode = + if n.kind == nkHiddenDeref and not (gCmd == cmdCompileToCpp or + sfCompileToCpp in c.module.flags): checkSonsLen(n, 1) result = n.sons[0] - else: + else: result = newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ)) addSon(result, n) if isAssignable(c, n) notin {arLValue, arLocalLValue}: From 1314e91ef53c5ceb532b4113c92b90d84cd5c63b Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 7 Feb 2015 10:47:11 +0100 Subject: [PATCH 062/250] fixes c++ codegen regression --- compiler/ccgcalls.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 5e8bbc3351..b9fc694cba 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -303,7 +303,7 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): PRope = if x.typ.kind == tyPtr: result = genArgNoParam(p, x) result.app("->") - elif x.kind in {nkHiddenDeref, nkDerefExpr}: + elif x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].typ.kind == tyPtr: result = genArgNoParam(p, x[0]) result.app("->") else: From 0b5c42f4050da85905c25633573617b91cd05229 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 7 Feb 2015 12:55:23 +0100 Subject: [PATCH 063/250] configuration system supports %= to access environment variables --- compiler/commands.nim | 2 +- compiler/nimconf.nim | 24 +++++++++++++++--------- config/nim.cfg | 4 +++- lib/pure/strtabs.nim | 2 +- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 78fa9249c9..c81b81d191 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -52,7 +52,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) const HelpMessage = "Nim Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" & - "Copyright (c) 2006-2014 by Andreas Rumpf\n" + "Copyright (c) 2006-2015 by Andreas Rumpf\n" const Usage = slurp"doc/basicopt.txt".replace("//", "") diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index bcf9b53596..a433bf98e4 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -11,7 +11,7 @@ import llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer, - options, idents, wordrecg + options, idents, wordrecg, strtabs # ---------------- configuration file parser ----------------------------- # we use Nim's scanner here to safe space and work @@ -82,17 +82,17 @@ proc doElif(L: var TLexer, tok: var TToken) = proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) = var nestedIfs = 0 while true: - if (tok.ident != nil) and (tok.ident.s == "@"): + if tok.ident != nil and tok.ident.s == "@": ppGetTok(L, tok) case whichKeyword(tok.ident) of wIf: inc(nestedIfs) of wElse: - if (dest == jdElseEndif) and (nestedIfs == 0): + if dest == jdElseEndif and nestedIfs == 0: doElse(L, tok) break of wElif: - if (dest == jdElseEndif) and (nestedIfs == 0): + if dest == jdElseEndif and nestedIfs == 0: doElif(L, tok) break of wEnd: @@ -119,9 +119,10 @@ proc parseDirective(L: var TLexer, tok: var TToken) = of wElif: doElif(L, tok) of wElse: doElse(L, tok) of wEnd: doEnd(L, tok) - of wWrite: + of wWrite: ppGetTok(L, tok) - msgs.msgWriteln(tokToStr(tok)) + msgs.msgWriteln(strtabs.`%`(tokToStr(tok), options.gConfigVars, + {useEnvironment, useKey})) ppGetTok(L, tok) else: case tok.ident.s.normalize @@ -178,9 +179,10 @@ proc parseAssignment(L: var TLexer, tok: var TToken) = if tok.tokType == tkBracketRi: confTok(L, tok) else: lexMessage(L, errTokenExpected, "']'") add(val, ']') - if tok.tokType in {tkColon, tkEquals}: + let percent = tok.ident.id == getIdent("%=").id + if tok.tokType in {tkColon, tkEquals} or percent: if len(val) > 0: add(val, ':') - confTok(L, tok) # skip ':' or '=' + confTok(L, tok) # skip ':' or '=' or '%' checkSymbol(L, tok) add(val, tokToStr(tok)) confTok(L, tok) # skip symbol @@ -189,7 +191,11 @@ proc parseAssignment(L: var TLexer, tok: var TToken) = checkSymbol(L, tok) add(val, tokToStr(tok)) confTok(L, tok) - processSwitch(s, val, passPP, info) + if percent: + processSwitch(s, strtabs.`%`(val, options.gConfigVars, + {useEnvironment, useEmpty}), passPP, info) + else: + processSwitch(s, val, passPP, info) proc readConfigFile(filename: string) = var diff --git a/config/nim.cfg b/config/nim.cfg index 54c77e5734..e4ea43a599 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -5,7 +5,8 @@ # You may set environment variables with # @putenv "key" "val" -# Environment variables cannot be used in the options, however! +# Environment variables can be accessed like so: +# gcc.path %= "$CC_PATH" cc = gcc @@ -21,6 +22,7 @@ mips.linux.gcc.linkerexe = "mips-openwrt-linux-gcc" @end path="$lib/core" + path="$lib/pure" path="$lib/pure/collections" path="$lib/pure/concurrency" diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index cce55bed7c..727d5a386d 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -158,7 +158,7 @@ proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string = else: result = "" if result.len == 0: if useKey in flags: result = '$' & key - elif not (useEmpty in flags): raiseFormatException(key) + elif useEmpty notin flags: raiseFormatException(key) proc newStringTable*(mode: StringTableMode): StringTableRef {. rtl, extern: "nst$1".} = From dc85c2498b2d555125510fe91905cd1beffb6d10 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 7 Feb 2015 13:15:30 +0100 Subject: [PATCH 064/250] nimsuggest knows how to deal with files not belonging to the project --- compiler/msgs.nim | 7 ++++++- compiler/nimsuggest/nimsuggest.nim | 8 ++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 35a1217692..62e6d52817 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -522,7 +522,7 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo = if optEmbedOrigSrc in gGlobalOptions or true: result.lines = @[] -proc fileInfoIdx*(filename: string): int32 = +proc fileInfoIdx*(filename: string; isKnownFile: var bool): int32 = var canon: string pseudoPath = false @@ -539,11 +539,16 @@ proc fileInfoIdx*(filename: string): int32 = if filenameToIndexTbl.hasKey(canon): result = filenameToIndexTbl[canon] else: + isKnownFile = false result = fileInfos.len.int32 fileInfos.add(newFileInfo(canon, if pseudoPath: filename else: canon.shortenDir)) filenameToIndexTbl[canon] = result +proc fileInfoIdx*(filename: string): int32 = + var dummy: bool + result = fileInfoIdx(filename, dummy) + proc newLineInfo*(fileInfoIdx: int32, line, col: int): TLineInfo = result.fileIndex = fileInfoIdx result.line = int16(line) diff --git a/compiler/nimsuggest/nimsuggest.nim b/compiler/nimsuggest/nimsuggest.nim index 6edea06e59..cac0781270 100644 --- a/compiler/nimsuggest/nimsuggest.nim +++ b/compiler/nimsuggest/nimsuggest.nim @@ -87,8 +87,9 @@ proc action(cmd: string) = i += skipWhile(cmd, seps, i) i += parseInt(cmd, col, i) + var isKnownFile = true if orig.len == 0: err() - let dirtyIdx = orig.fileInfoIdx + let dirtyIdx = orig.fileInfoIdx(isKnownFile) if dirtyfile.len != 0: msgs.setDirtyFile(dirtyIdx, dirtyfile) else: msgs.setDirtyFile(dirtyIdx, nil) @@ -99,7 +100,10 @@ proc action(cmd: string) = gTrackPos = newLineInfo(dirtyIdx, line, col) #echo dirtyfile, gDirtyBufferIdx, " project ", gProjectMainIdx gErrorCounter = 0 - compileProject() + if not isKnownFile: + compileProject(dirtyIdx) + else: + compileProject() proc serve() = # do not stop after the first error: From 42f8f1cd1fe491c19362a4b03f89952ea6e160bc Mon Sep 17 00:00:00 2001 From: Charles Blake Date: Sat, 7 Feb 2015 09:37:17 -0500 Subject: [PATCH 065/250] Fix unnecessarily slow set building from openArray. The estimation of the initialSize as simply array len + 10 was too small for for all but the smallest sets. It would not elide/skip one final enlarge(). That last one is actually always the most expensive enlarge(). Indeed, in a series where one to start from tiny and build up the table..that last one is about 50% of all the enlarging time in general. So, this simple and reasonable optimization (compared to just starting at 64) was only helping about half as much as it could. Introduce a rightSize() proc to be the inverse to mustRehash(). Export it to clients since pre-sizing is externally useful in set construction and the current mustRehash rules are opaque and beyond the control of clients. Also add test module logic to check that rightSize() and mustRehash() are inverses in the appropriate sense..not really in a block/assertion throwing unit test since this is a peformance nice-to-have issue rather than about basic correctness. (Also, fix a too vs. two typo in doc comment.) --- lib/pure/collections/sets.nim | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 72fd5cd811..3e462f73fa 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -114,6 +114,15 @@ proc mustRehash(length, counter: int): bool {.inline.} = assert(length > counter) result = (length * 2 < counter * 3) or (length - counter < 4) +proc rightSize*(count: int): int {.inline.} = + ## Return the value of `initialSize` to support `count` items. + ## + ## If more items are expected to be added, simply add that + ## expected extra amount to the parameter before calling this. + ## + ## Internally, we want mustRehash(rightSize(x), x) == false. + result = nextPowerOfTwo(count * 3 div 2 + 4) + proc nextTry(h, maxHash: THash): THash {.inline.} = result = (h + 1) and maxHash @@ -343,7 +352,7 @@ proc toSet*[A](keys: openArray[A]): HashSet[A] = ## var numbers = toSet([1, 2, 3, 4, 5]) ## assert numbers.contains(2) ## assert numbers.contains(4) - result = initSet[A](nextPowerOfTwo(keys.len+10)) + result = initSet[A](rightSize(keys.len)) for key in items(keys): result.incl(key) template dollarImpl(): stmt {.dirty.} = @@ -708,7 +717,7 @@ proc containsOrIncl*[A](s: var OrderedSet[A], key: A): bool = proc init*[A](s: var OrderedSet[A], initialSize=64) = ## Initializes an ordered hash set. ## - ## The `initialSize` parameter needs to be a power of too. You can use + ## The `initialSize` parameter needs to be a power of two. You can use ## `math.nextPowerOfTwo() `_ to guarantee that at ## runtime. All set variables have to be initialized before you can use them ## with other procs from this module with the exception of `isValid() @@ -751,7 +760,7 @@ proc toOrderedSet*[A](keys: openArray[A]): OrderedSet[A] = ## var numbers = toOrderedSet([1, 2, 3, 4, 5]) ## assert numbers.contains(2) ## assert numbers.contains(4) - result = initOrderedSet[A](nextPowerOfTwo(keys.len+10)) + result = initOrderedSet[A](rightSize(keys.len)) for key in items(keys): result.incl(key) proc `$`*[A](s: OrderedSet[A]): string = @@ -954,6 +963,11 @@ proc testModule() = b.incl(2) assert b.len == 1 + for i in 0 .. 32: + var s = rightSize(i) + if s <= i or mustRehash(s, i): + echo "performance issue: rightSize() will not elide enlarge() at ", i + echo "Micro tests run successfully." when isMainModule and not defined(release): testModule() From 1f3ce26421f73916aa978c67ab90cdf68218120d Mon Sep 17 00:00:00 2001 From: Charles Blake Date: Sat, 7 Feb 2015 13:13:03 -0500 Subject: [PATCH 066/250] Address Andreas' complaint about code duplication. --- lib/pure/collections/sets.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 3e462f73fa..33fec1a186 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -246,8 +246,9 @@ proc incl*[A](s: var HashSet[A], other: HashSet[A]) = for item in other: incl(s, item) template doWhile(a: expr, b: stmt): stmt = - b - while a: b + while true: + b + if not a: break proc excl*[A](s: var HashSet[A], key: A) = ## Excludes `key` from the set `s`. From 7ca3353616758c61ecf6e1746b6b4534fb8e6f30 Mon Sep 17 00:00:00 2001 From: Flaviu Tamas Date: Sat, 7 Feb 2015 13:12:28 -0500 Subject: [PATCH 067/250] Clarify "instantiation from here" After ~1 year of Nim, I finally realized it doesn't refer to dynamic memory --- compiler/msgs.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index b58561d30b..923c351703 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -311,7 +311,7 @@ const errXOnlyAtModuleScope: "\'$1\' is only allowed at top level", errXNeedsParamObjectType: "'$1' needs a parameter that has an object type", errTemplateInstantiationTooNested: "template/macro instantiation too nested", - errInstantiationFrom: "instantiation from here", + errInstantiationFrom: "template/generic instantiation from here", errInvalidIndexValueForTuple: "invalid index value for tuple subscript", errCommandExpectsFilename: "command expects a filename argument", errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file", From 52d3a82396dc515778deb2e8cf72b1749bd343c7 Mon Sep 17 00:00:00 2001 From: Flaviu Tamas Date: Sat, 7 Feb 2015 16:06:50 -0500 Subject: [PATCH 068/250] Clean up build icons --- readme.md | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/readme.md b/readme.md index d5968982b3..b08fa22914 100644 --- a/readme.md +++ b/readme.md @@ -66,8 +66,24 @@ Copyright (c) 2006-2014 Andreas Rumpf. All rights reserved. # Build Status -| |Linux|Windows|Mac| -|---|---|---|---| -| x86 | ![](http://178.62.143.63:8010/buildstatusimage?builder=linux-x32-builder) | ![](http://178.62.143.63:8010/buildstatusimage?builder=windows-x32-builder) | ![](http://178.62.143.63:8010/buildstatusimage?builder=mac-x32-builder) -| x86_64 | ![](http://178.62.143.63:8010/buildstatusimage?builder=linux-x64-builder) | ![](http://178.62.143.63:8010/buildstatusimage?builder=windows-x64-builder) | ![](http://178.62.143.63:8010/buildstatusimage?builder=mac-x64-builder) -| arm | ![](http://178.62.143.63:8010/buildstatusimage?builder=linux-arm5-builder) | +[**Build Waterfall**][waterfall] + +| | Linux | Windows | Mac | +| ------ | ----- | ------- | --- | +| x86 | ![linux-x86][linux-x86-img] | ![windows-x86][windows-x86-img] | ![mac-x86][mac-x86-img] | +| x86_64 | ![linux-x86_64][linux-x86_64-img] | ![windows-x86_64][windows-x86_64-img] | ![mac-x86_64][mac-x86_64-img] | +| arm | ![linux-armv5][linux-arm5-img]
![linux-armv6][linux-arm6-img]
![linux-armv7][linux-arm7-img] | | | + +[linux-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x32-builder +[linux-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x64-builder +[linux-arm5-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm5-builder +[linux-arm6-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm6-builder +[linux-arm7-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm7-builder + +[windows-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x32-builder +[windows-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x64-builder + +[mac-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=mac-x32-builder +[mac-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=mac-x64-builder + +[waterfall]: http://buildbot.nim-lang.org/waterfall From 0b2a63b7bdb5d79cdef2a01aa3100a22a5b13ebc Mon Sep 17 00:00:00 2001 From: PhilipWitte Date: Sun, 8 Feb 2015 04:01:18 -0800 Subject: [PATCH 069/250] Fixed website banner HTML & Javascript Various website CSS improvements Added docs & learn icons Added learn articles --- tools/website.tmpl | 162 +++++++++++---------------- web/assets/images/docs-articles.png | Bin 0 -> 381 bytes web/assets/images/docs-examples.png | Bin 0 -> 596 bytes web/assets/images/docs-internals.png | Bin 0 -> 621 bytes web/assets/images/docs-libraries.png | Bin 0 -> 335 bytes web/assets/images/docs-tools.png | Bin 0 -> 636 bytes web/assets/images/docs-tutorials.png | Bin 0 -> 560 bytes web/assets/index.js | 34 ++++++ web/assets/style.css | 126 +++++++-------------- web/documentation.txt | 57 ++++++---- web/learn.txt | 54 ++++++--- 11 files changed, 220 insertions(+), 213 deletions(-) create mode 100644 web/assets/images/docs-articles.png create mode 100644 web/assets/images/docs-examples.png create mode 100644 web/assets/images/docs-internals.png create mode 100644 web/assets/images/docs-libraries.png create mode 100644 web/assets/images/docs-tools.png create mode 100644 web/assets/images/docs-tutorials.png create mode 100644 web/assets/index.js diff --git a/tools/website.tmpl b/tools/website.tmpl index e1fdf67012..6dce93d147 100644 --- a/tools/website.tmpl +++ b/tools/website.tmpl @@ -7,7 +7,6 @@ $c.projectTitle - #if len(rss) > 0: @@ -17,23 +16,23 @@