From 72dbd12ca43682318ea16153980a0a2bdc602b92 Mon Sep 17 00:00:00 2001 From: def Date: Wed, 23 Jul 2014 16:32:20 +0200 Subject: [PATCH 01/23] Add count procedures to strutils --- lib/pure/strutils.nim | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 6f8924d83b..acb803a4c0 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -803,6 +803,44 @@ proc rfind*(s, sub: string, start: int = -1): int {.noSideEffect.} = if result != -1: return return -1 +proc count*(s: string, sub: string): int {.noSideEffect, + rtl, extern: "nsuCountString".} = + ## Count the occurences of a substring `sub` in the string `s`. Overlapping + ## occurences of `sub` do not count. + var i = 0 + while true: + i = s.find(sub, i) + if i < 0: + break + i += sub.len + inc result + +proc count*(s: string, sub: char): int {.noSideEffect, + rtl, extern: "nsuCountChar".} = + ## Count the occurences of the character `sub` in the string `s`. + for c in s: + if c == sub: + inc result + +proc count*(s: string, subs: set[char]): int {.noSideEffect, + rtl, extern: "nsuCountCharSet".} = + ## Count the occurences of the group of character `subs` in the string `s`. + for c in s: + if c in subs: + inc result + +proc countOverlapping*(s: string, sub: string): int {.noSideEffect, + rtl, extern: "nsuCountOverlapping".} = + ## Count the occurences of a substring `sub` in the string `s`. Overlapping + ## occurences of `sub` do count. + var i = 0 + while true: + i = s.find(sub, i) + if i < 0: + break + inc i + inc result + proc quoteIfContainsWhite*(s: string): string {.deprecated.} = ## Returns ``'"' & s & '"'`` if `s` contains a space and does not ## start with a quote, else returns `s`. @@ -1354,3 +1392,8 @@ when isMainModule: doAssert parseEnum[TMyEnum]("enu_D") == enuD doAssert parseEnum("invalid enum value", enC) == enC + + doAssert count("foofoofoo", "foofoo") == 1 + doAssert countOverlapping("foofoofoo", "foofoo") == 2 + doAssert count("foofoofoo", 'f') == 3 + doAssert count("foofoofoobar", {'f','b'}) == 4 From c78b1070a8dec61ae6aa660fe724bf9fb67fb6a9 Mon Sep 17 00:00:00 2001 From: def Date: Mon, 28 Jul 2014 16:48:07 +0200 Subject: [PATCH 02/23] overlapping as a parameter for count instead --- lib/pure/strutils.nim | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index acb803a4c0..1d17de2338 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -803,16 +803,20 @@ proc rfind*(s, sub: string, start: int = -1): int {.noSideEffect.} = if result != -1: return return -1 -proc count*(s: string, sub: string): int {.noSideEffect, +proc count*(s: string, sub: string, overlapping: bool = false): int {.noSideEffect, rtl, extern: "nsuCountString".} = - ## Count the occurences of a substring `sub` in the string `s`. Overlapping - ## occurences of `sub` do not count. + ## Count the occurences of a substring `sub` in the string `s`. + ## Overlapping occurences of `sub` only count when `overlapping` + ## is set to true. var i = 0 while true: i = s.find(sub, i) if i < 0: break - i += sub.len + if overlapping: + inc i + else: + i += sub.len inc result proc count*(s: string, sub: char): int {.noSideEffect, @@ -829,18 +833,6 @@ proc count*(s: string, subs: set[char]): int {.noSideEffect, if c in subs: inc result -proc countOverlapping*(s: string, sub: string): int {.noSideEffect, - rtl, extern: "nsuCountOverlapping".} = - ## Count the occurences of a substring `sub` in the string `s`. Overlapping - ## occurences of `sub` do count. - var i = 0 - while true: - i = s.find(sub, i) - if i < 0: - break - inc i - inc result - proc quoteIfContainsWhite*(s: string): string {.deprecated.} = ## Returns ``'"' & s & '"'`` if `s` contains a space and does not ## start with a quote, else returns `s`. @@ -1394,6 +1386,6 @@ when isMainModule: doAssert parseEnum("invalid enum value", enC) == enC doAssert count("foofoofoo", "foofoo") == 1 - doAssert countOverlapping("foofoofoo", "foofoo") == 2 + doAssert count("foofoofoo", "foofoo", overlapping = true) == 2 doAssert count("foofoofoo", 'f') == 3 doAssert count("foofoofoobar", {'f','b'}) == 4 From 278c265c6fe1a3bc9f1fb3c4895d3108134b8294 Mon Sep 17 00:00:00 2001 From: Grzegorz Adam Hankiewicz Date: Wed, 6 Aug 2014 21:19:20 +0200 Subject: [PATCH 03/23] Parallelizes documentation building. --- tools/nimweb.nim | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/tools/nimweb.nim b/tools/nimweb.nim index 9a83a5ccaa..d3c6d3fcd3 100644 --- a/tools/nimweb.nim +++ b/tools/nimweb.nim @@ -215,6 +215,11 @@ proc exec(cmd: string) = echo(cmd) if os.execShellCmd(cmd) != 0: quit("external program failed") +proc mexec(cmds: openarray[string]) = + ## Multiprocessor version of exec + if 0 != execProcesses(cmds, {poStdErrToStdOut, poParentStreams, poEchoCmd}): + quit("external program failed") + proc buildDocSamples(c: var TConfigData, destPath: string) = ## Special case documentation sample proc. ## @@ -229,18 +234,26 @@ proc buildDocSamples(c: var TConfigData, destPath: string) = proc buildDoc(c: var TConfigData, destPath: string) = # call nim for the documentation: + var + commands = newSeq[string](len(c.doc) + len(c.srcdoc) + len(c.srcdoc2)) + i = 0 for d in items(c.doc): - exec("nimrod rst2html $# --docSeeSrcUrl:$# -o:$# --index:on $#" % + commands[i] = "nimrod rst2html $# --docSeeSrcUrl:$# -o:$# --index:on $#" % [c.nimrodArgs, c.gitCommit, - destPath / changeFileExt(splitFile(d).name, "html"), d]) + destPath / changeFileExt(splitFile(d).name, "html"), d] + i.inc for d in items(c.srcdoc): - exec("nimrod doc $# --docSeeSrcUrl:$# -o:$# --index:on $#" % + commands[i] = "nimrod doc $# --docSeeSrcUrl:$# -o:$# --index:on $#" % [c.nimrodArgs, c.gitCommit, - destPath / changeFileExt(splitFile(d).name, "html"), d]) + destPath / changeFileExt(splitFile(d).name, "html"), d] + i.inc for d in items(c.srcdoc2): - exec("nimrod doc2 $# --docSeeSrcUrl:$# -o:$# --index:on $#" % + commands[i] = "nimrod doc2 $# --docSeeSrcUrl:$# -o:$# --index:on $#" % [c.nimrodArgs, c.gitCommit, - destPath / changeFileExt(splitFile(d).name, "html"), d]) + destPath / changeFileExt(splitFile(d).name, "html"), d] + i.inc + + mexec(commands) exec("nimrod buildIndex -o:$1/theindex.html $1" % [destPath]) proc buildPdfDoc(c: var TConfigData, destPath: string) = @@ -264,10 +277,12 @@ proc buildPdfDoc(c: var TConfigData, destPath: string) = proc buildAddDoc(c: var TConfigData, destPath: string) = # build additional documentation (without the index): - for d in items(c.webdoc): - exec("nimrod doc $# --docSeeSrcUrl:$# -o:$# $#" % + var commands = newSeq[string](c.webdoc.len) + for i, doc in pairs(c.webdoc): + commands[i] = "nimrod doc $# --docSeeSrcUrl:$# -o:$# $#" % [c.nimrodArgs, c.gitCommit, - destPath / changeFileExt(splitFile(d).name, "html"), d]) + destPath / changeFileExt(splitFile(doc).name, "html"), doc] + mexec(commands) proc parseNewsTitles(inputFilename: string): seq[TRssItem] = # parses the file for titles and returns them as TRssItem blocks. From bab41babeafc69a14f757f55e9a876315089f1e7 Mon Sep 17 00:00:00 2001 From: Grzegorz Adam Hankiewicz Date: Fri, 8 Aug 2014 02:21:13 +0200 Subject: [PATCH 04/23] Adds --parallelBuild to koch web and automatic reruns. Refs #1455. --- doc/koch.txt | 7 +++++++ tools/nimweb.nim | 31 +++++++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/doc/koch.txt b/doc/koch.txt index 0321518081..7be2be6d46 100644 --- a/doc/koch.txt +++ b/doc/koch.txt @@ -138,6 +138,13 @@ from rst to HTML. It also repeats the same operation but places the result in the ``web/upload`` which can be used to update the website at http://nimrod-lang.org. +By default the documentation will be built in parallel using the number of +available CPU cores. If any documentation build sub commands fail, they will +be rerun in serial fashion so that meaninful error output can be gathered for +inspection. The ``--parallelBuild:n`` switch or configuration option can be +used to force a specific number of parallel jobs or run everything serially +from the start (``n == 1``). + zip command ----------- diff --git a/tools/nimweb.nim b/tools/nimweb.nim index d3c6d3fcd3..d76c5e354a 100644 --- a/tools/nimweb.nim +++ b/tools/nimweb.nim @@ -21,6 +21,7 @@ type nimrodArgs: string gitCommit: string quotations: TTable[string, tuple[quote, author: string]] + numProcessors: int # Set by parallelBuild:n, only works for values > 0. TRssItem = object year, month, day, title: string @@ -42,6 +43,7 @@ proc initConfigData(c: var TConfigData) = c.ticker = "" c.vars = newStringTable(modeStyleInsensitive) c.gitCommit = "master" + c.numProcessors = countProcessors() # Attempts to obtain the git current commit. let (output, code) = execCmdEx("git log -n 1 --format=%H") if code == 0 and output.strip.len == 40: @@ -121,6 +123,12 @@ proc parseCmdLine(c: var TConfigData) = stdout.write(Version & "\n") quit(0) of "o", "output": c.outdir = val + of "parallelbuild": + try: + let num = parseInt(val) + if num != 0: c.numProcessors = num + except EInvalidValue: + quit("invalid numeric value for --parallelBuild") of "var": var idx = val.find('=') if idx < 0: quit("invalid command line") @@ -187,6 +195,12 @@ proc parseIniFile(c: var TConfigData) = of "srcdoc": addFiles(c.srcdoc, "lib", ".nim", split(v, {';'})) of "srcdoc2": addFiles(c.srcdoc2, "lib", ".nim", split(v, {';'})) of "webdoc": addFiles(c.webdoc, "lib", ".nim", split(v, {';'})) + of "parallelbuild": + try: + let num = parseInt(v) + if num != 0: c.numProcessors = num + except EInvalidValue: + quit("invalid numeric value for --parallelBuild in config") else: quit(errorStr(p, "unknown variable: " & k.key)) of "quotations": let vSplit = v.split('-') @@ -215,10 +229,19 @@ proc exec(cmd: string) = echo(cmd) if os.execShellCmd(cmd) != 0: quit("external program failed") -proc mexec(cmds: openarray[string]) = +proc sexec(cmds: openarray[string]) = + ## Serial queue wrapper around exec. + for cmd in cmds: exec(cmd) + +proc mexec(cmds: openarray[string], processors: int) = ## Multiprocessor version of exec + if processors < 2: + sexec(cmds) + return + if 0 != execProcesses(cmds, {poStdErrToStdOut, poParentStreams, poEchoCmd}): - quit("external program failed") + echo "external program failed, retrying serial work queue for logs!" + sexec(cmds) proc buildDocSamples(c: var TConfigData, destPath: string) = ## Special case documentation sample proc. @@ -253,7 +276,7 @@ proc buildDoc(c: var TConfigData, destPath: string) = destPath / changeFileExt(splitFile(d).name, "html"), d] i.inc - mexec(commands) + mexec(commands, c.numProcessors) exec("nimrod buildIndex -o:$1/theindex.html $1" % [destPath]) proc buildPdfDoc(c: var TConfigData, destPath: string) = @@ -282,7 +305,7 @@ proc buildAddDoc(c: var TConfigData, destPath: string) = commands[i] = "nimrod doc $# --docSeeSrcUrl:$# -o:$# $#" % [c.nimrodArgs, c.gitCommit, destPath / changeFileExt(splitFile(doc).name, "html"), doc] - mexec(commands) + mexec(commands, c.numProcessors) proc parseNewsTitles(inputFilename: string): seq[TRssItem] = # parses the file for titles and returns them as TRssItem blocks. From 7dac395cb2689b2e529b6e0b9507f2529dc125bb Mon Sep 17 00:00:00 2001 From: Erwan Ameil Date: Sat, 30 Aug 2014 20:42:40 +0200 Subject: [PATCH 05/23] Remove outdated ZeroMQ example (zmq has been moved out of the stdlib) --- examples/0mq/client.nim | 14 -------------- examples/0mq/server.nim | 11 ----------- 2 files changed, 25 deletions(-) delete mode 100644 examples/0mq/client.nim delete mode 100644 examples/0mq/server.nim diff --git a/examples/0mq/client.nim b/examples/0mq/client.nim deleted file mode 100644 index e75e5c7a2d..0000000000 --- a/examples/0mq/client.nim +++ /dev/null @@ -1,14 +0,0 @@ -import zmq - -var connection = zmq.open("tcp://localhost:5555", server=false) - -echo("Connecting...") - -for i in 0..10: - echo("Sending hello...", i) - send(connection, "Hello") - - var reply = receive(connection) - echo("Received ...", reply) - -close(connection) diff --git a/examples/0mq/server.nim b/examples/0mq/server.nim deleted file mode 100644 index 0fadf8b97f..0000000000 --- a/examples/0mq/server.nim +++ /dev/null @@ -1,11 +0,0 @@ -import zmq - -var connection = zmq.open("tcp://*:5555", server=true) - -while True: - var request = receive(connection) - echo("Received: ", request) - send(connection, "World") - -close(connection) - From a249a12da7d1868176788e3bc1627f76aa9977e8 Mon Sep 17 00:00:00 2001 From: Erwan Ameil Date: Sat, 30 Aug 2014 21:38:47 +0200 Subject: [PATCH 06/23] Secure and HttpOnly cookies --- lib/pure/cookies.nim | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim index d1cf36a871..49bf929807 100644 --- a/lib/pure/cookies.nim +++ b/lib/pure/cookies.nim @@ -28,8 +28,9 @@ proc parseCookies*(s: string): PStringTable = if s[i] == '\0': break inc(i) # skip ';' -proc setCookie*(key, value: string, domain = "", path = "", - expires = "", noName = false): string = +proc setCookie*(key, value: string, domain = "", path = "", + expires = "", noName = false, + secure = false, httpOnly = false): string = ## Creates a command in the format of ## ``Set-Cookie: key=value; Domain=...; ...`` result = "" @@ -38,16 +39,20 @@ proc setCookie*(key, value: string, domain = "", path = "", if domain != "": result.add("; Domain=" & domain) if path != "": result.add("; Path=" & path) if expires != "": result.add("; Expires=" & expires) + if secure: result.add("; secure") + if httpOnly: result.add("; HttpOnly") proc setCookie*(key, value: string, expires: TTimeInfo, - domain = "", path = "", noName = false): string = + domain = "", path = "", noName = false, + secure = false, httpOnly = false): string = ## Creates a command in the format of ## ``Set-Cookie: key=value; Domain=...; ...`` ## ## **Note:** UTC is assumed as the timezone for ``expires``. return setCookie(key, value, domain, path, - format(expires, "ddd',' dd MMM yyyy HH:mm:ss 'UTC'"), noname) + format(expires, "ddd',' dd MMM yyyy HH:mm:ss 'UTC'"), + noname, secure, httpOnly) when isMainModule: var tim = TTime(int(getTime()) + 76 * (60 * 60 * 24)) @@ -55,5 +60,3 @@ when isMainModule: echo(setCookie("test", "value", tim.getGMTime())) echo parseCookies("uid=1; kp=2") - - \ No newline at end of file From 05c1fb060fce7402541f625fe1dabb6ed30b6d48 Mon Sep 17 00:00:00 2001 From: Erwan Ameil Date: Sat, 30 Aug 2014 22:21:38 +0200 Subject: [PATCH 07/23] Escape ' and / when using escape in xmltree --- lib/pure/xmltree.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index 95b48a850d..1af7db7d55 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -151,6 +151,8 @@ proc addEscaped*(result: var string, s: string) = of '>': result.add(">") of '&': result.add("&") of '"': result.add(""") + of '\'': result.add("'") + of '/': result.add("/") else: result.add(c) proc escape*(s: string): string = @@ -164,6 +166,8 @@ proc escape*(s: string): string = ## ``>`` ``>`` ## ``&`` ``&`` ## ``"`` ``"`` + ## ``'`` ``'`` + ## ``/`` ``/`` ## ------------ ------------------- result = newStringOfCap(s.len) addEscaped(result, s) From 10f6a11cf22ac4be35eb8119b654124f2b58c45f Mon Sep 17 00:00:00 2001 From: fuzzthink Date: Tue, 2 Sep 2014 10:10:18 +0900 Subject: [PATCH 08/23] Pointer -> pointer to fix compile error using --cs:partial --- lib/system/jssys.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 8766906e3a..423f63e2a8 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -515,7 +515,7 @@ proc isFatPointer(ti: PNimType): bool = proc nimCopy(x: pointer, ti: PNimType): pointer {.compilerproc.} -proc nimCopyAux(dest, src: Pointer, n: ptr TNimNode) {.compilerproc.} = +proc nimCopyAux(dest, src: pointer, n: ptr TNimNode) {.compilerproc.} = case n.kind of nkNone: sysAssert(false, "nimCopyAux") of nkSlot: @@ -566,7 +566,7 @@ proc nimCopy(x: pointer, ti: PNimType): pointer = else: result = x -proc genericReset(x: Pointer, ti: PNimType): pointer {.compilerproc.} = +proc genericReset(x: pointer, ti: PNimType): pointer {.compilerproc.} = case ti.kind of tyPtr, tyRef, tyVar, tyNil: if not isFatPointer(ti): From f9c46b04a61c2ea1362b33e69c6e211f2d225354 Mon Sep 17 00:00:00 2001 From: Reimer Behrends Date: Wed, 10 Sep 2014 01:22:20 +0200 Subject: [PATCH 09/23] Properly handle staticExec() generating large output. A staticExec() invocation that generated more than the internal buffer size worth of output blocked because the compiler waited for the process to terminate before reading the output. --- compiler/vmdeps.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 9a213d8133..fdd8276cc3 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -12,11 +12,11 @@ import ast, types, msgs, osproc, streams, options proc readOutput(p: PProcess): string = result = "" var output = p.outputStream - discard p.waitForExit while not output.atEnd: result.add(output.readLine) result.add("\n") result.setLen(result.len - "\n".len) + discard p.waitForExit proc opGorge*(cmd, input: string): string = var p = startCmd(cmd) From 2c99991d169d66d5fd2334cfc783761d1ffe25bc Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 11 Sep 2014 00:34:59 +0200 Subject: [PATCH 10/23] fixes #1444 --- compiler/semgnrc.nim | 16 ++-- config/nim.cfg | 139 ++++++++++++++++++++++++++++++++++ lib/pure/collections/sets.nim | 2 +- lib/system.nim | 4 +- tests/generics/mdotlookup.nim | 8 ++ tests/generics/tdotlookup.nim | 5 +- 6 files changed, 165 insertions(+), 9 deletions(-) create mode 100644 config/nim.cfg diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 934434951c..a004d14659 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -36,10 +36,11 @@ proc semGenericStmtScope(c: PContext, n: PNode, template macroToExpand(s: expr): expr = s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfImmediate in s.flags) -proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode = +proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, + ctx: var TIntSet): PNode = incl(s.flags, sfUsed) case s.kind - of skUnknown: + of skUnknown: # Introduced in this pass! Leave it as an identifier. result = n of skProc, skMethod, skIterators, skConverter: @@ -48,11 +49,13 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode = if macroToExpand(s): let n = fixImmediateParams(n) result = semTemplateExpr(c, n, s, {efNoSemCheck}) + result = semGenericStmt(c, result, {}, ctx) else: result = symChoice(c, n, s, scOpen) of skMacro: if macroToExpand(s): result = semMacroExpr(c, n, n, s, {efNoSemCheck}) + result = semGenericStmt(c, result, {}, ctx) else: result = symChoice(c, n, s, scOpen) of skGenericParam: @@ -80,7 +83,7 @@ proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags, elif s.name.id in ctx: result = symChoice(c, n, s, scForceOpen) else: - result = semGenericStmtSymbol(c, n, s) + result = semGenericStmtSymbol(c, n, s, ctx) # else: leave as nkIdent proc newDot(n, b: PNode): PNode = @@ -95,8 +98,9 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, var s = qualifiedLookUp(c, n, luf) if s != nil: - result = semGenericStmtSymbol(c, n, s) + result = semGenericStmtSymbol(c, n, s, ctx) else: + n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx) result = n let n = n[1] let ident = considerQuotedIdent(n) @@ -107,7 +111,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, elif s.name.id in ctx: result = newDot(result, symChoice(c, n, s, scForceOpen)) else: - let sym = semGenericStmtSymbol(c, n, s) + let sym = semGenericStmtSymbol(c, n, s, ctx) if sym.kind == nkSym: result = newDot(result, symChoice(c, n, s, scForceOpen)) else: @@ -158,6 +162,7 @@ proc semGenericStmt(c: PContext, n: PNode, of skMacro: if macroToExpand(s): result = semMacroExpr(c, n, n, s, {efNoSemCheck}) + result = semGenericStmt(c, result, {}, ctx) else: n.sons[0] = symChoice(c, n.sons[0], s, scOption) result = n @@ -165,6 +170,7 @@ proc semGenericStmt(c: PContext, n: PNode, if macroToExpand(s): let n = fixImmediateParams(n) result = semTemplateExpr(c, n, s, {efNoSemCheck}) + result = semGenericStmt(c, result, {}, ctx) else: n.sons[0] = symChoice(c, n.sons[0], s, scOption) result = n diff --git a/config/nim.cfg b/config/nim.cfg new file mode 100644 index 0000000000..df3835ace7 --- /dev/null +++ b/config/nim.cfg @@ -0,0 +1,139 @@ +# Configuration file for the Nimrod Compiler. +# (c) 2013 Andreas Rumpf + +# Feel free to edit the default values as you need. + +# You may set environment variables with +# @putenv "key" "val" +# Environment variables cannot be used in the options, however! + +cc = gcc + +# example of how to setup a cross-compiler: +arm.linux.gcc.exe = "arm-linux-gcc" +arm.linux.gcc.linkerexe = "arm-linux-gcc" + +path="$lib/core" +path="$lib/pure" +path="$lib/pure/collections" +path="$lib/pure/concurrency" +path="$lib/impure" +path="$lib/wrappers" +# path="$lib/wrappers/cairo" +# path="$lib/wrappers/gtk" +# path="$lib/wrappers/lua" +# path="$lib/wrappers/opengl" +path="$lib/wrappers/pcre" +path="$lib/wrappers/readline" +path="$lib/wrappers/sdl" +# path="$lib/wrappers/x11" +path="$lib/wrappers/zip" +path="$lib/wrappers/libffi" +path="$lib/windows" +path="$lib/posix" +path="$lib/js" +path="$lib/pure/unidecode" + +@if nimbabel: + babelpath="$home/.babel/pkgs/" +@end + +@if release or quick: + obj_checks:off + field_checks:off + range_checks:off + bound_checks:off + overflow_checks:off + assertions:off + stacktrace:off + linetrace:off + debugger:off + line_dir:off + dead_code_elim:on +@end + +@if release: + opt:speed +@end + +# additional options always passed to the compiler: +--parallel_build: "0" # 0 to auto-detect number of processors + +hint[LineTooLong]=off +#hint[XDeclaredButNotUsed]=off + +@if unix: + @if not bsd: + # -fopenmp + gcc.options.linker = "-ldl" + gpp.options.linker = "-ldl" + clang.options.linker = "-ldl" + tcc.options.linker = "-ldl" + @end + @if bsd or haiku: + # BSD got posix_spawn only recently, so we deactivate it for osproc: + define:useFork + # at least NetBSD has problems with thread local storage: + tlsEmulation:on + @end +@end + +# Configuration for the Intel C/C++ compiler: +@if windows: + icl.options.speed = "/Ox /arch:SSE2" + icl.options.always = "/nologo" +@end + +# Configuration for the GNU C/C++ compiler: +@if windows: + #gcc.path = r"$nimrod\dist\mingw\bin" + @if gcc: + tlsEmulation:on + @end +@end + +@if macosx: + cc = clang + tlsEmulation:on + gcc.options.always = "-w -fasm-blocks" + gpp.options.always = "-w -fasm-blocks -fpermissive" +@else: + gcc.options.always = "-w" + gpp.options.always = "-w -fpermissive" +@end + +gcc.options.speed = "-O3 -fno-strict-aliasing" +gcc.options.size = "-Os" +gcc.options.debug = "-g3 -O0" + +gpp.options.speed = "-O3 -fno-strict-aliasing" +gpp.options.size = "-Os" +gpp.options.debug = "-g3 -O0" +#passl = "-pg" + +# Configuration for the LLVM GCC compiler: +llvm_gcc.options.debug = "-g" +llvm_gcc.options.always = "-w" +llvm_gcc.options.speed = "-O2" +llvm_gcc.options.size = "-Os" + +# Configuration for the LLVM CLang compiler: +clang.options.debug = "-g" +clang.options.always = "-w" +clang.options.speed = "-O3" +clang.options.size = "-Os" + +# Configuration for the Visual C/C++ compiler: +vcc.options.linker = "/DEBUG /Zi /Fd\"$projectName.pdb\" /F33554432" # set the stack size to 8 MB +vcc.options.debug = "/Zi /Fd\"$projectName.pdb\"" +vcc.options.always = "/nologo" +vcc.options.speed = "/Ox /arch:SSE2" +vcc.options.size = "/O1" + +# Configuration for the Digital Mars C/C++ compiler: +@if windows: + dmc.path = r"$nimrod\dist\dm\bin" +@end + +# Configuration for the Tiny C Compiler: +tcc.options.always = "-w" diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 22eff9c557..ce901963e7 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -128,7 +128,7 @@ proc mget*[A](s: var TSet[A], key: A): var A = ## for sharing. assert s.isValid, "The set needs to be initialized." var index = rawGet(s, key) - if index >= 0: result = t.data[index].key + if index >= 0: result = s.data[index].key else: raise newException(EInvalidKey, "key not found: " & $key) proc contains*[A](s: TSet[A], key: A): bool = diff --git a/lib/system.nim b/lib/system.nim index 0d8f63bd48..0df8849f5a 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -849,13 +849,13 @@ proc contains*[T](s: TSlice[T], value: T): bool {.noSideEffect, inline.} = ## assert((1..3).contains(4) == false) result = s.a <= value and value <= s.b -template `in` * (x, y: expr): expr {.immediate.} = contains(y, x) +template `in` * (x, y: expr): expr {.immediate, dirty.} = contains(y, x) ## Sugar for contains ## ## .. code-block:: Nimrod ## assert(1 in (1..3) == true) ## assert(5 in (1..3) == false) -template `notin` * (x, y: expr): expr {.immediate.} = not contains(y, x) +template `notin` * (x, y: expr): expr {.immediate, dirty.} = not contains(y, x) ## Sugar for not containing ## ## .. code-block:: Nimrod diff --git a/tests/generics/mdotlookup.nim b/tests/generics/mdotlookup.nim index 7a5e0ccbf0..0c4d0c87c7 100644 --- a/tests/generics/mdotlookup.nim +++ b/tests/generics/mdotlookup.nim @@ -6,3 +6,11 @@ type MyObj = object proc foo*(b: any) = var o: MyObj echo b.baz, " ", o.x.baz, " ", b.baz() + +import sets + +var intset = initSet[int]() + +proc func*[T](a: T) = + if a in intset: echo("true") + else: echo("false") diff --git a/tests/generics/tdotlookup.nim b/tests/generics/tdotlookup.nim index b886cd8c91..d3deca7fcb 100644 --- a/tests/generics/tdotlookup.nim +++ b/tests/generics/tdotlookup.nim @@ -1,7 +1,10 @@ discard """ - output: '''5 5 5''' + output: '''5 5 5 +false''' """ import mdotlookup foo(7) +# bug #1444 +func(4) From e766c7c3cd73ee9dc66266a0c1246a262ce51268 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 11 Sep 2014 00:36:31 +0200 Subject: [PATCH 11/23] minor bugfix for void .compileTime procs --- compiler/semexprs.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index da12ec08cd..ff445ecd09 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -662,7 +662,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = # optimization pass: not necessary for correctness of the semantic pass if {sfNoSideEffect, sfCompileTime} * callee.flags != {} and - {sfForward, sfImportc} * callee.flags == {}: + {sfForward, sfImportc} * callee.flags == {} and n.typ != nil: if sfCompileTime notin callee.flags and optImplicitStatic notin gOptions: return From b7f8dbbec2bc01f753100659f3db35b024e0076a Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 11 Sep 2014 00:45:29 +0200 Subject: [PATCH 12/23] fixes #1511 --- compiler/semstmts.nim | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 5831850487..d394a2ae5c 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -22,20 +22,23 @@ proc semDiscard(c: PContext, n: PNode): PNode = proc semBreakOrContinue(c: PContext, n: PNode): PNode = result = n checkSonsLen(n, 1) - if n.sons[0].kind != nkEmpty: - var s: PSym - case n.sons[0].kind - of nkIdent: s = lookUp(c, n.sons[0]) - of nkSym: s = n.sons[0].sym - else: illFormedAst(n) - if s.kind == skLabel and s.owner.id == c.p.owner.id: - var x = newSymNode(s) - x.info = n.info - incl(s.flags, sfUsed) - n.sons[0] = x - suggestSym(x.info, s) + if n.sons[0].kind != nkEmpty: + if n.kind != nkContinueStmt: + var s: PSym + case n.sons[0].kind + of nkIdent: s = lookUp(c, n.sons[0]) + of nkSym: s = n.sons[0].sym + else: illFormedAst(n) + if s.kind == skLabel and s.owner.id == c.p.owner.id: + var x = newSymNode(s) + x.info = n.info + incl(s.flags, sfUsed) + n.sons[0] = x + suggestSym(x.info, s) + else: + localError(n.info, errInvalidControlFlowX, s.name.s) else: - localError(n.info, errInvalidControlFlowX, s.name.s) + localError(n.info, errGenerated, "'continue' cannot have a label") elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0): localError(n.info, errInvalidControlFlowX, renderTree(n, {renderNoComments})) From dafa8ccaf39b3fac86a4d782693bd618d1f38e7b Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 11 Sep 2014 01:45:14 +0200 Subject: [PATCH 13/23] fixes #903, fixess #1513 --- compiler/vmgen.nim | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 94afbf008e..a4ddc2e15f 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -43,18 +43,19 @@ type proc debugInfo(info: TLineInfo): string = result = info.toFilename.splitFile.name & ":" & $info.line -proc codeListing(c: PCtx, result: var string, start=0) = +proc codeListing(c: PCtx, result: var string, start=0; last = -1) = # first iteration: compute all necessary labels: var jumpTargets = initIntSet() - for i in start.. < c.code.len: + let last = if last < 0: c.code.len-1 else: min(last, c.code.len-1) + for i in start..last: let x = c.code[i] if x.opcode in relativeJumps: jumpTargets.incl(i+x.regBx-wordExcess) # for debugging purposes var i = start - while i < c.code.len: + while i <= last: if i in jumpTargets: result.addf("L$1:\n", i) let x = c.code[i] @@ -82,9 +83,9 @@ proc codeListing(c: PCtx, result: var string, start=0) = result.add("\n") inc i -proc echoCode*(c: PCtx, start=0) {.deprecated.} = +proc echoCode*(c: PCtx, start=0; last = -1) {.deprecated.} = var buf = "" - codeListing(c, buf, start) + codeListing(c, buf, start, last) echo buf proc gABC(ctx: PCtx; n: PNode; opc: TOpcode; a, b, c: TRegister = 0) = @@ -495,6 +496,7 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) = c.freeTempRange(x, n.len) template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar +proc isGlobal(n: PNode): bool = n.kind == nkSym and isGlobal(n.sym) proc needsAsgnPatch(n: PNode): bool = n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr, @@ -637,8 +639,10 @@ proc genBinaryStmt(c: PCtx; n: PNode; opc: TOpcode) = c.freeTemp(tmp) proc genBinaryStmtVar(c: PCtx; n: PNode; opc: TOpcode) = + var x = n.sons[1] + if x.kind in {nkAddr, nkHiddenAddr}: x = x.sons[0] let - dest = c.genx(n.sons[1], {gfAddrOf}) + dest = c.genx(x) tmp = c.genx(n.sons[2]) c.gABC(n, opc, dest, tmp, 0) #c.genAsgnPatch(n.sons[1], dest) @@ -1053,6 +1057,8 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; # nkAddr we must not use 'unneededIndirection', but for deref we use it. if not isAddr and unneededIndirection(n.sons[0]): gen(c, n.sons[0], dest, newflags) + elif isAddr and isGlobal(n.sons[0]): + gen(c, n.sons[0], dest, flags+{gfAddrOf}) else: let tmp = c.genx(n.sons[0], newflags) if dest < 0: dest = c.getTemp(n.typ) @@ -1247,6 +1253,8 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = c.gABx(n, opcLdGlobal, cc, s.position) c.gABC(n, opcNodeToReg, dest, cc) c.freeTemp(cc) + elif gfAddrOf in flags: + c.gABx(n, opcLdGlobalAddr, dest, s.position) else: c.gABx(n, opcLdGlobal, dest, s.position) else: From 24afab2a95eb761f59ae0f2797e5803c9e2bdd41 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 11 Sep 2014 09:36:22 +0200 Subject: [PATCH 14/23] Threads work again --- lib/system/threads.nim | 78 +++++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 32 deletions(-) diff --git a/lib/system/threads.nim b/lib/system/threads.nim index 4717659e5f..c30c57fb9e 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -1,17 +1,17 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## Thread support for Nimrod. **Note**: This is part of the system module. +## Thread support for Nim. **Note**: This is part of the system module. ## Do not import it directly. To activate thread support you need to compile ## with the ``--threads:on`` command line switch. ## -## Nimrod's memory model for threads is quite different from other common +## Nim's memory model for threads is quite different from other common ## programming languages (C, Pascal): Each thread has its own ## (garbage collected) heap and sharing of memory is restricted. This helps ## to prevent race conditions and improves efficiency. See `the manual for @@ -19,7 +19,7 @@ ## ## Example: ## -## .. code-block:: nimrod +## .. code-block:: Nim ## ## import locks ## @@ -190,7 +190,7 @@ var globalsSlot = threadVarAlloc() when emulatedThreadVars: proc GetThreadLocalVars(): pointer {.compilerRtl, inl.} = - result = addr(cast[PGcThread](ThreadVarGetValue(globalsSlot)).tls) + result = addr(cast[PGcThread](threadVarGetValue(globalsSlot)).tls) when useStackMaskHack: proc maskStackPointer(offset: int): pointer {.compilerRtl, inl.} = @@ -210,7 +210,7 @@ when not defined(useNimRtl): initGC() when emulatedThreadVars: - if NimThreadVarsSize() > sizeof(TThreadLocalStorage): + if nimThreadVarsSize() > sizeof(TThreadLocalStorage): echo "too large thread local storage size requested" quit 1 @@ -245,14 +245,14 @@ when not defined(useNimRtl): # the GC can examine the stacks? proc stopTheWord() = discard -# We jump through some hops here to ensure that Nimrod thread procs can have -# the Nimrod calling convention. This is needed because thread procs are +# We jump through some hops here to ensure that Nim thread procs can have +# the Nim calling convention. This is needed because thread procs are # ``stdcall`` on Windows and ``noconv`` on UNIX. Alternative would be to just # use ``stdcall`` since it is mapped to ``noconv`` on UNIX anyway. type TThread* {.pure, final.}[TArg] = - object of TGcThread ## Nimrod thread. A thread is a heavy object (~14K) + object of TGcThread ## Nim thread. A thread is a heavy object (~14K) ## that **must not** be part of a message! Use ## a ``TThreadId`` for that. when TArg is void: @@ -267,7 +267,7 @@ when not defined(boehmgc) and not hasSharedHeap: proc deallocOsPages() template threadProcWrapperBody(closure: expr) {.immediate.} = - when declared(globalsSlot): ThreadVarSetValue(globalsSlot, closure) + when declared(globalsSlot): threadVarSetValue(globalsSlot, closure) var t = cast[ptr TThread[TArg]](closure) when useStackMaskHack: var tls: TThreadLocalStorage @@ -305,22 +305,26 @@ proc running*[TArg](t: TThread[TArg]): bool {.inline.} = ## returns true if `t` is running. result = t.dataFn != nil -proc joinThread*[TArg](t: TThread[TArg]) {.inline.} = - ## waits for the thread `t` to finish. - when hostOS == "windows": +when hostOS == "windows": + proc joinThread*[TArg](t: TThread[TArg]) {.inline.} = + ## waits for the thread `t` to finish. discard waitForSingleObject(t.sys, -1'i32) - else: - discard pthread_join(t.sys, nil) -proc joinThreads*[TArg](t: varargs[TThread[TArg]]) = - ## waits for every thread in `t` to finish. - when hostOS == "windows": + proc joinThreads*[TArg](t: varargs[TThread[TArg]]) = + ## waits for every thread in `t` to finish. var a: array[0..255, TSysThread] sysAssert a.len >= t.len, "a.len >= t.len" for i in 0..t.high: a[i] = t[i].sys - discard waitForMultipleObjects(t.len.int32, + discard waitForMultipleObjects(t.len.int32, cast[ptr TSysThread](addr(a)), 1, -1) - else: + +else: + proc joinThread*[TArg](t: TThread[TArg]) {.inline.} = + ## waits for the thread `t` to finish. + discard pthread_join(t.sys, nil) + + proc joinThreads*[TArg](t: varargs[TThread[TArg]]) = + ## waits for every thread in `t` to finish. for i in 0..t.high: joinThread(t[i]) when false: @@ -335,22 +339,32 @@ when false: when declared(registerThread): unregisterThread(addr(t)) t.dataFn = nil -proc createThread*[TArg](t: var TThread[TArg], - tp: proc (arg: TArg) {.thread.}, - param: TArg) = - ## creates a new thread `t` and starts its execution. Entry point is the - ## proc `tp`. `param` is passed to `tp`. `TArg` can be ``void`` if you - ## don't need to pass any data to the thread. - when TArg isnot void: t.data = param - t.dataFn = tp - when hasSharedHeap: t.stackSize = ThreadStackSize - when hostOS == "windows": +when hostOS == "windows": + proc createThread*[TArg](t: var TThread[TArg], + tp: proc (arg: TArg) {.thread.}, + param: TArg) = + ## creates a new thread `t` and starts its execution. Entry point is the + ## proc `tp`. `param` is passed to `tp`. `TArg` can be ``void`` if you + ## don't need to pass any data to the thread. + when TArg isnot void: t.data = param + t.dataFn = tp + when hasSharedHeap: t.stackSize = ThreadStackSize var dummyThreadId: int32 t.sys = createThread(nil, ThreadStackSize, threadProcWrapper[TArg], addr(t), 0'i32, dummyThreadId) if t.sys <= 0: raise newException(EResourceExhausted, "cannot create thread") - else: + +else: + proc createThread*[TArg](t: var TThread[TArg], + tp: proc (arg: TArg) {.thread.}, + param: TArg) = + ## creates a new thread `t` and starts its execution. Entry point is the + ## proc `tp`. `param` is passed to `tp`. `TArg` can be ``void`` if you + ## don't need to pass any data to the thread. + when TArg isnot void: t.data = param + t.dataFn = tp + when hasSharedHeap: t.stackSize = ThreadStackSize var a {.noinit.}: Tpthread_attr pthread_attr_init(a) pthread_attr_setstacksize(a, ThreadStackSize) @@ -364,7 +378,7 @@ proc threadId*[TArg](t: var TThread[TArg]): TThreadId[TArg] {.inline.} = proc myThreadId*[TArg](): TThreadId[TArg] = ## returns the thread ID of the thread that calls this proc. This is unsafe ## because the type ``TArg`` is not checked for consistency! - result = cast[TThreadId[TArg]](ThreadVarGetValue(globalsSlot)) + result = cast[TThreadId[TArg]](threadVarGetValue(globalsSlot)) when false: proc mainThreadId*[TArg](): TThreadId[TArg] = From 46bbae47455f5cefdec78251d8078ae07014bef6 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 11 Sep 2014 09:53:00 +0200 Subject: [PATCH 15/23] fixes #1366 --- compiler/semmagic.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index f943e70061..d4aeba32ac 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -126,7 +126,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, result.typ = getSysType(tyString) of mInstantiationInfo: result = semInstantiationInfo(c, n) of mOrd: result = semOrd(c, n) - of mHigh: result = semLowHigh(c, n, mHigh) + of mHigh, mLow: result = semLowHigh(c, n, n[0].sym.magic) of mShallowCopy: result = semShallowCopy(c, n, flags) of mNBindSym: result = semBindSym(c, n) of mLocals: result = semLocals(c, n) From ff55c487b6b550229b6ca3064c0d432134ca3fff Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 11 Sep 2014 09:57:33 +0200 Subject: [PATCH 16/23] mostly fixes #1339 --- compiler/semtypinst.nim | 8 ++++++-- compiler/types.nim | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index eeaf536499..9f0a4100d2 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -216,12 +216,16 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym = result.typ = replaceTypeVarsT(cl, s.typ) result.ast = replaceTypeVarsN(cl, s.ast) -proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType = +proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType = result = PType(idTableGet(cl.typeMap, t)) if result == nil: if cl.allowMetaTypes or tfRetType in t.flags: return localError(t.sym.info, errCannotInstantiateX, typeToString(t)) result = errorType(cl.c) + # In order to prevent endless recursions, we must remember + # this bad lookup and replace it with errorType everywhere. + # These code paths are only active in nimrod check + idTablePut(cl.typeMap, t, result) elif result.kind == tyGenericParam and not cl.allowMetaTypes: internalError(cl.info, "substitution with generic parameter") @@ -353,7 +357,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = of tyGenericBody: localError(cl.info, errCannotInstantiateX, typeToString(t)) - result = t + result = errorType(cl.c) #result = replaceTypeVarsT(cl, lastSon(t)) of tyFromExpr: diff --git a/compiler/types.nim b/compiler/types.nim index ec2271deba..c04413857d 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -913,9 +913,11 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = result = sameTypeAux(a.sons[0], b.sons[0], c) else: result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b) - of tyEnum, tyForward, tyProxy: + of tyEnum, tyForward: # XXX generic enums do not make much sense, but require structural checking result = a.id == b.id and sameFlags(a, b) + of tyError: + result = b.kind == tyError of tyTuple: cycleCheck() result = sameTuple(a, b, c) and sameFlags(a, b) From c73142d8527308850c0d20f1d3a116b5629e93d2 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 11 Sep 2014 10:02:45 +0200 Subject: [PATCH 17/23] fixes #1067 --- compiler/ccgstmts.nim | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index eca026e127..3004e353bc 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -37,6 +37,16 @@ proc genVarTuple(p: BProc, n: PNode) = var tup, field: TLoc if n.kind != nkVarTuple: internalError(n.info, "genVarTuple") var L = sonsLen(n) + + # if we have a something that's been captured, use the lowering instead: + var useLowering = false + for i in countup(0, L-3): + if n[i].kind != nkSym: + useLowering = true; break + if useLowering: + genStmts(p, lowerTupleUnpacking(n, p.prc)) + return + genLineDir(p, n) initLocExpr(p, n.sons[L-1], tup) var t = tup.t From 1791ab6385ee697b42d92b9dcd6cfc014d552558 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 11 Sep 2014 19:54:49 +0200 Subject: [PATCH 18/23] fixes #665 --- compiler/lambdalifting.nim | 2 +- compiler/lowerings.nim | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 6c650eee3b..62e13b9c42 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -949,7 +949,7 @@ proc liftLambdas*(fn: PSym, body: PNode): PNode = discard transformOuterProcBody(o, body, initIter(fn)) result = ex finishEnvironments(o) - #if fn.name.s == "cbOuter": + #if fn.name.s == "parseLong": # echo rendertree(result, {renderIds}) proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode = diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index ddfcb4f011..e1fb09e449 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -56,6 +56,7 @@ proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode = result.add newAsgnStmt(newSymNode(temp), value) for i in 0 .. n.len-3: + if n.sons[i].kind == nkSym: v.addVar(n.sons[i]) result.add newAsgnStmt(n.sons[i], newTupleAccess(value, i)) proc createObj*(owner: PSym, info: TLineInfo): PType = From 63548f04b2d1793099813cf5ab888c580f8074a0 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 11 Sep 2014 20:15:50 +0200 Subject: [PATCH 19/23] manual merge of #1526 --- lib/pure/times.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index ebc3b9fdb8..8b33d2c738 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -513,7 +513,7 @@ elif defined(JS): result.setFullYear(timeInfo.year) result.setDate(timeInfo.monthday) - proc `$`(timeInfo: TTimeInfo): string = return $(TimeInfoToTIme(timeInfo)) + proc `$`(timeInfo: TTimeInfo): string = return $(timeInfoToTime(timeInfo)) proc `$`(time: TTime): string = return $time.toLocaleString() proc `-` (a, b: TTime): int64 = From 6a29fbf240e9395588dcf048ddd3037144c52e12 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 11 Sep 2014 21:00:25 +0200 Subject: [PATCH 20/23] be explicit about single letter options --- doc/basicopt.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/basicopt.txt b/doc/basicopt.txt index fdb0e36e1c..3906238280 100644 --- a/doc/basicopt.txt +++ b/doc/basicopt.txt @@ -35,3 +35,5 @@ Options: -r, --run run the compiled program with given arguments --advanced show advanced command line switches -h, --help show this help + +Note: Even single letter options require the colon: -p:PATH. From e24996de7c7ef1b1e1bc7fe44b977e655a36864f Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 13 Sep 2014 17:53:35 +0200 Subject: [PATCH 21/23] minor changes to manual.txt --- compiler/semstmts.nim | 2 +- doc/manual.txt | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index aaddc84d02..5cb2eabf86 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -354,7 +354,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = def = semExprWithType(c, a.sons[length-1], {efAllowDestructor}) if typ != nil: if typ.isMetaType: - def = inferWithMetaType(c, typ, def) + def = inferWithMetatype(c, typ, def) typ = def.typ else: # BUGFIX: ``fitNode`` is needed here! diff --git a/doc/manual.txt b/doc/manual.txt index f0f50e373c..3d14ef4882 100644 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -596,7 +596,7 @@ Ordinal types Ordinal types have the following characteristics: - Ordinal types are countable and ordered. This property allows - the operation of functions as ``Inc``, ``Ord``, ``Dec`` on ordinal types to + the operation of functions as ``inc``, ``ord``, ``dec`` on ordinal types to be defined. - Ordinal values have a smallest possible value. Trying to count further down than the smallest value gives a checked runtime or static error. @@ -699,11 +699,11 @@ lowest and highest value of the type: .. code-block:: nim type - TSubrange = range[0..5] + Subrange = range[0..5] -``TSubrange`` is a subrange of an integer which can only hold the values 0 -to 5. Assigning any other value to a variable of type ``TSubrange`` is a +``Subrange`` is a subrange of an integer which can only hold the values 0 +to 5. Assigning any other value to a variable of type ``Subrange`` is a checked runtime error (or static error if it can be statically determined). Assignments from the base type to one of its subrange types (and vice versa) are allowed. @@ -791,6 +791,10 @@ turned off as default. The only operations that are affected by the ``floatChecks`` pragma are the ``+``, ``-``, ``*``, ``/`` operators for floating point types. +An implementation should always use the maximum precision available to evaluate +floating pointer values at compile time; this means expressions like +``0.09'f32 + 0.01'f32 == 0.09'f64 + 0.01'f64`` are true. + Boolean type ------------ @@ -3675,10 +3679,11 @@ Future versions of Nim may also support overloading based on the return type of the overloads. In such settings, the expected result type at call sites may also influence the inferred return type. -Likewise, if a type class is used in another position where Nim expects a -concrete type (e.g. a variable declaration or a type coercion), Nim will try to -infer the concrete type by applying the sane matching algorithm also used in -overload resolution. +.. + Likewise, if a type class is used in another position where Nim expects a + concrete type (e.g. a variable declaration or a type coercion), Nim will try + to infer the concrete type by applying the matching algorithm that also used + in overload resolution. Symbol lookup in generics From 05f09fafcffb8578b03fb719e7f8f0cdbae7ed99 Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 14 Sep 2014 11:27:14 +0200 Subject: [PATCH 22/23] fixed 'system.open' bug --- lib/system/sysio.nim | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim index 56de5e6e80..7908fbe4dd 100644 --- a/lib/system/sysio.nim +++ b/lib/system/sysio.nim @@ -215,13 +215,13 @@ proc open(f: var File, filename: string, mode: FileMode = fmRead, bufSize: int = -1): bool = var p: pointer = fopen(filename, FormatOpen[mode]) - result = (p != nil) - f = cast[File](p) - if bufSize > 0 and bufSize <= high(cint).int: - if setvbuf(f, nil, IOFBF, bufSize.cint) != 0'i32: - sysFatal(OutOfMemError, "out of memory") - elif bufSize == 0: - discard setvbuf(f, nil, IONBF, 0) + if p != nil: + result = true + f = cast[File](p) + if bufSize > 0 and bufSize <= high(cint).int: + discard setvbuf(f, nil, IOFBF, bufSize.cint) + elif bufSize == 0: + discard setvbuf(f, nil, IONBF, 0) proc reopen(f: File, filename: string, mode: FileMode = fmRead): bool = var p: pointer = freopen(filename, FormatOpen[mode], f) From d330a72a4565353bd3ad54ade0580d53cd9d5a5d Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 14 Sep 2014 11:34:06 +0200 Subject: [PATCH 23/23] fixes documentation generator --- compiler/msgs.nim | 2 +- compiler/options.nim | 5 +++-- compiler/pretty.nim | 6 +++++- compiler/vm.nim | 4 ++-- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 622c643599..da2fe122d4 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -442,7 +442,7 @@ type TNoteKinds* = set[TNoteKind] TFileInfo*{.final.} = object - fullPath*: string # This is a canonical full filesystem path + fullPath: string # This is a canonical full filesystem path projPath*: string # This is relative to the project's root shortName*: string # short name of the module quotedName*: PRope # cached quoted short name for codegen diff --git a/compiler/options.nim b/compiler/options.nim index 69067b7c41..9d7df2f2bc 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -188,8 +188,9 @@ proc getPrefixDir*(): string = result = splitPath(getAppDir()).head proc canonicalizePath*(path: string): string = - result = path.expandFilename - when not FileSystemCaseSensitive: result = result.toLower + #result = path.expandFilename + when not FileSystemCaseSensitive: result = path.toLower + else: result = path proc shortenDir*(dir: string): string = ## returns the interesting part of a dir diff --git a/compiler/pretty.nim b/compiler/pretty.nim index 9f2074a0b2..ec93223095 100644 --- a/compiler/pretty.nim +++ b/compiler/pretty.nim @@ -110,7 +110,7 @@ template styleCheckDef*(info: TLineInfo; s: PSym) = template styleCheckDef*(s: PSym) = styleCheckDef(s.info, s, s.kind) -proc styleCheckUse*(info: TLineInfo; s: PSym) = +proc styleCheckUseImpl(info: TLineInfo; s: PSym) = if info.fileIndex < 0: return # we simply convert it to what it looks like in the definition # for consistency @@ -138,3 +138,7 @@ proc styleCheckUse*(info: TLineInfo; s: PSym) = system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x) gSourceFiles[info.fileIndex].dirty = true #if newName == "File": writeStackTrace() + +template styleCheckUse*(info: TLineInfo; s: PSym) = + when defined(nimfix): + if gStyleCheck != StyleCheck.None: styleCheckUseImpl(info, s) diff --git a/compiler/vm.nim b/compiler/vm.nim index 5ef4576ecc..f74f2e0d70 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1135,14 +1135,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcParseExprToAst: decodeB(rkNode) # c.debug[pc].line.int - countLines(regs[rb].strVal) ? - let ast = parseString(regs[rb].node.strVal, c.debug[pc].toFilename, + let ast = parseString(regs[rb].node.strVal, c.debug[pc].toFullPath, c.debug[pc].line.int) if sonsLen(ast) != 1: globalError(c.debug[pc], errExprExpected, "multiple statements") regs[ra].node = ast.sons[0] of opcParseStmtToAst: decodeB(rkNode) - let ast = parseString(regs[rb].node.strVal, c.debug[pc].toFilename, + let ast = parseString(regs[rb].node.strVal, c.debug[pc].toFullPath, c.debug[pc].line.int) regs[ra].node = ast of opcCallSite: