From bf6e82a8611428fde85a0017166f316599c4228e Mon Sep 17 00:00:00 2001 From: skilchen Date: Mon, 16 Apr 2018 17:40:54 +0200 Subject: [PATCH 01/47] there is no hour 0 in am/pm time --- lib/pure/times.nim | 22 +++++++++++++++------- tests/stdlib/ttimes.nim | 6 ++++++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index dc216477b..e45135612 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -1158,12 +1158,16 @@ proc formatToken(dt: DateTime, token: string, buf: var string) = of "dddd": buf.add($dt.weekday) of "h": - buf.add($(if dt.hour > 12: dt.hour - 12 else: dt.hour)) + if dt.hour == 0: buf.add("12") + else: buf.add($(if dt.hour > 12: dt.hour - 12 else: dt.hour)) of "hh": - let amerHour = if dt.hour > 12: dt.hour - 12 else: dt.hour - if amerHour < 10: - buf.add('0') - buf.add($amerHour) + if dt.hour == 0: + buf.add("12") + else: + let amerHour = if dt.hour > 12: dt.hour - 12 else: dt.hour + if amerHour < 10: + buf.add('0') + buf.add($amerHour) of "H": buf.add($dt.hour) of "HH": @@ -1488,11 +1492,15 @@ proc parseToken(dt: var DateTime; token, value: string; j: var int) = dt.second = value[j..j+1].parseInt() j += 2 of "t": - if value[j] == 'P' and dt.hour > 0 and dt.hour < 12: + if value[j] == 'A' and dt.hour == 12: + dt.hour = 0 + elif value[j] == 'P' and dt.hour > 0 and dt.hour < 12: dt.hour += 12 j += 1 of "tt": - if value[j..j+1] == "PM" and dt.hour > 0 and dt.hour < 12: + if value[j..j+1] == "AM" and dt.hour == 12: + dt.hour = 0 + elif value[j..j+1] == "PM" and dt.hour > 0 and dt.hour < 12: dt.hour += 12 j += 2 of "yy": diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim index f35965286..4f1a43f15 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -28,6 +28,12 @@ t.checkFormat("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" & t.checkFormat("yyyyMMddhhmmss", "20380119031407") +# issue 7620 +let t7620_am = parse("4/15/2017 12:01:02 AM +0", "M/d/yyyy' 'h:mm:ss' 'tt' 'z", utc()) +t7620_am.checkFormat("M/d/yyyy' 'h:mm:ss' 'tt' 'z", "4/15/2017 12:01:02 AM +0") +let t7620_pm = parse("4/15/2017 12:01:02 PM +0", "M/d/yyyy' 'h:mm:ss' 'tt' 'z", utc()) +t7620_pm.checkFormat("M/d/yyyy' 'h:mm:ss' 'tt' 'z", "4/15/2017 12:01:02 PM +0") + let t2 = fromUnix(160070789).utc # Mon 27 Jan 16:06:29 GMT 1975 t2.checkFormat("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" & " ss t tt y yy yyy yyyy yyyyy z zz zzz", From d4867cbcbd1325c627612fbb4ff331394cd2c2a3 Mon Sep 17 00:00:00 2001 From: SolitudeSF Date: Thu, 26 Apr 2018 23:08:57 +0300 Subject: [PATCH 02/47] link against libssl.so.45 --- lib/wrappers/openssl.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 86ae85369..6609dc245 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -38,7 +38,7 @@ when useWinVersion: from winlean import SocketHandle else: - const versions = "(.1.1|.38|.39|.41|.43|.44|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|)" + const versions = "(.1.1|.38|.39|.41|.43|.44|.45|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|)" when defined(macosx): const From 9099ec5d0b2b8882edaa1bb66c38c99701a59ddc Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 3 May 2018 15:18:19 +0100 Subject: [PATCH 03/47] Merges #7700 manually and adds decodePlus option to decodeUrl too. --- lib/pure/uri.nim | 48 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index 9bf25b86b..36ab00580 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -47,25 +47,36 @@ proc add*(url: var Url, a: Url) {.deprecated.} = url = url / a {.pop.} -proc encodeUrl*(s: string): string = - ## Encodes a value to be HTTP safe: This means that characters in the set - ## ``{'A'..'Z', 'a'..'z', '0'..'9', '_'}`` are carried over to the result, - ## a space is converted to ``'+'`` and every other character is encoded as - ## ``'%xx'`` where ``xx`` denotes its hexadecimal value. +proc encodeUrl*(s: string, usePlus=true): string = + ## Encodes a URL according to RFC3986. + ## + ## This means that characters in the set + ## ``{'a'..'z', 'A'..'Z', '0'..'9', '-', '.', '_', '~'}`` are + ## carried over to the result. + ## All other characters are encoded as ``''%xx'`` where ``xx`` + ## denotes its hexadecimal value. + ## + ## As a special rule, when the value of ``usePlus`` is true, + ## spaces are encoded as ``'+'`` instead of ``'%20'``. result = newStringOfCap(s.len + s.len shr 2) # assume 12% non-alnum-chars - for i in 0..s.len-1: - case s[i] - of 'a'..'z', 'A'..'Z', '0'..'9', '_': add(result, s[i]) - of ' ': add(result, '+') + let fromSpace = if usePlus: "+" else: "%20" + for c in s: + case c + of 'a'..'z', 'A'..'Z', '0'..'9', '-', '.', '_', '~': add(result, c) + of ' ': add(result, fromSpace) else: add(result, '%') - add(result, toHex(ord(s[i]), 2)) + add(result, toHex(ord(c), 2)) -proc decodeUrl*(s: string): string = - ## Decodes a value from its HTTP representation: This means that a ``'+'`` - ## is converted to a space, ``'%xx'`` (where ``xx`` denotes a hexadecimal - ## value) is converted to the character with ordinal number ``xx``, and +proc decodeUrl*(s: string, decodePlus=true): string = + ## Decodes a URL according to RFC3986. + ## + ## This means that any ``'%xx'`` (where ``xx`` denotes a hexadecimal + ## value) are converted to the character with ordinal number ``xx``, ## and every other character is carried over. + ## + ## As a special rule, when the value of ``decodePlus`` is true, ``'+'`` + ## characters are converted to a space. proc handleHexChar(c: char, x: var int) {.inline.} = case c of '0'..'9': x = (x shl 4) or (ord(c) - ord('0')) @@ -84,7 +95,11 @@ proc decodeUrl*(s: string): string = handleHexChar(s[i+2], x) inc(i, 2) result[j] = chr(x) - of '+': result[j] = ' ' + of '+': + if decodePlus: + result[j] = ' ' + else: + result[j] = s[i] else: result[j] = s[i] inc(i) inc(j) @@ -370,6 +385,9 @@ when isMainModule: const test1 = "abc\L+def xyz" doAssert encodeUrl(test1) == "abc%0A%2Bdef+xyz" doAssert decodeUrl(encodeUrl(test1)) == test1 + doAssert encodeUrl(test1, false) == "abc%0A%2Bdef%20xyz" + doAssert decodeUrl(encodeUrl(test1, false), false) == test1 + doAssert decodeUrl(encodeUrl(test1)) == test1 block: let str = "http://localhost" From 9955ee0a9b1a593c7ac6c538264d50bbcd01d42a Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Thu, 3 May 2018 18:15:31 +0300 Subject: [PATCH 04/47] Fixes #7738 --- lib/pure/xmltree.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index a6f62abce..20bec300f 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -319,8 +319,8 @@ proc xmlConstructor(a: NimNode): NimNode {.compileTime.} = if a.kind == nnkCall: result = newCall("newXmlTree", toStrLit(a[0])) var attrs = newNimNode(nnkBracket, a) - var newStringTabCall = newCall("newStringTable", attrs, - newIdentNode("modeCaseSensitive")) + var newStringTabCall = newCall(bindSym"newStringTable", attrs, + bindSym"modeCaseSensitive") var elements = newNimNode(nnkBracket, a) for i in 1..a.len-1: if a[i].kind == nnkExprEqExpr: From f94fafff9b6734a82bd252a03ba19057e1913cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Thu, 3 May 2018 17:23:13 +0200 Subject: [PATCH 05/47] Deprecate smart binary search (#7745) * deprecate smartBinarySearch * changelog entry --- changelog.md | 3 +++ lib/pure/algorithm.nim | 32 ++++++++++++++++++-------------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/changelog.md b/changelog.md index 6cd0faf52..336ede15c 100644 --- a/changelog.md +++ b/changelog.md @@ -63,6 +63,9 @@ fields. - ``system.SomeReal`` is now called ``SomeFloat`` for consistency and correctness. +- ``algorithm.smartBinarySearch`` and ``algorithm.binarySearch`` is + now joined in ``binarySearch``. ``smartbinarySearch`` is now + deprecated. ### Language additions diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 45e031574..4f7880fec 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -69,21 +69,25 @@ proc reversed*[T](a: openArray[T]): seq[T] = proc binarySearch*[T](a: openArray[T], key: T): int = ## binary search for `key` in `a`. Returns -1 if not found. - var b = len(a) - while result < b: - var mid = (result + b) div 2 - if a[mid] < key: result = mid + 1 - else: b = mid - if result >= len(a) or a[result] != key: result = -1 + if ((a.len - 1) and a.len) == 0: + # when `a.len` is a power of 2, a faster div can be used. + var step = a.len div 2 + while step > 0: + if a[result or step] <= key: + result = result or step + step = step shr 1 + if a[result] != key: result = -1 + else: + var b = len(a) + while result < b: + var mid = (result + b) div 2 + if a[mid] < key: result = mid + 1 + else: b = mid + if result >= len(a) or a[result] != key: result = -1 -proc smartBinarySearch*[T](a: openArray[T], key: T): int = - ## ``a.len`` must be a power of 2 for this to work. - var step = a.len div 2 - while step > 0: - if a[result or step] <= key: - result = result or step - step = step shr 1 - if a[result] != key: result = -1 +proc smartBinarySearch*[T](a: openArray[T], key: T): int {.deprecated.} = + ## **Deprecated since version 0.18.1**; Use ``binarySearch`` instead. + binarySearch(a,key) const onlySafeCode = true From 8f7bd6cf5ce3772466d90648a182fcd82ded9156 Mon Sep 17 00:00:00 2001 From: notTito Date: Fri, 4 May 2018 08:37:57 +0300 Subject: [PATCH 06/47] Replace factorial function with a compile time one (#7276) * Replace factorial function with a compile time one * Fix the indentation * Update --- lib/pure/math.nim | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index cbd04a145..5f3240e00 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -29,11 +29,21 @@ proc binom*(n, k: int): int {.noSideEffect.} = for i in countup(2, k): result = (result * (n + 1 - i)) div i -proc fac*(n: int): int {.noSideEffect.} = +proc createFactTable[N: static[int]]: array[N, int] = + result[0] = 1 + for i in 1 ..< N: + result[i] = result[i - 1] * i + +proc fac*(n: int): int = ## Computes the faculty/factorial function. - result = 1 - for i in countup(2, n): - result = result * i + const factTable = + when sizeof(int) == 4: + createFactTable[13]() + else: + createFactTable[21]() + assert(n > 0, $n & " must not be negative.") + assert(n < factTable.len, $n & " is too large to look up in the table") + factTable[n] {.push checks:off, line_dir:off, stack_trace:off.} From 27631b1112bb10e4a7ca43b611c2d3bde2ba320f Mon Sep 17 00:00:00 2001 From: Dmitry Atamanov Date: Fri, 4 May 2018 08:39:05 +0300 Subject: [PATCH 07/47] Fix filter_tmpl errors (#7763) --- compiler/filter_tmpl.nim | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim index 51ccb8390..545bea950 100644 --- a/compiler/filter_tmpl.nim +++ b/compiler/filter_tmpl.nim @@ -45,7 +45,6 @@ proc scanPar(p: var TTmplParser, d: int) = let hi = p.x.len - 1 while i <= hi: case p.x[i] - of '\0': break of '(': inc(p.par) of ')': dec(p.par) of '[': inc(p.bracket) @@ -64,16 +63,22 @@ const proc parseLine(p: var TTmplParser) = var j = 0 - while p.x[j] == ' ': inc(j) + let hi = p.x.len - 1 + + if hi == 0: + return + + while j <= hi and p.x[j] == ' ': inc(j) + if p.x[0] == p.nimDirective and p.x[1] == '?': newLine(p) elif p.x[j] == p.nimDirective: newLine(p) inc(j) - while p.x[j] == ' ': inc(j) + while j <= hi and p.x[j] == ' ': inc(j) let d = j var keyw = "" - while p.x[j] in PatternChars: + while j <= hi and p.x[j] in PatternChars: add(keyw, p.x[j]) inc(j) @@ -127,10 +132,8 @@ proc parseLine(p: var TTmplParser) = llStreamWrite(p.outp, "(\"") inc(p.emitPar) p.state = psTempl - while true: + while j <= hi: case p.x[j] - of '\0': - break of '\x01'..'\x1F', '\x80'..'\xFF': llStreamWrite(p.outp, "\\x") llStreamWrite(p.outp, toHex(ord(p.x[j]), 2)) @@ -157,11 +160,8 @@ proc parseLine(p: var TTmplParser) = llStreamWrite(p.outp, '(') inc(j) var curly = 0 - while true: + while j <= hi: case p.x[j] - of '\0': - localError(p.info, errXExpected, "}") - break of '{': inc(j) inc(curly) @@ -174,6 +174,9 @@ proc parseLine(p: var TTmplParser) = else: llStreamWrite(p.outp, p.x[j]) inc(j) + if curly > 0: + localError(p.info, errXExpected, "}") + break llStreamWrite(p.outp, ')') llStreamWrite(p.outp, p.conc) llStreamWrite(p.outp, '\"') @@ -182,7 +185,7 @@ proc parseLine(p: var TTmplParser) = llStreamWrite(p.outp, p.conc) llStreamWrite(p.outp, p.toStr) llStreamWrite(p.outp, '(') - while p.x[j] in PatternChars: + while j <= hi and p.x[j] in PatternChars: llStreamWrite(p.outp, p.x[j]) inc(j) llStreamWrite(p.outp, ')') From cda591a42f5c3ef29911078c862cb6c07e35f651 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Fri, 4 May 2018 07:40:40 +0200 Subject: [PATCH 08/47] Disable setTerminate when noCppExceptions is defined (#7751) --- compiler/cgen.nim | 2 +- lib/system.nim | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index ff3e6714d..d838f9b9c 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -265,7 +265,7 @@ proc rdCharLoc(a: TLoc): Rope = proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc, takeAddr: bool) = - if p.module.compileToCpp and t.isException: + if p.module.compileToCpp and t.isException and not isDefined("noCppExceptions"): # init vtable in Exception object for polymorphic exceptions includeHeader(p.module, "") linefmt(p, section, "new ($1) $2;$n", rdLoc(a), getTypeDesc(p.module, t)) diff --git a/lib/system.nim b/lib/system.nim index 0c8659fda..5781aff27 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -4172,8 +4172,9 @@ template doAssertRaises*(exception, code: untyped): typed = if wrong: raiseAssert(astToStr(exception) & " wasn't raised by:\n" & astToStr(code)) -when defined(cpp) and appType != "lib" and not defined(js) and - not defined(nimscript) and hostOS != "standalone": +when defined(cpp) and appType != "lib" and + not defined(js) and not defined(nimscript) and + hostOS != "standalone" and not defined(noCppExceptions): proc setTerminate(handler: proc() {.noconv.}) {.importc: "std::set_terminate", header: "".} setTerminate proc() {.noconv.} = From 7d78707e36ca7b7317730244df190b06cf8ddc70 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 4 May 2018 08:10:46 +0200 Subject: [PATCH 09/47] fixes #7766 --- lib/system/sysstr.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index bba59e930..c5c8a9cac 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -76,6 +76,7 @@ proc rawNewStringNoInit(space: int): NimString {.compilerProc.} = if s < 7: s = 7 result = allocStrNoInit(sizeof(TGenericSeq) + s + 1) result.reserved = s + result.len = 0 when defined(gogc): result.elemSize = 1 @@ -84,6 +85,7 @@ proc rawNewString(space: int): NimString {.compilerProc.} = if s < 7: s = 7 result = allocStr(sizeof(TGenericSeq) + s + 1) result.reserved = s + result.len = 0 when defined(gogc): result.elemSize = 1 From 6f4ca3f276729bbb99039b823c4227cace3cae92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Fri, 4 May 2018 15:29:21 +0200 Subject: [PATCH 10/47] test binarySearch, fix for search in empty. (#7769) --- lib/pure/algorithm.nim | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 4f7880fec..5d7348b8d 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -69,7 +69,7 @@ proc reversed*[T](a: openArray[T]): seq[T] = proc binarySearch*[T](a: openArray[T], key: T): int = ## binary search for `key` in `a`. Returns -1 if not found. - if ((a.len - 1) and a.len) == 0: + if ((a.len - 1) and a.len) == 0 and a.len > 0: # when `a.len` is a power of 2, a faster div can be used. var step = a.len div 2 while step > 0: @@ -367,10 +367,11 @@ when isMainModule: var srt1 = [1,2,3,4,4,4,4,5] var srt2 = ["iello","hello"] var srt3 = [1.0,1.0,1.0] - var srt4: seq[int] = @[] + var srt4: seq[int] assert srt1.isSorted(cmp) == true assert srt2.isSorted(cmp) == false assert srt3.isSorted(cmp) == true + assert srt4.isSorted(cmp) == true var srtseq = newSeq[int]() assert srtseq.isSorted(cmp) == true # Tests for reversed @@ -518,4 +519,24 @@ when isMainModule: block fillEmptySeq: var s = newSeq[int]() - s.fill(0) \ No newline at end of file + s.fill(0) + + block testBinarySearch: + var noData: seq[int] + doAssert binarySearch(noData, 7) == -1 + let oneData = @[1] + doAssert binarySearch(oneData, 1) == 0 + doAssert binarySearch(onedata, 7) == -1 + let someData = @[1,3,4,7] + doAssert binarySearch(someData, 1) == 0 + doAssert binarySearch(somedata, 7) == 3 + doAssert binarySearch(someData, -1) == -1 + doAssert binarySearch(someData, 5) == -1 + doAssert binarySearch(someData, 13) == -1 + let moreData = @[1,3,5,7,4711] + doAssert binarySearch(moreData, -1) == -1 + doAssert binarySearch(moreData, 1) == 0 + doAssert binarySearch(moreData, 5) == 2 + doAssert binarySearch(moreData, 6) == -1 + doAssert binarySearch(moreData, 4711) == 4 + doAssert binarySearch(moreData, 4712) == -1 From 608017801d3625dc8c7991073a0ef84440314c24 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Fri, 4 May 2018 22:26:16 +0100 Subject: [PATCH 11/47] Fixes crash in httpclient due to new string indexing rules. --- lib/pure/httpclient.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index b7617b0b5..91b78f59b 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -749,7 +749,7 @@ proc generateHeaders(requestUrl: Uri, httpMethod: string, if proxy.isNil or requestUrl.scheme == "https": # /path?query - if requestUrl.path[0] != '/': result.add '/' + if not requestUrl.path.startsWith("/"): result.add '/' result.add(requestUrl.path) if requestUrl.query.len > 0: result.add("?" & requestUrl.query) From 805402b294c6cb3ee8e0f39245aa2d1366ae76e9 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 5 May 2018 14:17:31 +0200 Subject: [PATCH 12/47] fixes #7582 --- compiler/parser.nim | 5 +++-- tests/parser/tcommand_as_expr.nim | 13 ++++++++++++- tests/parser/twrongcmdsyntax.nim | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index ac0a57770..d7a1a75e3 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -744,8 +744,9 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode = # progress guaranteed somePar() result = namedParams(p, result, nkCurlyExpr, tkCurlyRi) - of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType: - if p.inPragma == 0: + of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType, + tkOpr, tkDotDot: + if p.inPragma == 0 and (isUnary(p) or p.tok.tokType notin {tkOpr, tkDotDot}): # actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet # solution, but pragmas.nim can't handle that let a = result diff --git a/tests/parser/tcommand_as_expr.nim b/tests/parser/tcommand_as_expr.nim index a244c8767..b25ec4bd8 100644 --- a/tests/parser/tcommand_as_expr.nim +++ b/tests/parser/tcommand_as_expr.nim @@ -2,7 +2,10 @@ discard """ output: '''140 5-120-120 359 -77''' +77 +-4 +-1 +-1''' """ #import math import sequtils @@ -25,3 +28,11 @@ let a = [2,4,8].map do (d:int) -> int: d + 1 echo a[0], a[1], a[2] echo(foo 8, foo 8) + +# bug #7582 +proc f(x: int): int = x + +echo f -4 + +echo int -1 # doesn't compile +echo int `-` 1 # compiles diff --git a/tests/parser/twrongcmdsyntax.nim b/tests/parser/twrongcmdsyntax.nim index affe72c34..c2962bed4 100644 --- a/tests/parser/twrongcmdsyntax.nim +++ b/tests/parser/twrongcmdsyntax.nim @@ -1,5 +1,5 @@ discard """ - errormsg: '''identifier expected, but found 'echo 4''' + errormsg: '''in expression '4 2': identifier expected, but found '4''' line: 6 """ From 1aa359febba7c666c3a0108d6362ac1c51cfaf4e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 5 May 2018 14:58:33 +0200 Subject: [PATCH 13/47] warn about inconsistent spacing around binary operators; fixes #7582 --- changelog.md | 5 ++++- compiler/msgs.nim | 6 ++++-- compiler/parser.nim | 8 ++------ compiler/plugins/locals/locals.nim | 2 +- compiler/renderer.nim | 2 +- compiler/semstmts.nim | 2 +- compiler/vmgen.nim | 2 +- lib/pure/algorithm.nim | 2 +- lib/system/assign.nim | 12 ++++++------ lib/system/deepcopy.nim | 10 +++++----- lib/system/gc.nim | 2 +- lib/system/osalloc.nim | 2 +- 12 files changed, 28 insertions(+), 27 deletions(-) diff --git a/changelog.md b/changelog.md index 6cd0faf52..b50bedb5a 100644 --- a/changelog.md +++ b/changelog.md @@ -17,6 +17,9 @@ - The ``not nil`` type annotation now has to be enabled explicitly via ``{.experimental: "notnil"}`` as we are still not pleased with how this feature works with Nim's containers. +- The parser now warns about inconsistent spacing around binary operators as + these can easily be confused with unary operators. This warning will likely + become an error in the future. #### Breaking changes in the standard library @@ -89,7 +92,7 @@ - Accessing the binary zero terminator in Nim's native strings is now invalid. Internally a Nim string still has the trailing zero for zero-copy interoperability with ``cstring``. Compile your code with the - next switch ``--laxStrings:on`` if you need a transition period. + new switch ``--laxStrings:on`` if you need a transition period. ### Tool changes diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 5da375c1c..088742d18 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -131,7 +131,7 @@ type warnEachIdentIsTuple, warnShadowIdent, warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2, warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed, - warnUser, + warnInconsistentSpacing, warnUser, hintSuccess, hintSuccessX, hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded, hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled, @@ -416,6 +416,7 @@ const warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.", warnLockLevel: "$1", warnResultShadowed: "Special variable 'result' is shadowed.", + warnInconsistentSpacing: "Number of spaces around '$#' is not consistent", warnUser: "$1", hintSuccess: "operation successful", hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)", @@ -454,7 +455,8 @@ const "TypelessParam", "UseBase", "WriteToForeignHeap", "UnsafeCode", "EachIdentIsTuple", "ShadowIdent", "ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit", - "GcMem", "Destructor", "LockLevel", "ResultShadowed", "User"] + "GcMem", "Destructor", "LockLevel", "ResultShadowed", + "Spacing", "User"] HintsToStr* = ["Success", "SuccessX", "LineTooLong", "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded", diff --git a/compiler/parser.nim b/compiler/parser.nim index d7a1a75e3..c61519541 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -268,13 +268,9 @@ proc isUnary(p: TParser): bool = proc checkBinary(p: TParser) {.inline.} = ## Check if the current parser token is a binary operator. # we don't check '..' here as that's too annoying - if p.strongSpaces and p.tok.tokType == tkOpr: + if p.tok.tokType == tkOpr: if p.tok.strongSpaceB > 0 and p.tok.strongSpaceA != p.tok.strongSpaceB: - parMessage(p, errGenerated, - "Number of spaces around '$#' not consistent" % - prettyTok(p.tok)) - elif p.tok.strongSpaceA notin {0,1,2,4,8}: - parMessage(p, errGenerated, "Number of spaces must be 0,1,2,4 or 8") + parMessage(p, warnInconsistentSpacing, prettyTok(p.tok)) #| module = stmt ^* (';' / IND{=}) #| diff --git a/compiler/plugins/locals/locals.nim b/compiler/plugins/locals/locals.nim index 9cbb61186..ff7f3be58 100644 --- a/compiler/plugins/locals/locals.nim +++ b/compiler/plugins/locals/locals.nim @@ -9,7 +9,7 @@ ## The builtin 'system.locals' implemented as a plugin. -import "../../" / [pluginsupport, ast, astalgo, +import "../../" / [pluginsupport, ast, astalgo, magicsys, lookups, semdata, lowerings] proc semLocals(c: PContext, n: PNode): PNode = diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 95a622d4e..996168412 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -342,7 +342,7 @@ proc atom(g: TSrcGen; n: PNode): string = of nkIdent: result = n.ident.s of nkSym: result = n.sym.name.s of nkStrLit: result = ""; result.addQuoted(n.strVal) - of nkRStrLit: result = "r\"" & replace(n.strVal, "\"", "\"\"") & '\"' + of nkRStrLit: result = "r\"" & replace(n.strVal, "\"", "\"\"") & '\"' of nkTripleStrLit: result = "\"\"\"" & n.strVal & "\"\"\"" of nkCharLit: result = "\'" diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 8b466f1da..f5fdc3445 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -846,7 +846,7 @@ proc checkCovariantParamsUsages(genericType: PType) = if subType != nil: subresult traverseSubTypes(subType) if result: - error("non-invariant type param used in a proc type: " & $t) + error("non-invariant type param used in a proc type: " & $t) of tySequence: return traverseSubTypes(t[0]) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 0544dc311..f7d3237b8 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -790,7 +790,7 @@ proc genIntCast(c: PCtx; n: PNode; dest: var TDest) = elif src.kind in signedIntegers and dst.kind in unsignedIntegers: # cast signed to unsigned integer of same size # unsignedVal = (offset +% signedVal +% 1) and offset - let offset = (1 shl (src_size * 8)) - 1 + let offset = (1 shl (src_size * 8)) - 1 c.gABx(n, opcLdConst, tmp2, mkIntLit(offset)) c.gABx(n, opcLdConst, dest, mkIntLit(offset+1)) c.gABC(n, opcAddu, tmp3, tmp, dest) diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 45e031574..f9a31bc23 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -395,7 +395,7 @@ proc rotateInternal[T](arg: var openarray[T]; first, middle, last: int): int = swap(arg[mFirst], arg[next]) mFirst += 1 - next += 1 + next += 1 if mFirst == mMiddle: mMiddle = next diff --git a/lib/system/assign.nim b/lib/system/assign.nim index ff1ef31d2..16b56aba7 100644 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -74,7 +74,7 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) = var dst = cast[ByteAddress](cast[PPointer](dest)[]) for i in 0..seq.len-1: genericAssignAux( - cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize), + cast[pointer](dst +% i *% mt.base.size +% GenericSeqSize), cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +% GenericSeqSize), mt.base, shallow) @@ -100,8 +100,8 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) = genericAssignAux(dest, src, mt.node, shallow) of tyArray, tyArrayConstr: for i in 0..(mt.size div mt.base.size)-1: - genericAssignAux(cast[pointer](d +% i*% mt.base.size), - cast[pointer](s +% i*% mt.base.size), mt.base, shallow) + genericAssignAux(cast[pointer](d +% i *% mt.base.size), + cast[pointer](s +% i *% mt.base.size), mt.base, shallow) of tyRef: unsureAsgnRef(cast[PPointer](dest), cast[PPointer](s)[]) of tyOptAsRef: @@ -166,8 +166,8 @@ proc genericAssignOpenArray(dest, src: pointer, len: int, d = cast[ByteAddress](dest) s = cast[ByteAddress](src) for i in 0..len-1: - genericAssign(cast[pointer](d +% i*% mt.base.size), - cast[pointer](s +% i*% mt.base.size), mt.base) + genericAssign(cast[pointer](d +% i *% mt.base.size), + cast[pointer](s +% i *% mt.base.size), mt.base) proc objectInit(dest: pointer, typ: PNimType) {.compilerProc, benign.} proc objectInitAux(dest: pointer, n: ptr TNimNode) {.benign.} = @@ -235,7 +235,7 @@ proc genericReset(dest: pointer, mt: PNimType) = pint[] = nil of tyArray, tyArrayConstr: for i in 0..(mt.size div mt.base.size)-1: - genericReset(cast[pointer](d +% i*% mt.base.size), mt.base) + genericReset(cast[pointer](d +% i *% mt.base.size), mt.base) else: zeroMem(dest, mt.size) # set raw bits to zero diff --git a/lib/system/deepcopy.nim b/lib/system/deepcopy.nim index 51e138e5e..750da00cf 100644 --- a/lib/system/deepcopy.nim +++ b/lib/system/deepcopy.nim @@ -105,7 +105,7 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) = var dst = cast[ByteAddress](cast[PPointer](dest)[]) for i in 0..seq.len-1: genericDeepCopyAux( - cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize), + cast[pointer](dst +% i *% mt.base.size +% GenericSeqSize), cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +% GenericSeqSize), mt.base, tab) @@ -122,8 +122,8 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) = genericDeepCopyAux(dest, src, mt.node, tab) of tyArray, tyArrayConstr: for i in 0..(mt.size div mt.base.size)-1: - genericDeepCopyAux(cast[pointer](d +% i*% mt.base.size), - cast[pointer](s +% i*% mt.base.size), mt.base, tab) + genericDeepCopyAux(cast[pointer](d +% i *% mt.base.size), + cast[pointer](s +% i *% mt.base.size), mt.base, tab) of tyRef, tyOptAsRef: let s2 = cast[PPointer](src)[] if s2 == nil: @@ -183,5 +183,5 @@ proc genericDeepCopyOpenArray(dest, src: pointer, len: int, d = cast[ByteAddress](dest) s = cast[ByteAddress](src) for i in 0..len-1: - genericDeepCopy(cast[pointer](d +% i*% mt.base.size), - cast[pointer](s +% i*% mt.base.size), mt.base) + genericDeepCopy(cast[pointer](d +% i *% mt.base.size), + cast[pointer](s +% i *% mt.base.size), mt.base) diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 66d49ce1b..425963f3f 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -535,7 +535,7 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize copyMem(res, ol, oldsize + sizeof(Cell)) - zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)), + zeroMem(cast[pointer](cast[ByteAddress](res) +% oldsize +% sizeof(Cell)), newsize-oldsize) sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3") # This can be wrong for intermediate temps that are nevertheless on the diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim index 1ad4cf695..9609b6d39 100644 --- a/lib/system/osalloc.nim +++ b/lib/system/osalloc.nim @@ -58,7 +58,7 @@ when defined(emscripten): # Convert pointer to PageSize correct one. var new_pos = cast[ByteAddress](pos) +% (PageSize - (pos %% PageSize)) - if (new_pos-pos)< sizeof(EmscriptenMMapBlock): + if (new_pos-pos) < sizeof(EmscriptenMMapBlock): new_pos = new_pos +% PageSize result = cast[pointer](new_pos) From eef12654bd896df9b1219ea4bbd6381ccb920e58 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 5 May 2018 15:07:13 +0200 Subject: [PATCH 14/47] compiler/msgs.nim: minor code cleanup --- compiler/msgs.nim | 210 +++++++++++++++++++++++----------------------- 1 file changed, 105 insertions(+), 105 deletions(-) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 088742d18..b6cd05e06 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -146,7 +146,7 @@ const errUnknown: "unknown error", errInternal: "internal error: $1", errIllFormedAstX: "illformed AST: $1", - errCannotOpenFile: "cannot open \'$1\'", + errCannotOpenFile: "cannot open '$1'", errGenerated: "$1", errStringLiteralExpected: "string literal expected", errIntLiteralExpected: "integer literal expected", @@ -160,39 +160,39 @@ const errNumberOutOfRange: "number $1 out of valid range", errNnotAllowedInCharacter: "\\n not allowed in character literal", errClosingBracketExpected: "closing ']' expected, but end of file reached", - errMissingFinalQuote: "missing final \' for character literal", - errIdentifierExpected: "identifier expected, but found \'$1\'", - errNewlineExpected: "newline expected, but found \'$1\'", + errMissingFinalQuote: "missing final ' for character literal", + errIdentifierExpected: "identifier expected, but found '$1'", + errNewlineExpected: "newline expected, but found '$1'", errInvalidModuleName: "invalid module name: '$1'", - errOperatorExpected: "operator expected, but found \'$1\'", - errTokenExpected: "\'$1\' expected", - errRecursiveDependencyX: "recursive dependency: \'$1\'", - errOnOrOffExpected: "\'on\' or \'off\' expected", - errNoneSpeedOrSizeExpected: "\'none\', \'speed\' or \'size\' expected", + errOperatorExpected: "operator expected, but found '$1'", + errTokenExpected: "'$1' expected", + errRecursiveDependencyX: "recursive dependency: '$1'", + errOnOrOffExpected: "'on' or 'off' expected", + errNoneSpeedOrSizeExpected: "'none', 'speed' or 'size' expected", errInvalidPragma: "invalid pragma", - errUnknownPragma: "unknown pragma: \'$1\'", - errInvalidDirectiveX: "invalid directive: \'$1\'", - errAtPopWithoutPush: "\'pop\' without a \'push\' pragma", + errUnknownPragma: "unknown pragma: '$1'", + errInvalidDirectiveX: "invalid directive: '$1'", + errAtPopWithoutPush: "'pop' without a 'push' pragma", errEmptyAsm: "empty asm statement", errInvalidIndentation: "invalid indentation", errExceptionAlreadyHandled: "exception already handled", errYieldNotAllowedHere: "'yield' only allowed in an iterator", errYieldNotAllowedInTryStmt: "'yield' cannot be used within 'try' in a non-inlined iterator", - errInvalidNumberOfYieldExpr: "invalid number of \'yield\' expressions", + errInvalidNumberOfYieldExpr: "invalid number of 'yield' expressions", errCannotReturnExpr: "current routine cannot return an expression", errNoReturnWithReturnTypeNotAllowed: "routines with NoReturn pragma are not allowed to have return type", - errAttemptToRedefine: "redefinition of \'$1\'", - errStmtInvalidAfterReturn: "statement not allowed after \'return\', \'break\', \'raise\', \'continue\' or proc call with noreturn pragma", + errAttemptToRedefine: "redefinition of '$1'", + errStmtInvalidAfterReturn: "statement not allowed after 'return', 'break', 'raise', 'continue' or proc call with noreturn pragma", errStmtExpected: "statement expected", - errInvalidLabel: "\'$1\' is no label", - errInvalidCmdLineOption: "invalid command line option: \'$1\'", - errCmdLineArgExpected: "argument for command line option expected: \'$1\'", - errCmdLineNoArgExpected: "invalid argument for command line option: \'$1\'", - errInvalidVarSubstitution: "invalid variable substitution in \'$1\'", - errUnknownVar: "unknown variable: \'$1\'", - errUnknownCcompiler: "unknown C compiler: \'$1\'", - errOnOrOffExpectedButXFound: "\'on\' or \'off\' expected, but \'$1\' found", - errOnOffOrListExpectedButXFound: "\'on\', \'off\' or \'list\' expected, but \'$1\' found", + errInvalidLabel: "'$1' is no label", + errInvalidCmdLineOption: "invalid command line option: '$1'", + errCmdLineArgExpected: "argument for command line option expected: '$1'", + errCmdLineNoArgExpected: "invalid argument for command line option: '$1'", + errInvalidVarSubstitution: "invalid variable substitution in '$1'", + errUnknownVar: "unknown variable: '$1'", + errUnknownCcompiler: "unknown C compiler: '$1'", + errOnOrOffExpectedButXFound: "'on' or 'off' expected, but '$1' found", + errOnOffOrListExpectedButXFound: "'on', 'off' or 'list' expected, but '$1' found", errNoneBoehmRefcExpectedButXFound: "'none', 'boehm' or 'refc' expected, but '$1' found", errNoneSpeedOrSizeExpectedButXFound: "'none', 'speed' or 'size' expected, but '$1' found", errGuiConsoleOrLibExpectedButXFound: "'gui', 'console' or 'lib' expected, but '$1' found", @@ -201,19 +201,19 @@ const errGenOutExpectedButXFound: "'c', 'c++' or 'yaml' expected, but '$1' found", errArgsNeedRunOption: "arguments can only be given if the '--run' option is selected", errInvalidMultipleAsgn: "multiple assignment is not allowed", - errColonOrEqualsExpected: "\':\' or \'=\' expected, but found \'$1\'", - errExprExpected: "expression expected, but found \'$1\'", - errUndeclaredField: "undeclared field: \'$1\'", - errUndeclaredRoutine: "attempting to call undeclared routine: \'$1\'", - errUseQualifier: "ambiguous identifier: \'$1\' -- use a qualifier", + errColonOrEqualsExpected: "':' or '=' expected, but found '$1'", + errExprExpected: "expression expected, but found '$1'", + errUndeclaredField: "undeclared field: '$1'", + errUndeclaredRoutine: "attempting to call undeclared routine: '$1'", + errUseQualifier: "ambiguous identifier: '$1' -- use a qualifier", errTypeExpected: "type expected", - errSystemNeeds: "system module needs \'$1\'", + errSystemNeeds: "system module needs '$1'", errExecutionOfProgramFailed: "execution of an external program failed: '$1'", - errNotOverloadable: "overloaded \'$1\' leads to ambiguous calls", - errInvalidArgForX: "invalid argument for \'$1\'", + errNotOverloadable: "overloaded '$1' leads to ambiguous calls", + errInvalidArgForX: "invalid argument for '$1'", errStmtHasNoEffect: "statement has no effect", - errXExpectsTypeOrValue: "\'$1\' expects a type or value", - errXExpectsArrayType: "\'$1\' expects an array type", + errXExpectsTypeOrValue: "'$1' expects a type or value", + errXExpectsArrayType: "'$1' expects an array type", errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet", errExprXAmbiguous: "expression '$1' ambiguous in this context", errConstantDivisionByZero: "division by zero", @@ -221,26 +221,26 @@ const errOrdinalOrFloatTypeExpected: "ordinal or float type expected", errOverOrUnderflow: "over- or underflow", errCannotEvalXBecauseIncompletelyDefined: "cannot evaluate '$1' because type is not defined completely", - errChrExpectsRange0_255: "\'chr\' expects an int in the range 0..255", - errDynlibRequiresExportc: "\'dynlib\' requires \'exportc\'", - errUndeclaredFieldX: "undeclared field: \'$1\'", + errChrExpectsRange0_255: "'chr' expects an int in the range 0..255", + errDynlibRequiresExportc: "'dynlib' requires 'exportc'", + errUndeclaredFieldX: "undeclared field: '$1'", errNilAccess: "attempt to access a nil address", errIndexOutOfBounds: "index out of bounds", errIndexTypesDoNotMatch: "index types do not match", - errBracketsInvalidForType: "\'[]\' operator invalid for this type", + errBracketsInvalidForType: "'[]' operator invalid for this type", errValueOutOfSetBounds: "value out of set bounds", - errFieldInitTwice: "field initialized twice: \'$1\'", - errFieldNotInit: "field \'$1\' not initialized", - errExprXCannotBeCalled: "expression \'$1\' cannot be called", + errFieldInitTwice: "field initialized twice: '$1'", + errFieldNotInit: "field '$1' not initialized", + errExprXCannotBeCalled: "expression '$1' cannot be called", errExprHasNoType: "expression has no type", - errExprXHasNoType: "expression \'$1\' has no type (or is ambiguous)", - errCastNotInSafeMode: "\'cast\' not allowed in safe mode", + errExprXHasNoType: "expression '$1' has no type (or is ambiguous)", + errCastNotInSafeMode: "'cast' not allowed in safe mode", errExprCannotBeCastToX: "expression cannot be cast to $1", errCommaOrParRiExpected: "',' or ')' expected", - errCurlyLeOrParLeExpected: "\'{\' or \'(\' expected", - errSectionExpected: "section (\'type\', \'proc\', etc.) expected", + errCurlyLeOrParLeExpected: "'{' or '(' expected", + errSectionExpected: "section ('type', 'proc', etc.) expected", errRangeExpected: "range expected", - errMagicOnlyInSystem: "\'magic\' only allowed in system module", + errMagicOnlyInSystem: "'magic' only allowed in system module", errPowerOfTwoExpected: "power of two expected", errStringMayNotBeEmpty: "string literal may not be empty", errCallConvExpected: "calling convention expected", @@ -257,51 +257,51 @@ const errWrongNumberOfVariables: "wrong number of variables", errExprCannotBeRaised: "only a 'ref object' can be raised", errBreakOnlyInLoop: "'break' only allowed in loop construct", - errTypeXhasUnknownSize: "type \'$1\' has unknown size", + errTypeXhasUnknownSize: "type '$1' has unknown size", errConstNeedsConstExpr: "a constant can only be initialized with a constant expression", errConstNeedsValue: "a constant needs a value", errResultCannotBeOpenArray: "the result type cannot be on open array", - errSizeTooBig: "computing the type\'s size produced an overflow", + errSizeTooBig: "computing the type's size produced an overflow", errSetTooBig: "set is too large", errBaseTypeMustBeOrdinal: "base type of a set must be an ordinal", errInheritanceOnlyWithNonFinalObjects: "inheritance only works with non-final objects", errInheritanceOnlyWithEnums: "inheritance only works with an enum", - errIllegalRecursionInTypeX: "illegal recursion in type \'$1\'", - errCannotInstantiateX: "cannot instantiate: \'$1\'", + errIllegalRecursionInTypeX: "illegal recursion in type '$1'", + errCannotInstantiateX: "cannot instantiate: '$1'", errExprHasNoAddress: "expression has no address", errXStackEscape: "address of '$1' may not escape its stack frame", - errVarForOutParamNeededX: "for a \'var\' type a variable needs to be passed; but '$1' is immutable", + errVarForOutParamNeededX: "for a 'var' type a variable needs to be passed; but '$1' is immutable", errPureTypeMismatch: "type mismatch", errTypeMismatch: "type mismatch: got <", errButExpected: "but expected one of: ", - errButExpectedX: "but expected \'$1\'", + errButExpectedX: "but expected '$1'", errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3", errWrongNumberOfArguments: "wrong number of arguments", errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'", errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters", - errXCannotBePassedToProcVar: "\'$1\' cannot be passed to a procvar", + errXCannotBePassedToProcVar: "'$1' cannot be passed to a procvar", errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1", - errImplOfXNotAllowed: "implementation of \'$1\' is not allowed", - errImplOfXexpected: "implementation of \'$1\' expected", + errImplOfXNotAllowed: "implementation of '$1' is not allowed", + errImplOfXexpected: "implementation of '$1' expected", errNoSymbolToBorrowFromFound: "no symbol to borrow from found", errDiscardValueX: "value of type '$1' has to be discarded", errInvalidDiscard: "statement returns no value that can be discarded", errIllegalConvFromXtoY: "conversion from $1 to $2 is invalid", - errCannotBindXTwice: "cannot bind parameter \'$1\' twice", + errCannotBindXTwice: "cannot bind parameter '$1' twice", errInvalidOrderInArrayConstructor: "invalid order in array constructor", - errInvalidOrderInEnumX: "invalid order in enum \'$1\'", - errEnumXHasHoles: "enum \'$1\' has holes", - errExceptExpected: "\'except\' or \'finally\' expected", - errInvalidTry: "after catch all \'except\' or \'finally\' no section may follow", - errOptionExpected: "option expected, but found \'$1\'", - errXisNoLabel: "\'$1\' is not a label", + errInvalidOrderInEnumX: "invalid order in enum '$1'", + errEnumXHasHoles: "enum '$1' has holes", + errExceptExpected: "'except' or 'finally' expected", + errInvalidTry: "after catch all 'except' or 'finally' no section may follow", + errOptionExpected: "option expected, but found '$1'", + errXisNoLabel: "'$1' is not a label", errNotAllCasesCovered: "not all cases are covered", - errUnknownSubstitionVar: "unknown substitution variable: \'$1\'", + errUnknownSubstitionVar: "unknown substitution variable: '$1'", errComplexStmtRequiresInd: "complex statement requires indentation", - errXisNotCallable: "\'$1\' is not callable", + errXisNotCallable: "'$1' is not callable", errNoPragmasAllowedForX: "no pragmas allowed for $1", errNoGenericParamsAllowedForX: "no generic parameters allowed for $1", - errInvalidParamKindX: "invalid param kind: \'$1\'", + errInvalidParamKindX: "invalid param kind: '$1'", errDefaultArgumentInvalid: "default argument invalid", errNamedParamHasToBeIdent: "named parameter has to be an identifier", errNoReturnTypeForX: "no return type allowed for $1", @@ -309,24 +309,24 @@ const errInvalidPragmaX: "invalid pragma: $1", errXNotAllowedHere: "$1 not allowed here", errInvalidControlFlowX: "invalid control flow: $1", - errXisNoType: "invalid type: \'$1\'", + errXisNoType: "invalid type: '$1'", errCircumNeedsPointer: "'[]' needs a pointer or reference type", errInvalidExpression: "invalid expression", - errInvalidExpressionX: "invalid expression: \'$1\'", - errEnumHasNoValueX: "enum has no value \'$1\'", + errInvalidExpressionX: "invalid expression: '$1'", + errEnumHasNoValueX: "enum has no value '$1'", errNamedExprExpected: "named expression expected", errNamedExprNotAllowed: "named expression not allowed here", - errXExpectsOneTypeParam: "\'$1\' expects one type parameter", + errXExpectsOneTypeParam: "'$1' expects one type parameter", errArrayExpectsTwoTypeParams: "array expects two type parameters", - errInvalidVisibilityX: "invalid visibility: \'$1\'", + errInvalidVisibilityX: "invalid visibility: '$1'", errInitHereNotAllowed: "initialization not allowed here", - errXCannotBeAssignedTo: "\'$1\' cannot be assigned to", - errIteratorNotAllowed: "iterators can only be defined at the module\'s top level", + errXCannotBeAssignedTo: "'$1' cannot be assigned to", + errIteratorNotAllowed: "iterators can only be defined at the module's top level", errXNeedsReturnType: "$1 needs a return type", errNoReturnTypeDeclared: "no return type declared", errNoCommand: "no command given", - errInvalidCommandX: "invalid command: \'$1\'", - errXOnlyAtModuleScope: "\'$1\' is only allowed at top level", + errInvalidCommandX: "invalid command: '$1'", + errXOnlyAtModuleScope: "'$1' is only allowed at top level", errXNeedsParamObjectType: "'$1' needs a parameter that has an object type", errTemplateInstantiationTooNested: "template instantiation too nested, try --evalTemplateLimit:N", errMacroInstantiationTooNested: "macro instantiation too nested, try --evalMacroLimit:N", @@ -334,17 +334,17 @@ const errInvalidIndexValueForTuple: "invalid index value for tuple subscript", errCommandExpectsFilename: "command expects a filename argument", errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file", - errXExpected: "\'$1\' expected", - errTIsNotAConcreteType: "\'$1\' is not a concrete type.", - errCastToANonConcreteType: "cannot cast to a non concrete type: \'$1\'", + errXExpected: "'$1' expected", + errTIsNotAConcreteType: "'$1' is not a concrete type.", + errCastToANonConcreteType: "cannot cast to a non concrete type: '$1'", errInvalidSectionStart: "invalid section start", errGridTableNotImplemented: "grid table is not implemented", errGeneralParseError: "general parse error", errNewSectionExpected: "new section expected", - errWhitespaceExpected: "whitespace expected, got \'$1\'", - errXisNoValidIndexFile: "\'$1\' is no valid index file", - errCannotRenderX: "cannot render reStructuredText element \'$1\'", - errVarVarTypeNotAllowed: "type \'var var\' is not allowed", + errWhitespaceExpected: "whitespace expected, got '$1'", + errXisNoValidIndexFile: "'$1' is no valid index file", + errCannotRenderX: "cannot render reStructuredText element '$1'", + errVarVarTypeNotAllowed: "type 'var var' is not allowed", errInstantiateXExplicitly: "instantiate '$1' explicitly", errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator", errUsingNoSymbol: "'$1' is not a variable, constant or a proc name", @@ -354,26 +354,26 @@ const "A destructor must be associated will all instantiations of a generic type", errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " & "templates, macros and other inline iterators", - errXExpectsTwoArguments: "\'$1\' expects two arguments", - errXExpectsObjectTypes: "\'$1\' expects object types", - errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype", + errXExpectsTwoArguments: "'$1' expects two arguments", + errXExpectsObjectTypes: "'$1' expects object types", + errXcanNeverBeOfThisSubtype: "'$1' can never be of this subtype", errTooManyIterations: "interpretation requires too many iterations; " & "if you are sure this is not a bug in your code edit " & "compiler/vmdef.MaxLoopIterations and rebuild the compiler", - errCannotInterpretNodeX: "cannot evaluate \'$1\'", - errFieldXNotFound: "field \'$1\' cannot be found", - errInvalidConversionFromTypeX: "invalid conversion from type \'$1\'", + errCannotInterpretNodeX: "cannot evaluate '$1'", + errFieldXNotFound: "field '$1' cannot be found", + errInvalidConversionFromTypeX: "invalid conversion from type '$1'", errAssertionFailed: "assertion failed", - errCannotGenerateCodeForX: "cannot generate code for \'$1\'", + errCannotGenerateCodeForX: "cannot generate code for '$1'", errXRequiresOneArgument: "$1 requires one parameter", errUnhandledExceptionX: "unhandled exception: $1", errCyclicTree: "macro returned a cyclic abstract syntax tree", - errXisNoMacroOrTemplate: "\'$1\' is no macro or template", - errXhasSideEffects: "\'$1\' can have side effects", + errXisNoMacroOrTemplate: "'$1' is no macro or template", + errXhasSideEffects: "'$1' can have side effects", errIteratorExpected: "iterator within for loop context expected", errLetNeedsInit: "'let' symbol requires an initialization", errThreadvarCannotInit: "a thread var cannot be initialized explicitly; this would only run for the main thread", - errWrongSymbolX: "usage of \'$1\' is a user-defined error", + errWrongSymbolX: "usage of '$1' is a user-defined error", errIllegalCaptureX: "illegal capture '$1'", errXCannotBeClosure: "'$1' cannot have 'closure' calling convention", errXMustBeCompileTime: "'$1' can only be used in compile-time context", @@ -384,22 +384,22 @@ const "it is used as an operand to another routine and the types " & "of the generic paramers can be inferred from the expected signature.", errProcHasNoConcreteType: "'$1' doesn't have a concrete type, due to unspecified generic parameters.", - errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target", + errCompilerDoesntSupportTarget: "The current compiler '$1' doesn't support the requested compilation target", errInOutFlagNotExtern: "The `$1` modifier can be used only with imported types", errUser: "$1", - warnCannotOpenFile: "cannot open \'$1\'", + warnCannotOpenFile: "cannot open '$1'", warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored", - warnXIsNeverRead: "\'$1\' is never read", - warnXmightNotBeenInit: "\'$1\' might not have been initialized", + warnXIsNeverRead: "'$1' is never read", + warnXmightNotBeenInit: "'$1' might not have been initialized", warnDeprecated: "$1 is deprecated", warnConfigDeprecated: "config file '$1' is deprecated", - warnSmallLshouldNotBeUsed: "\'l\' should not be used as an identifier; may look like \'1\' (one)", - warnUnknownMagic: "unknown magic \'$1\' might crash the compiler", - warnRedefinitionOfLabel: "redefinition of label \'$1\'", - warnUnknownSubstitutionX: "unknown substitution \'$1\'", - warnLanguageXNotSupported: "language \'$1\' not supported", - warnFieldXNotSupported: "field \'$1\' not supported", - warnCommentXIgnored: "comment \'$1\' ignored", + warnSmallLshouldNotBeUsed: "'l' should not be used as an identifier; may look like '1' (one)", + warnUnknownMagic: "unknown magic '$1' might crash the compiler", + warnRedefinitionOfLabel: "redefinition of label '$1'", + warnUnknownSubstitutionX: "unknown substitution '$1'", + warnLanguageXNotSupported: "language '$1' not supported", + warnFieldXNotSupported: "field '$1' not supported", + warnCommentXIgnored: "comment '$1' ignored", warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'", warnUseBase: "use {.base.} for base methods; baseless methods are deprecated", warnWriteToForeignHeap: "write to foreign heap", @@ -421,15 +421,15 @@ const hintSuccess: "operation successful", hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)", hintLineTooLong: "line too long", - hintXDeclaredButNotUsed: "\'$1\' is declared but not used", + hintXDeclaredButNotUsed: "'$1' is declared but not used", hintConvToBaseNotNeeded: "conversion to base object is not needed", hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless", - hintExprAlwaysX: "expression evaluates always to \'$1\'", + hintExprAlwaysX: "expression evaluates always to '$1'", hintQuitCalled: "quit() called", hintProcessing: "$1", hintCodeBegin: "generated code listing:", hintCodeEnd: "end of listing", - hintConf: "used config file \'$1\'", + hintConf: "used config file '$1'", hintPath: "added path: '$1'", hintConditionAlwaysTrue: "condition is always true: '$1'", hintName: "name should be: '$1'", From b7116a28eea13f4fd82b8b22323f2f75c813794f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 5 May 2018 18:47:29 +0200 Subject: [PATCH 15/47] compiler refactoring, pass config around explicitly --- compiler/docgen.nim | 6 +- compiler/lexer.nim | 35 +- compiler/main.nim | 13 +- compiler/modules.nim | 2 +- compiler/nimconf.nim | 2 +- compiler/options.nim | 1 + compiler/parser.nim | 16 +- compiler/passes.nim | 2 +- compiler/pbraces.nim | 1790 ------------------------------------- compiler/reorder.nim | 8 +- compiler/scriptconfig.nim | 2 +- compiler/sem.nim | 6 +- compiler/semexprs.nim | 6 +- compiler/semstmts.nim | 5 +- compiler/syntaxes.nim | 29 +- compiler/vm.nim | 41 +- compiler/vmdef.nim | 8 +- 17 files changed, 93 insertions(+), 1879 deletions(-) delete mode 100644 compiler/pbraces.nim diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 6f3dcde8b..e1a70a23e 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -790,7 +790,7 @@ proc writeOutputJson*(d: PDoc, filename, outExt: string, discard "fixme: error report" proc commandDoc*() = - var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache()) + var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef()) if ast == nil: return var d = newDocumentor(gProjectFull, options.gConfigVars) d.hasToc = true @@ -840,7 +840,7 @@ proc commandRst2TeX*() = commandRstAux(gProjectFull, TexExt) proc commandJson*() = - var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache()) + var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef()) if ast == nil: return var d = newDocumentor(gProjectFull, options.gConfigVars) d.hasToc = true @@ -855,7 +855,7 @@ proc commandJson*() = writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false) proc commandTags*() = - var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache()) + var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef()) if ast == nil: return var d = newDocumentor(gProjectFull, options.gConfigVars) d.hasToc = true diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 0478ed574..0aeb44ca3 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -144,13 +144,12 @@ type cache*: IdentCache when defined(nimsuggest): previousToken: TLineInfo + config*: ConfigRef when defined(nimpretty): var gIndentationWidth*: int -var gLinesCompiled*: int # all lines that have been compiled - proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} = result = newLineInfo(L.fileIdx, tok.line, tok.col) when defined(nimpretty): @@ -222,7 +221,7 @@ proc fillToken(L: var TToken) = L.commentOffsetB = 0 proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream; - cache: IdentCache) = + cache: IdentCache; config: ConfigRef) = openBaseLexer(lex, inputstream) lex.fileIdx = fileidx lex.indentAhead = - 1 @@ -231,13 +230,14 @@ proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream; lex.cache = cache when defined(nimsuggest): lex.previousToken.fileIndex = fileIdx + lex.config = config proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream; - cache: IdentCache) = - openLexer(lex, filename.fileInfoIdx, inputstream, cache) + cache: IdentCache; config: ConfigRef) = + openLexer(lex, filename.fileInfoIdx, inputstream, cache, config) proc closeLexer*(lex: var TLexer) = - inc(gLinesCompiled, lex.lineNumber) + inc(lex.config.linesCompiled, lex.lineNumber) closeBaseLexer(lex) proc getLineInfo(L: TLexer): TLineInfo = @@ -576,17 +576,18 @@ proc getNumber(L: var TLexer, result: var TToken) = result.iNumber = parseBiggestInt(result.literal) # Explicit bounds checks - let outOfRange = case result.tokType: - of tkInt8Lit: (result.iNumber < int8.low or result.iNumber > int8.high) - of tkUInt8Lit: (result.iNumber < BiggestInt(uint8.low) or - result.iNumber > BiggestInt(uint8.high)) - of tkInt16Lit: (result.iNumber < int16.low or result.iNumber > int16.high) - of tkUInt16Lit: (result.iNumber < BiggestInt(uint16.low) or - result.iNumber > BiggestInt(uint16.high)) - of tkInt32Lit: (result.iNumber < int32.low or result.iNumber > int32.high) - of tkUInt32Lit: (result.iNumber < BiggestInt(uint32.low) or - result.iNumber > BiggestInt(uint32.high)) - else: false + let outOfRange = + case result.tokType + of tkInt8Lit: (result.iNumber < int8.low or result.iNumber > int8.high) + of tkUInt8Lit: (result.iNumber < BiggestInt(uint8.low) or + result.iNumber > BiggestInt(uint8.high)) + of tkInt16Lit: (result.iNumber < int16.low or result.iNumber > int16.high) + of tkUInt16Lit: (result.iNumber < BiggestInt(uint16.low) or + result.iNumber > BiggestInt(uint16.high)) + of tkInt32Lit: (result.iNumber < int32.low or result.iNumber > int32.high) + of tkUInt32Lit: (result.iNumber < BiggestInt(uint32.low) or + result.iNumber > BiggestInt(uint32.high)) + else: false if outOfRange: lexMessageLitNum(L, errNumberOutOfRange, startpos) diff --git a/compiler/main.nim b/compiler/main.nim index 401099fc3..f23a3a88e 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -129,9 +129,10 @@ proc commandEval(graph: ModuleGraph; cache: IdentCache; exp: string) = interactivePasses(graph, cache) compileSystemModule(graph, cache) let echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")" - evalNim(graph, echoExp.parseString(cache), makeStdinModule(graph), cache) + evalNim(graph, echoExp.parseString(cache, graph.config), + makeStdinModule(graph), cache) -proc commandScan(cache: IdentCache) = +proc commandScan(cache: IdentCache, config: ConfigRef) = var f = addFileExt(mainCommandArg(), NimExt) var stream = llStreamOpen(f, fmRead) if stream != nil: @@ -139,7 +140,7 @@ proc commandScan(cache: IdentCache) = L: TLexer tok: TToken initToken(tok) - openLexer(L, f, stream, cache) + openLexer(L, f, stream, cache, config) while true: rawGetTok(L, tok) printTok(tok) @@ -265,11 +266,11 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = of "parse": gCmd = cmdParse wantMainModule() - discard parseFile(FileIndex gProjectMainIdx, cache) + discard parseFile(FileIndex gProjectMainIdx, cache, graph.config) of "scan": gCmd = cmdScan wantMainModule() - commandScan(cache) + commandScan(cache, graph.config) msgWriteln("Beware: Indentation tokens depend on the parser's state!") of "secret": gCmd = cmdInteractive @@ -291,7 +292,7 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = let usedMem = formatSize(getMaxMem()) & " peakmem" else: let usedMem = formatSize(getTotalMem()) - rawMessage(hintSuccessX, [$gLinesCompiled, + rawMessage(hintSuccessX, [$graph.config.linesCompiled, formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3), usedMem, if condSyms.isDefined("release"): "Release Build" diff --git a/compiler/modules.nim b/compiler/modules.nim index 56bfdf662..7fe2336dd 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -107,7 +107,7 @@ proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex; proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex; cache: IdentCache): PNode {.procvar.} = - result = syntaxes.parseFile(fileIdx, cache) + result = syntaxes.parseFile(fileIdx, cache, graph.config) graph.addDep(s, fileIdx) graph.addIncludeDep(s.position.FileIndex, fileIdx) diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index bdf558134..dc8d082b3 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -205,7 +205,7 @@ proc readConfigFile(filename: string; cache: IdentCache; config: ConfigRef) = stream = llStreamOpen(filename, fmRead) if stream != nil: initToken(tok) - openLexer(L, filename, stream, cache) + openLexer(L, filename, stream, cache, config) tok.tokType = tkEof # to avoid a pointless warning confTok(L, tok, config) # read in the first token while tok.tokType != tkEof: parseAssignment(L, tok, config) diff --git a/compiler/options.nim b/compiler/options.nim index 5baaa1bfd..f8cb735ae 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -113,6 +113,7 @@ type notnil ConfigRef* = ref object ## eventually all global configuration should be moved here + linesCompiled*: int # all lines that have been compiled cppDefines*: HashSet[string] headerFile*: string features*: set[Feature] diff --git a/compiler/parser.nim b/compiler/parser.nim index c61519541..14683e307 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -27,7 +27,7 @@ when isMainModule: outp.close import - llstream, lexer, idents, strutils, ast, astalgo, msgs + llstream, lexer, idents, strutils, ast, astalgo, msgs, options type TParser* = object # A TParser object represents a file that @@ -84,20 +84,20 @@ proc getTok(p: var TParser) = p.hasProgress = true proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream, - cache: IdentCache; + cache: IdentCache; config: ConfigRef; strongSpaces=false) = ## Open a parser, using the given arguments to set up its internal state. ## initToken(p.tok) - openLexer(p.lex, fileIdx, inputStream, cache) + openLexer(p.lex, fileIdx, inputStream, cache, config) getTok(p) # read the first token p.firstTok = true p.strongSpaces = strongSpaces proc openParser*(p: var TParser, filename: string, inputStream: PLLStream, - cache: IdentCache; + cache: IdentCache; config: ConfigRef; strongSpaces=false) = - openParser(p, filename.fileInfoIdx, inputStream, cache, strongSpaces) + openParser(p, filename.fileInfoIdx, inputStream, cache, config, strongSpaces) proc closeParser(p: var TParser) = ## Close a parser, freeing up its resources. @@ -2178,8 +2178,8 @@ proc parseTopLevelStmt(p: var TParser): PNode = if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok) break -proc parseString*(s: string; cache: IdentCache; filename: string = ""; - line: int = 0; +proc parseString*(s: string; cache: IdentCache; config: ConfigRef; + filename: string = ""; line: int = 0; errorHandler: TErrorHandler = nil): PNode = ## Parses a string into an AST, returning the top node. ## `filename` and `line`, although optional, provide info so that the @@ -2192,7 +2192,7 @@ proc parseString*(s: string; cache: IdentCache; filename: string = ""; # XXX for now the builtin 'parseStmt/Expr' functions do not know about strong # spaces... parser.lex.errorHandler = errorHandler - openParser(parser, filename, stream, cache, false) + openParser(parser, filename, stream, cache, config, false) result = parser.parseAll closeParser(parser) diff --git a/compiler/passes.nim b/compiler/passes.nim index 6ff3f2bb5..b104cd132 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -207,7 +207,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, else: s = stream while true: - openParsers(p, fileIdx, s, cache) + openParsers(p, fileIdx, s, cache, graph.config) if sfSystemModule notin module.flags: # XXX what about caching? no processing then? what if I change the diff --git a/compiler/pbraces.nim b/compiler/pbraces.nim deleted file mode 100644 index fe438d58b..000000000 --- a/compiler/pbraces.nim +++ /dev/null @@ -1,1790 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2017 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -# This module implements the parser of the braces Nim syntax. - -import - llstream, lexer, idents, strutils, ast, astalgo, msgs - -from parser import TParser - -proc getTok(p: var TParser) = - ## Get the next token from the parser's lexer, and store it in the parser's - ## `tok` member. - rawGetTok(p.lex, p.tok) - -proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream; - cache: IdentCache) = - ## Open a parser, using the given arguments to set up its internal state. - ## - initToken(p.tok) - openLexer(p.lex, fileIdx, inputStream, cache) - getTok(p) # read the first token - p.lex.allowTabs = true - -proc openParser*(p: var TParser, filename: string, inputStream: PLLStream; - cache: IdentCache) = - openParser(p, filename.fileInfoIdx, inputStream, cache) - -proc closeParser*(p: var TParser) = - ## Close a parser, freeing up its resources. - closeLexer(p.lex) - -proc parMessage(p: TParser, msg: TMsgKind, arg = "") = - ## Produce and emit the parser message `arg` to output. - lexMessageTok(p.lex, msg, p.tok, arg) - -proc parMessage(p: TParser, msg: TMsgKind, tok: TToken) = - ## Produce and emit a parser message to output about the token `tok` - parMessage(p, msg, prettyTok(tok)) - -proc rawSkipComment(p: var TParser, node: PNode) = - if p.tok.tokType == tkComment: - if node != nil: - if node.comment == nil: node.comment = "" - add(node.comment, p.tok.literal) - else: - parMessage(p, errInternal, "skipComment") - getTok(p) - -proc skipComment(p: var TParser, node: PNode) = - rawSkipComment(p, node) - -proc flexComment(p: var TParser, node: PNode) = - rawSkipComment(p, node) - -proc skipInd(p: var TParser) = discard -proc optPar(p: var TParser) = discard - -proc optInd(p: var TParser, n: PNode) = - skipComment(p, n) - -proc getTokNoInd(p: var TParser) = - getTok(p) - -proc expectIdentOrKeyw(p: TParser) = - if p.tok.tokType != tkSymbol and not isKeyword(p.tok.tokType): - lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok)) - -proc expectIdent(p: TParser) = - if p.tok.tokType != tkSymbol: - lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok)) - -proc eat(p: var TParser, tokType: TTokType) = - ## Move the parser to the next token if the current token is of type - ## `tokType`, otherwise error. - if p.tok.tokType == tokType: - getTok(p) - else: - lexMessageTok(p.lex, errTokenExpected, p.tok, TokTypeToStr[tokType]) - -proc parLineInfo(p: TParser): TLineInfo = - ## Retrieve the line information associated with the parser's current state. - result = getLineInfo(p.lex, p.tok) - -proc indAndComment(p: var TParser, n: PNode) = - rawSkipComment(p, n) - -proc newNodeP(kind: TNodeKind, p: TParser): PNode = - result = newNodeI(kind, parLineInfo(p)) - -proc newIntNodeP(kind: TNodeKind, intVal: BiggestInt, p: TParser): PNode = - result = newNodeP(kind, p) - result.intVal = intVal - -proc newFloatNodeP(kind: TNodeKind, floatVal: BiggestFloat, - p: TParser): PNode = - result = newNodeP(kind, p) - result.floatVal = floatVal - -proc newStrNodeP(kind: TNodeKind, strVal: string, p: TParser): PNode = - result = newNodeP(kind, p) - result.strVal = strVal - -proc newIdentNodeP(ident: PIdent, p: TParser): PNode = - result = newNodeP(nkIdent, p) - result.ident = ident - -proc parseExpr(p: var TParser): PNode -proc parseStmt(p: var TParser): PNode -proc parseTypeDesc(p: var TParser): PNode -proc parseDoBlocks(p: var TParser, call: PNode) -proc parseParamList(p: var TParser, retColon = true): PNode -proc parseStmtPragma(p: var TParser): PNode -proc parseCase(p: var TParser): PNode -proc parseTry(p: var TParser): PNode - -proc isSigilLike(tok: TToken): bool {.inline.} = - result = tok.tokType == tkOpr and tok.ident.s[0] == '@' - -proc isAt(tok: TToken): bool {.inline.} = - tok.tokType == tkOpr and tok.ident.s == "@" and tok.strongSpaceB == 0 - -proc isRightAssociative(tok: TToken): bool {.inline.} = - ## Determines whether the token is right assocative. - result = tok.tokType == tkOpr and tok.ident.s[0] == '^' - # or (let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>')) - -proc getPrecedence(tok: TToken): int = - ## Calculates the precedence of the given token. - template considerStrongSpaces(x): untyped = x - - case tok.tokType - of tkOpr: - let L = tok.ident.s.len - let relevantChar = tok.ident.s[0] - - # arrow like? - if L > 1 and tok.ident.s[L-1] == '>' and - tok.ident.s[L-2] in {'-', '~', '='}: return considerStrongSpaces(1) - - template considerAsgn(value: untyped) = - result = if tok.ident.s[L-1] == '=': 1 else: value - - case relevantChar - of '$', '^': considerAsgn(10) - of '*', '%', '/', '\\': considerAsgn(9) - of '~': result = 8 - of '+', '-', '|': considerAsgn(8) - of '&': considerAsgn(7) - of '=', '<', '>', '!': result = 5 - of '.': considerAsgn(6) - of '?': result = 2 - else: considerAsgn(2) - of tkDiv, tkMod, tkShl, tkShr: result = 9 - of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5 - of tkDotDot: result = 6 - of tkAnd: result = 4 - of tkOr, tkXor, tkPtr, tkRef: result = 3 - else: return -10 - result = considerStrongSpaces(result) - -proc isOperator(tok: TToken): bool = - ## Determines if the given token is an operator type token. - tok.tokType in {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs, - tkIsnot, tkNot, tkOf, tkAs, tkDotDot, tkAnd, tkOr, tkXor} - -proc isUnary(p: TParser): bool = - ## Check if the current parser token is a unary operator - if p.tok.tokType in {tkOpr, tkDotDot}: - result = true - -proc checkBinary(p: TParser) {.inline.} = - ## Check if the current parser token is a binary operator. - # we don't check '..' here as that's too annoying - discard - -#| module = stmt ^* (';' / IND{=}) -#| -#| comma = ',' COMMENT? -#| semicolon = ';' COMMENT? -#| colon = ':' COMMENT? -#| colcom = ':' COMMENT? -#| -#| operator = OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9 -#| | 'or' | 'xor' | 'and' -#| | 'is' | 'isnot' | 'in' | 'notin' | 'of' -#| | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'static' | '..' -#| -#| prefixOperator = operator -#| -#| optInd = COMMENT? -#| optPar = (IND{>} | IND{=})? -#| -#| simpleExpr = arrowExpr (OP0 optInd arrowExpr)* -#| arrowExpr = assignExpr (OP1 optInd assignExpr)* -#| assignExpr = orExpr (OP2 optInd orExpr)* -#| orExpr = andExpr (OP3 optInd andExpr)* -#| andExpr = cmpExpr (OP4 optInd cmpExpr)* -#| cmpExpr = sliceExpr (OP5 optInd sliceExpr)* -#| sliceExpr = ampExpr (OP6 optInd ampExpr)* -#| ampExpr = plusExpr (OP7 optInd plusExpr)* -#| plusExpr = mulExpr (OP8 optInd mulExpr)* -#| mulExpr = dollarExpr (OP9 optInd dollarExpr)* -#| dollarExpr = primary (OP10 optInd primary)* - -proc colcom(p: var TParser, n: PNode) = - skipComment(p, n) - -proc parseSymbol(p: var TParser, allowNil = false): PNode = - #| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`' - #| | IDENT | 'addr' | 'type' - case p.tok.tokType - of tkSymbol, tkAddr, tkType: - result = newIdentNodeP(p.tok.ident, p) - getTok(p) - of tkAccent: - result = newNodeP(nkAccQuoted, p) - getTok(p) - while true: - case p.tok.tokType - of tkAccent: - if result.len == 0: - parMessage(p, errIdentifierExpected, p.tok) - break - of tkOpr, tkDot, tkDotDot, tkEquals, tkParLe..tkParDotRi: - var accm = "" - while p.tok.tokType in {tkOpr, tkDot, tkDotDot, tkEquals, - tkParLe..tkParDotRi}: - accm.add(tokToStr(p.tok)) - getTok(p) - result.add(newIdentNodeP(p.lex.cache.getIdent(accm), p)) - of tokKeywordLow..tokKeywordHigh, tkSymbol, tkIntLit..tkCharLit: - result.add(newIdentNodeP(p.lex.cache.getIdent(tokToStr(p.tok)), p)) - getTok(p) - else: - parMessage(p, errIdentifierExpected, p.tok) - break - eat(p, tkAccent) - else: - if allowNil and p.tok.tokType == tkNil: - result = newNodeP(nkNilLit, p) - getTok(p) - else: - parMessage(p, errIdentifierExpected, p.tok) - # BUGFIX: We must consume a token here to prevent endless loops! - # But: this really sucks for idetools and keywords, so we don't do it - # if it is a keyword: - if not isKeyword(p.tok.tokType): getTok(p) - result = ast.emptyNode - -proc colonOrEquals(p: var TParser, a: PNode): PNode = - if p.tok.tokType == tkColon: - result = newNodeP(nkExprColonExpr, p) - getTok(p) - #optInd(p, result) - addSon(result, a) - addSon(result, parseExpr(p)) - elif p.tok.tokType == tkEquals: - result = newNodeP(nkExprEqExpr, p) - getTok(p) - #optInd(p, result) - addSon(result, a) - addSon(result, parseExpr(p)) - else: - result = a - -proc exprColonEqExpr(p: var TParser): PNode = - #| exprColonEqExpr = expr (':'|'=' expr)? - var a = parseExpr(p) - result = colonOrEquals(p, a) - -proc exprList(p: var TParser, endTok: TTokType, result: PNode) = - #| exprList = expr ^+ comma - getTok(p) - optInd(p, result) - while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof): - var a = parseExpr(p) - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, a) - -proc dotExpr(p: var TParser, a: PNode): PNode = - #| dotExpr = expr '.' optInd symbol - var info = p.parLineInfo - getTok(p) - result = newNodeI(nkDotExpr, info) - optInd(p, result) - addSon(result, a) - addSon(result, parseSymbol(p)) - -proc qualifiedIdent(p: var TParser): PNode = - #| qualifiedIdent = symbol ('.' optInd symbol)? - result = parseSymbol(p) - if p.tok.tokType == tkDot: result = dotExpr(p, result) - -proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) = - assert(endTok in {tkCurlyLe, tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi}) - getTok(p) - optInd(p, result) - while p.tok.tokType != endTok and p.tok.tokType != tkEof: - var a = exprColonEqExpr(p) - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - skipComment(p, a) - optPar(p) - eat(p, endTok) - -proc exprColonEqExprList(p: var TParser, kind: TNodeKind, - endTok: TTokType): PNode = - #| exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)? - result = newNodeP(kind, p) - exprColonEqExprListAux(p, endTok, result) - -proc setOrTableConstr(p: var TParser): PNode = - result = newNodeP(nkCurly, p) - getTok(p) - optInd(p, result) - if p.tok.tokType == tkColon: - getTok(p) # skip ':' - result.kind = nkTableConstr - else: - while p.tok.tokType notin {tkBracketDotRi, tkEof}: - var a = exprColonEqExpr(p) - if a.kind == nkExprColonExpr: result.kind = nkTableConstr - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - skipComment(p, a) - optPar(p) - eat(p, tkBracketDotRi) - -proc parseCast(p: var TParser): PNode = - #| castExpr = 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')' - result = newNodeP(nkCast, p) - getTok(p) - eat(p, tkBracketLe) - optInd(p, result) - addSon(result, parseTypeDesc(p)) - optPar(p) - eat(p, tkBracketRi) - eat(p, tkParLe) - optInd(p, result) - addSon(result, parseExpr(p)) - optPar(p) - eat(p, tkParRi) - -proc setBaseFlags(n: PNode, base: TNumericalBase) = - case base - of base10: discard - of base2: incl(n.flags, nfBase2) - of base8: incl(n.flags, nfBase8) - of base16: incl(n.flags, nfBase16) - -proc parseGStrLit(p: var TParser, a: PNode): PNode = - case p.tok.tokType - of tkGStrLit: - result = newNodeP(nkCallStrLit, p) - addSon(result, a) - addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p)) - getTok(p) - of tkGTripleStrLit: - result = newNodeP(nkCallStrLit, p) - addSon(result, a) - addSon(result, newStrNodeP(nkTripleStrLit, p.tok.literal, p)) - getTok(p) - else: - result = a - -type - TPrimaryMode = enum pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix - -proc complexOrSimpleStmt(p: var TParser): PNode -proc simpleExpr(p: var TParser, mode = pmNormal): PNode - -proc semiStmtList(p: var TParser, result: PNode) = - inc p.inSemiStmtList - result.add(complexOrSimpleStmt(p)) - while p.tok.tokType == tkSemiColon: - getTok(p) - optInd(p, result) - result.add(complexOrSimpleStmt(p)) - dec p.inSemiStmtList - result.kind = nkStmtListExpr - -proc parsePar(p: var TParser): PNode = - #| parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try' - #| | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let' - #| | 'when' | 'var' | 'mixin' - #| par = '(' optInd - #| ( &parKeyw complexOrSimpleStmt ^+ ';' - #| | ';' complexOrSimpleStmt ^+ ';' - #| | pragmaStmt - #| | simpleExpr ( ('=' expr (';' complexOrSimpleStmt ^+ ';' )? ) - #| | (':' expr (',' exprColonEqExpr ^+ ',' )? ) ) ) - #| optPar ')' - # - # unfortunately it's ambiguous: (expr: expr) vs (exprStmt); however a - # leading ';' could be used to enforce a 'stmt' context ... - result = newNodeP(nkPar, p) - getTok(p) - optInd(p, result) - if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase, - tkTry, tkDefer, tkFinally, tkExcept, tkFor, tkBlock, - tkConst, tkLet, tkWhen, tkVar, - tkMixin}: - # XXX 'bind' used to be an expression, so we exclude it here; - # tests/reject/tbind2 fails otherwise. - semiStmtList(p, result) - elif p.tok.tokType == tkSemiColon: - # '(;' enforces 'stmt' context: - getTok(p) - optInd(p, result) - semiStmtList(p, result) - elif p.tok.tokType == tkCurlyDotLe: - result.add(parseStmtPragma(p)) - elif p.tok.tokType != tkParRi: - var a = simpleExpr(p) - if p.tok.tokType == tkEquals: - # special case: allow assignments - getTok(p) - optInd(p, result) - let b = parseExpr(p) - let asgn = newNodeI(nkAsgn, a.info, 2) - asgn.sons[0] = a - asgn.sons[1] = b - result.add(asgn) - if p.tok.tokType == tkSemiColon: - semiStmtList(p, result) - elif p.tok.tokType == tkSemiColon: - # stmt context: - result.add(a) - semiStmtList(p, result) - else: - a = colonOrEquals(p, a) - result.add(a) - if p.tok.tokType == tkComma: - getTok(p) - skipComment(p, a) - while p.tok.tokType != tkParRi and p.tok.tokType != tkEof: - var a = exprColonEqExpr(p) - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - skipComment(p, a) - optPar(p) - eat(p, tkParRi) - -proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode = - #| literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT - #| | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT - #| | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT - #| | STR_LIT | RSTR_LIT | TRIPLESTR_LIT - #| | CHAR_LIT - #| | NIL - #| generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT - #| identOrLiteral = generalizedLit | symbol | literal - #| | par | arrayConstr | setOrTableConstr - #| | castExpr - #| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')' - #| arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']' - case p.tok.tokType - of tkSymbol, tkType, tkAddr: - result = newIdentNodeP(p.tok.ident, p) - getTok(p) - result = parseGStrLit(p, result) - of tkAccent: - result = parseSymbol(p) # literals - of tkIntLit: - result = newIntNodeP(nkIntLit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkInt8Lit: - result = newIntNodeP(nkInt8Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkInt16Lit: - result = newIntNodeP(nkInt16Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkInt32Lit: - result = newIntNodeP(nkInt32Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkInt64Lit: - result = newIntNodeP(nkInt64Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkUIntLit: - result = newIntNodeP(nkUIntLit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkUInt8Lit: - result = newIntNodeP(nkUInt8Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkUInt16Lit: - result = newIntNodeP(nkUInt16Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkUInt32Lit: - result = newIntNodeP(nkUInt32Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkUInt64Lit: - result = newIntNodeP(nkUInt64Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkFloatLit: - result = newFloatNodeP(nkFloatLit, p.tok.fNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkFloat32Lit: - result = newFloatNodeP(nkFloat32Lit, p.tok.fNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkFloat64Lit: - result = newFloatNodeP(nkFloat64Lit, p.tok.fNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkFloat128Lit: - result = newFloatNodeP(nkFloat128Lit, p.tok.fNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkStrLit: - result = newStrNodeP(nkStrLit, p.tok.literal, p) - getTok(p) - of tkRStrLit: - result = newStrNodeP(nkRStrLit, p.tok.literal, p) - getTok(p) - of tkTripleStrLit: - result = newStrNodeP(nkTripleStrLit, p.tok.literal, p) - getTok(p) - of tkCharLit: - result = newIntNodeP(nkCharLit, ord(p.tok.literal[0]), p) - getTok(p) - of tkNil: - result = newNodeP(nkNilLit, p) - getTok(p) - of tkParLe: - # () constructor - if mode in {pmTypeDesc, pmTypeDef}: - result = exprColonEqExprList(p, nkPar, tkParRi) - else: - result = parsePar(p) - of tkBracketDotLe: - # {} constructor - result = setOrTableConstr(p) - of tkBracketLe: - # [] constructor - result = exprColonEqExprList(p, nkBracket, tkBracketRi) - of tkCast: - result = parseCast(p) - else: - parMessage(p, errExprExpected, p.tok) - getTok(p) # we must consume a token here to prevend endless loops! - result = ast.emptyNode - -proc namedParams(p: var TParser, callee: PNode, - kind: TNodeKind, endTok: TTokType): PNode = - let a = callee - result = newNodeP(kind, p) - addSon(result, a) - exprColonEqExprListAux(p, endTok, result) - -proc parseMacroColon(p: var TParser, x: PNode): PNode -proc primarySuffix(p: var TParser, r: PNode): PNode = - #| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks? - #| | doBlocks - #| | '.' optInd symbol generalizedLit? - #| | '[' optInd indexExprList optPar ']' - #| | '{' optInd indexExprList optPar '}' - #| | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax - result = r - - template somePar() = discard - while p.tok.indent < 0: - case p.tok.tokType - of tkParLe: - somePar() - result = namedParams(p, result, nkCall, tkParRi) - if result.len > 1 and result.sons[1].kind == nkExprColonExpr: - result.kind = nkObjConstr - else: - parseDoBlocks(p, result) - of tkDo: - var a = result - result = newNodeP(nkCall, p) - addSon(result, a) - parseDoBlocks(p, result) - of tkDot: - result = dotExpr(p, result) - result = parseGStrLit(p, result) - of tkBracketLe: - somePar() - result = namedParams(p, result, nkBracketExpr, tkBracketRi) - of tkBracketDotLe: - somePar() - result = namedParams(p, result, nkCurlyExpr, tkBracketDotRi) - of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType: - if p.inPragma == 0: - # actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet - # solution, but pragmas.nim can't handle that - let a = result - result = newNodeP(nkCommand, p) - addSon(result, a) - when true: - addSon result, parseExpr(p) - else: - while p.tok.tokType != tkEof: - let x = parseExpr(p) - addSon(result, x) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, x) - if p.tok.tokType == tkDo: - parseDoBlocks(p, result) - else: - result = parseMacroColon(p, result) - break - else: - break - -proc primary(p: var TParser, mode: TPrimaryMode): PNode -proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode - -proc parseOperators(p: var TParser, headNode: PNode, - limit: int, mode: TPrimaryMode): PNode = - result = headNode - # expand while operators have priorities higher than 'limit' - var opPrec = getPrecedence(p.tok) - let modeB = if mode == pmTypeDef: pmTypeDesc else: mode - # the operator itself must not start on a new line: - while opPrec >= limit and p.tok.indent < 0 and not isAt(p.tok): - checkBinary(p) - var leftAssoc = 1-ord(isRightAssociative(p.tok)) - var a = newNodeP(nkInfix, p) - var opNode = newIdentNodeP(p.tok.ident, p) # skip operator: - getTok(p) - optInd(p, a) - # read sub-expression with higher priority: - var b = simpleExprAux(p, opPrec + leftAssoc, modeB) - addSon(a, opNode) - addSon(a, result) - addSon(a, b) - result = a - opPrec = getPrecedence(p.tok) - -proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode = - result = primary(p, mode) - result = parseOperators(p, result, limit, mode) - -proc simpleExpr(p: var TParser, mode = pmNormal): PNode = - result = simpleExprAux(p, -1, mode) - -proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode = - #| condExpr = expr colcom expr optInd - #| ('elif' expr colcom expr optInd)* - #| 'else' colcom expr - #| ifExpr = 'if' condExpr - #| whenExpr = 'when' condExpr - result = newNodeP(kind, p) - while true: - getTok(p) # skip `if`, `elif` - var branch = newNodeP(nkElifExpr, p) - addSon(branch, parseExpr(p)) - colcom(p, branch) - addSon(branch, parseExpr(p)) - optInd(p, branch) - addSon(result, branch) - if p.tok.tokType != tkElif: break - var branch = newNodeP(nkElseExpr, p) - eat(p, tkElse) - colcom(p, branch) - addSon(branch, parseExpr(p)) - addSon(result, branch) - -proc parsePragma(p: var TParser): PNode = - result = newNodeP(nkPragma, p) - inc p.inPragma - if isAt(p.tok): - while isAt(p.tok): - getTok(p) - var a = parseExpr(p) - optInd(p, a) - if a.kind in nkCallKinds and a.len == 2: - let repaired = newNodeI(nkExprColonExpr, a.info) - repaired.add a[0] - repaired.add a[1] - a = repaired - addSon(result, a) - skipComment(p, a) - else: - getTok(p) - optInd(p, result) - while p.tok.tokType notin {tkCurlyDotRi, tkCurlyRi, tkEof}: - var a = exprColonEqExpr(p) - addSon(result, a) - if p.tok.tokType == tkComma: - getTok(p) - skipComment(p, a) - optPar(p) - if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p) - else: parMessage(p, errTokenExpected, ".}") - dec p.inPragma - -proc identVis(p: var TParser; allowDot=false): PNode = - #| identVis = symbol opr? # postfix position - #| identVisDot = symbol '.' optInd symbol opr? - var a = parseSymbol(p) - if p.tok.tokType == tkOpr: - result = newNodeP(nkPostfix, p) - addSon(result, newIdentNodeP(p.tok.ident, p)) - addSon(result, a) - getTok(p) - elif p.tok.tokType == tkDot and allowDot: - result = dotExpr(p, a) - else: - result = a - -proc identWithPragma(p: var TParser; allowDot=false): PNode = - #| identWithPragma = identVis pragma? - #| identWithPragmaDot = identVisDot pragma? - var a = identVis(p, allowDot) - if p.tok.tokType == tkCurlyDotLe or isAt(p.tok): - result = newNodeP(nkPragmaExpr, p) - addSon(result, a) - addSon(result, parsePragma(p)) - else: - result = a - -type - TDeclaredIdentFlag = enum - withPragma, # identifier may have pragma - withBothOptional # both ':' and '=' parts are optional - TDeclaredIdentFlags = set[TDeclaredIdentFlag] - -proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode = - #| declColonEquals = identWithPragma (comma identWithPragma)* comma? - #| (':' optInd typeDesc)? ('=' optInd expr)? - #| identColonEquals = ident (comma ident)* comma? - #| (':' optInd typeDesc)? ('=' optInd expr)?) - var a: PNode - result = newNodeP(nkIdentDefs, p) - while true: - case p.tok.tokType - of tkSymbol, tkAccent: - if withPragma in flags: a = identWithPragma(p) - else: a = parseSymbol(p) - if a.kind == nkEmpty: return - else: break - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, a) - if p.tok.tokType == tkColon: - getTok(p) - optInd(p, result) - addSon(result, parseTypeDesc(p)) - else: - addSon(result, ast.emptyNode) - if p.tok.tokType != tkEquals and withBothOptional notin flags: - parMessage(p, errColonOrEqualsExpected, p.tok) - if p.tok.tokType == tkEquals: - getTok(p) - optInd(p, result) - addSon(result, parseExpr(p)) - else: - addSon(result, ast.emptyNode) - -proc parseTuple(p: var TParser): PNode = - result = newNodeP(nkTupleTy, p) - getTok(p) - if p.tok.tokType in {tkBracketLe, tkCurlyLe}: - let usedCurly = p.tok.tokType == tkCurlyLe - getTok(p) - optInd(p, result) - while p.tok.tokType in {tkSymbol, tkAccent}: - var a = parseIdentColonEquals(p, {}) - addSon(result, a) - if p.tok.tokType notin {tkComma, tkSemiColon}: break - getTok(p) - skipComment(p, a) - optPar(p) - if usedCurly: eat(p, tkCurlyRi) - else: eat(p, tkBracketRi) - else: - result = newNodeP(nkTupleClassTy, p) - -proc parseParamList(p: var TParser, retColon = true): PNode = - #| paramList = '(' declColonEquals ^* (comma/semicolon) ')' - #| paramListArrow = paramList? ('->' optInd typeDesc)? - #| paramListColon = paramList? (':' optInd typeDesc)? - var a: PNode - result = newNodeP(nkFormalParams, p) - addSon(result, ast.emptyNode) # return type - let hasParLe = p.tok.tokType == tkParLe and p.tok.indent < 0 - if hasParLe: - getTok(p) - optInd(p, result) - while true: - case p.tok.tokType - of tkSymbol, tkAccent: - a = parseIdentColonEquals(p, {withBothOptional, withPragma}) - of tkParRi: - break - else: - parMessage(p, errTokenExpected, ")") - break - addSon(result, a) - if p.tok.tokType notin {tkComma, tkSemiColon}: break - getTok(p) - skipComment(p, a) - optPar(p) - eat(p, tkParRi) - let hasRet = if retColon: p.tok.tokType == tkColon - else: p.tok.tokType == tkOpr and p.tok.ident.s == "->" - if hasRet and p.tok.indent < 0: - getTok(p) - optInd(p, result) - result.sons[0] = parseTypeDesc(p) - elif not retColon and not hasParle: - # Mark as "not there" in order to mark for deprecation in the semantic pass: - result = ast.emptyNode - -proc optPragmas(p: var TParser): PNode = - if p.tok.tokType == tkCurlyDotLe or isAt(p.tok): - result = parsePragma(p) - else: - result = ast.emptyNode - -proc parseDoBlock(p: var TParser): PNode = - #| doBlock = 'do' paramListArrow pragmas? colcom stmt - let info = parLineInfo(p) - getTok(p) - let params = parseParamList(p, retColon=false) - let pragmas = optPragmas(p) - colcom(p, result) - result = newProcNode(nkDo, info, parseStmt(p), - params = params, - pragmas = pragmas) - -proc parseDoBlocks(p: var TParser, call: PNode) = - #| doBlocks = doBlock ^* IND{=} - while p.tok.tokType == tkDo: - addSon(call, parseDoBlock(p)) - -proc parseCurlyStmt(p: var TParser): PNode = - result = newNodeP(nkStmtList, p) - eat(p, tkCurlyLe) - result.add parseStmt(p) - while p.tok.tokType notin {tkEof, tkCurlyRi}: - if p.tok.tokType == tkSemicolon: getTok(p) - elif p.tok.indent < 0: break - result.add parseStmt(p) - eat(p, tkCurlyRi) - -proc parseProcExpr(p: var TParser, isExpr: bool): PNode = - #| procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)? - # either a proc type or a anonymous proc - let info = parLineInfo(p) - getTok(p) - let hasSignature = p.tok.tokType in {tkParLe, tkColon} and p.tok.indent < 0 - let params = parseParamList(p) - let pragmas = optPragmas(p) - if p.tok.tokType == tkCurlyLe and isExpr: - result = newProcNode(nkLambda, info, parseCurlyStmt(p), - params = params, - pragmas = pragmas) - else: - result = newNodeI(nkProcTy, info) - if hasSignature: - addSon(result, params) - addSon(result, pragmas) - -proc isExprStart(p: TParser): bool = - case p.tok.tokType - of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, - tkProc, tkIterator, tkBind, tkAddr, - tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr, - tkTuple, tkObject, tkType, tkWhen, tkCase, tkOut: - result = true - else: result = false - -proc parseSymbolList(p: var TParser, result: PNode, allowNil = false) = - while true: - var s = parseSymbol(p, allowNil) - if s.kind == nkEmpty: break - addSon(result, s) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, s) - -proc parseTypeDescKAux(p: var TParser, kind: TNodeKind, - mode: TPrimaryMode): PNode = - #| distinct = 'distinct' optInd typeDesc - result = newNodeP(kind, p) - getTok(p) - optInd(p, result) - if not isOperator(p.tok) and isExprStart(p): - addSon(result, primary(p, mode)) - if kind == nkDistinctTy and p.tok.tokType == tkSymbol: - var nodeKind: TNodeKind - if p.tok.ident.s == "with": - nodeKind = nkWith - elif p.tok.ident.s == "without": - nodeKind = nkWithout - else: - return result - getTok(p) - let list = newNodeP(nodeKind, p) - result.addSon list - parseSymbolList(p, list, allowNil = true) - -proc parseExpr(p: var TParser): PNode = - #| expr = (ifExpr - #| | whenExpr - #| | caseExpr - #| | tryExpr) - #| / simpleExpr - case p.tok.tokType: - of tkIf: result = parseIfExpr(p, nkIfExpr) - of tkWhen: result = parseIfExpr(p, nkWhenExpr) - of tkCase: result = parseCase(p) - of tkTry: result = parseTry(p) - else: result = simpleExpr(p) - -proc parseEnum(p: var TParser): PNode -proc parseObject(p: var TParser): PNode -proc parseTypeClass(p: var TParser): PNode - -proc primary(p: var TParser, mode: TPrimaryMode): PNode = - #| typeKeyw = 'var' | 'out' | 'ref' | 'ptr' | 'shared' | 'tuple' - #| | 'proc' | 'iterator' | 'distinct' | 'object' | 'enum' - #| primary = typeKeyw typeDescK - #| / prefixOperator* identOrLiteral primarySuffix* - #| / 'static' primary - #| / 'bind' primary - if isOperator(p.tok): - let isSigil = isSigilLike(p.tok) - result = newNodeP(nkPrefix, p) - var a = newIdentNodeP(p.tok.ident, p) - addSon(result, a) - getTok(p) - optInd(p, a) - if isSigil: - #XXX prefix operators - addSon(result, primary(p, pmSkipSuffix)) - result = primarySuffix(p, result) - else: - addSon(result, primary(p, pmNormal)) - return - - case p.tok.tokType: - of tkTuple: result = parseTuple(p) - of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}) - of tkIterator: - result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}) - if result.kind == nkLambda: result.kind = nkIteratorDef - else: result.kind = nkIteratorTy - of tkEnum: - if mode == pmTypeDef: - result = parseEnum(p) - else: - result = newNodeP(nkEnumTy, p) - getTok(p) - of tkObject: - if mode == pmTypeDef: - result = parseObject(p) - else: - result = newNodeP(nkObjectTy, p) - getTok(p) - of tkConcept: - if mode == pmTypeDef: - result = parseTypeClass(p) - else: - parMessage(p, errInvalidToken, p.tok) - of tkStatic: - let info = parLineInfo(p) - getTokNoInd(p) - let next = primary(p, pmNormal) - if next.kind == nkBracket and next.sonsLen == 1: - result = newNode(nkStaticTy, info, @[next.sons[0]]) - else: - result = newNode(nkStaticExpr, info, @[next]) - of tkBind: - result = newNodeP(nkBind, p) - getTok(p) - optInd(p, result) - addSon(result, primary(p, pmNormal)) - of tkVar: result = parseTypeDescKAux(p, nkVarTy, mode) - of tkOut: result = parseTypeDescKAux(p, nkVarTy, mode) - of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode) - of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode) - of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, mode) - else: - result = identOrLiteral(p, mode) - if mode != pmSkipSuffix: - result = primarySuffix(p, result) - -proc parseTypeDesc(p: var TParser): PNode = - #| typeDesc = simpleExpr - result = simpleExpr(p, pmTypeDesc) - -proc parseTypeDefAux(p: var TParser): PNode = - #| typeDefAux = simpleExpr - #| | 'concept' typeClass - result = simpleExpr(p, pmTypeDef) - -proc makeCall(n: PNode): PNode = - ## Creates a call if the given node isn't already a call. - if n.kind in nkCallKinds: - result = n - else: - result = newNodeI(nkCall, n.info) - result.add n - -proc parseMacroColon(p: var TParser, x: PNode): PNode = - #| macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt - #| | IND{=} 'elif' expr ':' stmt - #| | IND{=} 'except' exprList ':' stmt - #| | IND{=} 'else' ':' stmt )* - result = x - if p.tok.tokType == tkColon and p.tok.indent < 0: - result = makeCall(result) - getTok(p) - skipComment(p, result) - let stmtList = newNodeP(nkStmtList, p) - if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}: - let body = parseStmt(p) - stmtList.add body - #addSon(result, makeStmtList(body)) - while true: - var b: PNode - case p.tok.tokType - of tkOf: - b = newNodeP(nkOfBranch, p) - exprList(p, tkCurlyLe, b) - of tkElif: - b = newNodeP(nkElifBranch, p) - getTok(p) - optInd(p, b) - addSon(b, parseExpr(p)) - of tkExcept: - b = newNodeP(nkExceptBranch, p) - exprList(p, tkCurlyLe, b) - of tkElse: - b = newNodeP(nkElse, p) - getTok(p) - else: break - addSon(b, parseCurlyStmt(p)) - addSon(stmtList, b) - if b.kind == nkElse: break - if stmtList.len == 1 and stmtList[0].kind == nkStmtList: - # to keep backwards compatibility (see tests/vm/tstringnil) - result.add stmtList[0] - else: - result.add stmtList - -proc parseExprStmt(p: var TParser): PNode = - #| exprStmt = simpleExpr - #| (( '=' optInd expr ) - #| / ( expr ^+ comma - #| doBlocks - #| / macroColon - #| ))? - var a = simpleExpr(p) - if p.tok.tokType == tkEquals: - getTok(p) - optInd(p, result) - var b = parseExpr(p) - result = newNodeI(nkAsgn, a.info) - addSon(result, a) - addSon(result, b) - else: - # simpleExpr parsed 'p a' from 'p a, b'? - if p.tok.indent < 0 and p.tok.tokType == tkComma and a.kind == nkCommand: - result = a - while true: - getTok(p) - optInd(p, result) - var e = parseExpr(p) - addSon(result, e) - if p.tok.tokType != tkComma: break - elif p.tok.indent < 0 and isExprStart(p): - if a.kind == nkCommand: - result = a - else: - result = newNode(nkCommand, a.info, @[a]) - while true: - var e = parseExpr(p) - addSon(result, e) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, result) - else: - result = a - if p.tok.tokType == tkDo and p.tok.indent < 0: - result = makeCall(result) - parseDoBlocks(p, result) - return result - result = parseMacroColon(p, result) - -proc parseModuleName(p: var TParser, kind: TNodeKind): PNode = - result = parseExpr(p) - -proc parseImport(p: var TParser, kind: TNodeKind): PNode = - #| importStmt = 'import' optInd expr - #| ((comma expr)* - #| / 'except' optInd (expr ^+ comma)) - result = newNodeP(kind, p) - getTok(p) # skip `import` or `export` - optInd(p, result) - var a = parseModuleName(p, kind) - addSon(result, a) - if p.tok.tokType in {tkComma, tkExcept}: - if p.tok.tokType == tkExcept: - result.kind = succ(kind) - getTok(p) - optInd(p, result) - while true: - # was: while p.tok.tokType notin {tkEof, tkSad, tkDed}: - a = parseModuleName(p, kind) - if a.kind == nkEmpty: break - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, a) - #expectNl(p) - -proc parseIncludeStmt(p: var TParser): PNode = - #| includeStmt = 'include' optInd expr ^+ comma - result = newNodeP(nkIncludeStmt, p) - getTok(p) # skip `import` or `include` - optInd(p, result) - while true: - # was: while p.tok.tokType notin {tkEof, tkSad, tkDed}: - var a = parseExpr(p) - if a.kind == nkEmpty: break - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, a) - #expectNl(p) - -proc parseFromStmt(p: var TParser): PNode = - #| fromStmt = 'from' moduleName 'import' optInd expr (comma expr)* - result = newNodeP(nkFromStmt, p) - getTok(p) # skip `from` - optInd(p, result) - var a = parseModuleName(p, nkImportStmt) - addSon(result, a) #optInd(p, a); - eat(p, tkImport) - optInd(p, result) - while true: - # p.tok.tokType notin {tkEof, tkSad, tkDed}: - a = parseExpr(p) - if a.kind == nkEmpty: break - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, a) - #expectNl(p) - -proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode = - #| returnStmt = 'return' optInd expr? - #| raiseStmt = 'raise' optInd expr? - #| yieldStmt = 'yield' optInd expr? - #| discardStmt = 'discard' optInd expr? - #| breakStmt = 'break' optInd expr? - #| continueStmt = 'break' optInd expr? - result = newNodeP(kind, p) - getTok(p) - if p.tok.tokType == tkComment: - skipComment(p, result) - addSon(result, ast.emptyNode) - elif p.tok.indent >= 0 or not isExprStart(p): - # NL terminates: - addSon(result, ast.emptyNode) - else: - addSon(result, parseExpr(p)) - -proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode = - #| condStmt = expr colcom stmt COMMENT? - #| (IND{=} 'elif' expr colcom stmt)* - #| (IND{=} 'else' colcom stmt)? - #| ifStmt = 'if' condStmt - #| whenStmt = 'when' condStmt - result = newNodeP(kind, p) - while true: - getTok(p) # skip `if`, `when`, `elif` - var branch = newNodeP(nkElifBranch, p) - optInd(p, branch) - addSon(branch, parseExpr(p)) - colcom(p, branch) - addSon(branch, parseCurlyStmt(p)) - skipComment(p, branch) - addSon(result, branch) - if p.tok.tokType != tkElif: break - if p.tok.tokType == tkElse: - var branch = newNodeP(nkElse, p) - eat(p, tkElse) - addSon(branch, parseCurlyStmt(p)) - addSon(result, branch) - -proc parseWhile(p: var TParser): PNode = - #| whileStmt = 'while' expr colcom stmt - result = newNodeP(nkWhileStmt, p) - getTok(p) - optInd(p, result) - addSon(result, parseExpr(p)) - colcom(p, result) - addSon(result, parseCurlyStmt(p)) - -proc parseCase(p: var TParser): PNode = - #| ofBranch = 'of' exprList colcom stmt - #| ofBranches = ofBranch (IND{=} ofBranch)* - #| (IND{=} 'elif' expr colcom stmt)* - #| (IND{=} 'else' colcom stmt)? - #| caseStmt = 'case' expr ':'? COMMENT? - #| (IND{>} ofBranches DED - #| | IND{=} ofBranches) - var - b: PNode - inElif= false - result = newNodeP(nkCaseStmt, p) - getTok(p) - addSon(result, parseExpr(p)) - eat(p, tkCurlyLe) - skipComment(p, result) - - while true: - case p.tok.tokType - of tkOf: - if inElif: break - b = newNodeP(nkOfBranch, p) - exprList(p, tkCurlyLe, b) - of tkElif: - inElif = true - b = newNodeP(nkElifBranch, p) - getTok(p) - optInd(p, b) - addSon(b, parseExpr(p)) - of tkElse: - b = newNodeP(nkElse, p) - getTok(p) - else: break - skipComment(p, b) - addSon(b, parseCurlyStmt(p)) - addSon(result, b) - if b.kind == nkElse: break - eat(p, tkCurlyRi) - -proc parseTry(p: var TParser): PNode = - #| tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally') - #| (IND{=}? 'except' exprList colcom stmt)* - #| (IND{=}? 'finally' colcom stmt)? - #| tryExpr = 'try' colcom stmt &(optInd 'except'|'finally') - #| (optInd 'except' exprList colcom stmt)* - #| (optInd 'finally' colcom stmt)? - result = newNodeP(nkTryStmt, p) - getTok(p) - colcom(p, result) - addSon(result, parseCurlyStmt(p)) - var b: PNode = nil - while true: - case p.tok.tokType - of tkExcept: - b = newNodeP(nkExceptBranch, p) - exprList(p, tkCurlyLe, b) - of tkFinally: - b = newNodeP(nkFinally, p) - getTok(p) - else: break - skipComment(p, b) - addSon(b, parseCurlyStmt(p)) - addSon(result, b) - if b.kind == nkFinally: break - if b == nil: parMessage(p, errTokenExpected, "except") - -proc parseFor(p: var TParser): PNode = - #| forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt - result = newNodeP(nkForStmt, p) - getTokNoInd(p) - var a = identWithPragma(p) - addSon(result, a) - while p.tok.tokType == tkComma: - getTok(p) - optInd(p, a) - a = identWithPragma(p) - addSon(result, a) - eat(p, tkIn) - addSon(result, parseExpr(p)) - colcom(p, result) - addSon(result, parseCurlyStmt(p)) - -proc parseBlock(p: var TParser): PNode = - #| blockStmt = 'block' symbol? colcom stmt - result = newNodeP(nkBlockStmt, p) - getTokNoInd(p) - if p.tok.tokType == tkCurlyLe: addSon(result, ast.emptyNode) - else: addSon(result, parseSymbol(p)) - colcom(p, result) - addSon(result, parseCurlyStmt(p)) - -proc parseStaticOrDefer(p: var TParser; k: TNodeKind): PNode = - #| staticStmt = 'static' colcom stmt - #| deferStmt = 'defer' colcom stmt - result = newNodeP(k, p) - getTok(p) - colcom(p, result) - addSon(result, parseCurlyStmt(p)) - -proc parseAsm(p: var TParser): PNode = - #| asmStmt = 'asm' pragma? (STR_LIT | RSTR_LIT | TRIPLE_STR_LIT) - result = newNodeP(nkAsmStmt, p) - getTokNoInd(p) - if p.tok.tokType == tkCurlyDotLe or isAt(p.tok): addSon(result, parsePragma(p)) - else: addSon(result, ast.emptyNode) - case p.tok.tokType - of tkStrLit: addSon(result, newStrNodeP(nkStrLit, p.tok.literal, p)) - of tkRStrLit: addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p)) - of tkTripleStrLit: addSon(result, - newStrNodeP(nkTripleStrLit, p.tok.literal, p)) - else: - parMessage(p, errStringLiteralExpected) - addSon(result, ast.emptyNode) - return - getTok(p) - -proc parseGenericParam(p: var TParser): PNode = - #| genericParam = symbol (comma symbol)* (colon expr)? ('=' optInd expr)? - var a: PNode - result = newNodeP(nkIdentDefs, p) - while true: - case p.tok.tokType - of tkIn, tkOut: - let t = p.tok.tokType - getTok(p) - expectIdent(p) - a = parseSymbol(p) - of tkSymbol, tkAccent: - a = parseSymbol(p) - if a.kind == nkEmpty: return - else: break - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, a) - if p.tok.tokType == tkColon: - getTok(p) - optInd(p, result) - addSon(result, parseExpr(p)) - else: - addSon(result, ast.emptyNode) - if p.tok.tokType == tkEquals: - getTok(p) - optInd(p, result) - addSon(result, parseExpr(p)) - else: - addSon(result, ast.emptyNode) - -proc parseGenericParamList(p: var TParser): PNode = - #| genericParamList = '[' optInd - #| genericParam ^* (comma/semicolon) optPar ']' - result = newNodeP(nkGenericParams, p) - getTok(p) - optInd(p, result) - while p.tok.tokType in {tkSymbol, tkAccent}: - var a = parseGenericParam(p) - addSon(result, a) - if p.tok.tokType notin {tkComma, tkSemiColon}: break - getTok(p) - skipComment(p, a) - optPar(p) - eat(p, tkBracketRi) - -proc parsePattern(p: var TParser): PNode = - eat(p, tkBracketDotLe) - result = parseStmt(p) - eat(p, tkBracketDotRi) - -proc validInd(p: TParser): bool = p.tok.indent < 0 - -proc parseRoutine(p: var TParser, kind: TNodeKind): PNode = - #| indAndComment = (IND{>} COMMENT)? | COMMENT? - #| routine = optInd identVis pattern? genericParamList? - #| paramListColon pragma? ('=' COMMENT? stmt)? indAndComment - result = newNodeP(kind, p) - getTok(p) - optInd(p, result) - addSon(result, identVis(p)) - if p.tok.tokType == tkBracketDotLe and p.validInd: - addSon(result, p.parsePattern) - else: - addSon(result, ast.emptyNode) - if p.tok.tokType == tkBracketLe and p.validInd: - result.add(p.parseGenericParamList) - else: - addSon(result, ast.emptyNode) - addSon(result, p.parseParamList) - if (p.tok.tokType == tkCurlyDotLe or isAt(p.tok)) and p.validInd: - addSon(result, p.parsePragma) - else: - addSon(result, ast.emptyNode) - # empty exception tracking: - addSon(result, ast.emptyNode) - if p.tok.tokType == tkCurlyLe: - addSon(result, parseCurlyStmt(p)) - else: - addSon(result, ast.emptyNode) - indAndComment(p, result) - -proc newCommentStmt(p: var TParser): PNode = - #| commentStmt = COMMENT - result = newNodeP(nkCommentStmt, p) - result.comment = p.tok.literal - getTok(p) - -type - TDefParser = proc (p: var TParser): PNode {.nimcall.} - -proc parseSection(p: var TParser, kind: TNodeKind, - defparser: TDefParser): PNode = - #| section(p) = COMMENT? p / (IND{>} (p / COMMENT)^+IND{=} DED) - result = newNodeP(kind, p) - if kind != nkTypeSection: getTok(p) - skipComment(p, result) - if p.tok.tokType == tkParLe: - getTok(p) - skipComment(p, result) - while true: - case p.tok.tokType - of tkSymbol, tkAccent, tkParLe: - var a = defparser(p) - skipComment(p, a) - addSon(result, a) - of tkComment: - var a = newCommentStmt(p) - addSon(result, a) - of tkParRi: break - else: - parMessage(p, errIdentifierExpected, p.tok) - break - eat(p, tkParRi) - if result.len == 0: parMessage(p, errIdentifierExpected, p.tok) - elif p.tok.tokType in {tkSymbol, tkAccent, tkBracketLe}: - # tkBracketLe is allowed for ``var [x, y] = ...`` tuple parsing - addSon(result, defparser(p)) - else: - parMessage(p, errIdentifierExpected, p.tok) - -proc parseConstant(p: var TParser): PNode = - #| constant = identWithPragma (colon typedesc)? '=' optInd expr indAndComment - result = newNodeP(nkConstDef, p) - addSon(result, identWithPragma(p)) - if p.tok.tokType == tkColon: - getTok(p) - optInd(p, result) - addSon(result, parseTypeDesc(p)) - else: - addSon(result, ast.emptyNode) - eat(p, tkEquals) - optInd(p, result) - addSon(result, parseExpr(p)) - indAndComment(p, result) - -proc parseEnum(p: var TParser): PNode = - #| enum = 'enum' optInd (symbol optInd ('=' optInd expr COMMENT?)? comma?)+ - result = newNodeP(nkEnumTy, p) - getTok(p) - addSon(result, ast.emptyNode) - optInd(p, result) - flexComment(p, result) - eat(p, tkCurlyLe) - optInd(p, result) - while p.tok.tokType notin {tkEof, tkCurlyRi}: - var a = parseSymbol(p) - if a.kind == nkEmpty: return - if p.tok.tokType == tkEquals: - getTok(p) - optInd(p, a) - var b = a - a = newNodeP(nkEnumFieldDef, p) - addSon(a, b) - addSon(a, parseExpr(p)) - if p.tok.indent < 0: - rawSkipComment(p, a) - if p.tok.tokType == tkComma: - getTok(p) - rawSkipComment(p, a) - addSon(result, a) - eat(p, tkCurlyRi) - if result.len <= 1: - lexMessageTok(p.lex, errIdentifierExpected, p.tok, prettyTok(p.tok)) - -proc parseObjectPart(p: var TParser; needsCurly: bool): PNode -proc parseObjectWhen(p: var TParser): PNode = - result = newNodeP(nkRecWhen, p) - while true: - getTok(p) # skip `when`, `elif` - var branch = newNodeP(nkElifBranch, p) - optInd(p, branch) - addSon(branch, parseExpr(p)) - colcom(p, branch) - addSon(branch, parseObjectPart(p, true)) - flexComment(p, branch) - addSon(result, branch) - if p.tok.tokType != tkElif: break - if p.tok.tokType == tkElse: - var branch = newNodeP(nkElse, p) - eat(p, tkElse) - colcom(p, branch) - addSon(branch, parseObjectPart(p, true)) - flexComment(p, branch) - addSon(result, branch) - -proc parseObjectCase(p: var TParser): PNode = - result = newNodeP(nkRecCase, p) - getTokNoInd(p) - var a = newNodeP(nkIdentDefs, p) - addSon(a, identWithPragma(p)) - eat(p, tkColon) - addSon(a, parseTypeDesc(p)) - addSon(a, ast.emptyNode) - addSon(result, a) - eat(p, tkCurlyLe) - flexComment(p, result) - while true: - var b: PNode - case p.tok.tokType - of tkOf: - b = newNodeP(nkOfBranch, p) - exprList(p, tkColon, b) - of tkElse: - b = newNodeP(nkElse, p) - getTok(p) - else: break - colcom(p, b) - var fields = parseObjectPart(p, true) - if fields.kind == nkEmpty: - parMessage(p, errIdentifierExpected, p.tok) - fields = newNodeP(nkNilLit, p) # don't break further semantic checking - addSon(b, fields) - addSon(result, b) - if b.kind == nkElse: break - eat(p, tkCurlyRi) - -proc parseObjectPart(p: var TParser; needsCurly: bool): PNode = - if p.tok.tokType == tkCurlyLe: - result = newNodeP(nkRecList, p) - getTok(p) - rawSkipComment(p, result) - while true: - case p.tok.tokType - of tkCase, tkWhen, tkSymbol, tkAccent, tkNil, tkDiscard: - addSon(result, parseObjectPart(p, false)) - of tkCurlyRi: break - else: - parMessage(p, errIdentifierExpected, p.tok) - break - eat(p, tkCurlyRi) - else: - if needsCurly: - parMessage(p, errTokenExpected, "{") - case p.tok.tokType - of tkWhen: - result = parseObjectWhen(p) - of tkCase: - result = parseObjectCase(p) - of tkSymbol, tkAccent: - result = parseIdentColonEquals(p, {withPragma}) - if p.tok.indent < 0: rawSkipComment(p, result) - of tkNil, tkDiscard: - result = newNodeP(nkNilLit, p) - getTok(p) - else: - result = ast.emptyNode - -proc parseObject(p: var TParser): PNode = - result = newNodeP(nkObjectTy, p) - getTok(p) - if (p.tok.tokType == tkCurlyDotLe or isAt(p.tok)) and p.validInd: - addSon(result, parsePragma(p)) - else: - addSon(result, ast.emptyNode) - if p.tok.tokType == tkOf and p.tok.indent < 0: - var a = newNodeP(nkOfInherit, p) - getTok(p) - addSon(a, parseTypeDesc(p)) - addSon(result, a) - else: - addSon(result, ast.emptyNode) - skipComment(p, result) - # an initial IND{>} HAS to follow: - addSon(result, parseObjectPart(p, true)) - -proc parseTypeClassParam(p: var TParser): PNode = - if p.tok.tokType in {tkOut, tkVar}: - result = newNodeP(nkVarTy, p) - getTok(p) - result.addSon(p.parseSymbol) - else: - result = p.parseSymbol - -proc parseTypeClass(p: var TParser): PNode = - #| typeClassParam = ('var' | 'out')? symbol - #| typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')? - #| &IND{>} stmt - result = newNodeP(nkTypeClassTy, p) - getTok(p) - var args = newNodeP(nkArgList, p) - addSon(result, args) - addSon(args, p.parseTypeClassParam) - while p.tok.tokType == tkComma: - getTok(p) - addSon(args, p.parseTypeClassParam) - if (p.tok.tokType == tkCurlyDotLe or isAt(p.tok)) and p.validInd: - addSon(result, parsePragma(p)) - else: - addSon(result, ast.emptyNode) - if p.tok.tokType == tkOf and p.tok.indent < 0: - var a = newNodeP(nkOfInherit, p) - getTok(p) - while true: - addSon(a, parseTypeDesc(p)) - if p.tok.tokType != tkComma: break - getTok(p) - addSon(result, a) - else: - addSon(result, ast.emptyNode) - if p.tok.tokType == tkComment: - skipComment(p, result) - addSon(result, parseCurlyStmt(p)) - -proc parseTypeDef(p: var TParser): PNode = - #| - #| typeDef = identWithPragmaDot genericParamList? '=' optInd typeDefAux - #| indAndComment? - result = newNodeP(nkTypeDef, p) - addSon(result, identWithPragma(p, allowDot=true)) - if p.tok.tokType == tkBracketLe and p.validInd: - addSon(result, parseGenericParamList(p)) - else: - addSon(result, ast.emptyNode) - if p.tok.tokType == tkEquals: - getTok(p) - optInd(p, result) - addSon(result, parseTypeDefAux(p)) - else: - addSon(result, ast.emptyNode) - indAndComment(p, result) # special extension! - -proc parseVarTuple(p: var TParser): PNode = - #| varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr - result = newNodeP(nkVarTuple, p) - getTok(p) # skip '(' - optInd(p, result) - while p.tok.tokType in {tkSymbol, tkAccent}: - var a = identWithPragma(p) - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - skipComment(p, a) - addSon(result, ast.emptyNode) # no type desc - optPar(p) - eat(p, tkBracketRi) - eat(p, tkEquals) - optInd(p, result) - addSon(result, parseExpr(p)) - -proc parseVariable(p: var TParser): PNode = - #| variable = (varTuple / identColonEquals) indAndComment - if p.tok.tokType == tkBracketLe: result = parseVarTuple(p) - else: result = parseIdentColonEquals(p, {withPragma}) - indAndComment(p, result) - -proc parseBind(p: var TParser, k: TNodeKind): PNode = - #| bindStmt = 'bind' optInd qualifiedIdent ^+ comma - #| mixinStmt = 'mixin' optInd qualifiedIdent ^+ comma - result = newNodeP(k, p) - getTok(p) - optInd(p, result) - while true: - var a = qualifiedIdent(p) - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, a) - -proc parseStmtPragma(p: var TParser): PNode = - result = parsePragma(p) - if p.tok.tokType == tkCurlyLe: - let a = result - result = newNodeI(nkPragmaBlock, a.info) - getTok(p) - skipComment(p, result) - result.add a - result.add parseStmt(p) - eat(p, tkCurlyRi) - -proc simpleStmt(p: var TParser): PNode = - case p.tok.tokType - of tkReturn: result = parseReturnOrRaise(p, nkReturnStmt) - of tkRaise: result = parseReturnOrRaise(p, nkRaiseStmt) - of tkYield: result = parseReturnOrRaise(p, nkYieldStmt) - of tkDiscard: result = parseReturnOrRaise(p, nkDiscardStmt) - of tkBreak: result = parseReturnOrRaise(p, nkBreakStmt) - of tkContinue: result = parseReturnOrRaise(p, nkContinueStmt) - of tkCurlyDotLe: result = parseStmtPragma(p) - of tkImport: result = parseImport(p, nkImportStmt) - of tkExport: result = parseImport(p, nkExportStmt) - of tkFrom: result = parseFromStmt(p) - of tkInclude: result = parseIncludeStmt(p) - of tkComment: result = newCommentStmt(p) - else: - if isExprStart(p): result = parseExprStmt(p) - else: result = ast.emptyNode - if result.kind notin {nkEmpty, nkCommentStmt}: skipComment(p, result) - -proc complexOrSimpleStmt(p: var TParser): PNode = - case p.tok.tokType - of tkIf: result = parseIfOrWhen(p, nkIfStmt) - of tkWhile: result = parseWhile(p) - of tkCase: result = parseCase(p) - of tkTry: result = parseTry(p) - of tkFor: result = parseFor(p) - of tkBlock: result = parseBlock(p) - of tkStatic: result = parseStaticOrDefer(p, nkStaticStmt) - of tkDefer: result = parseStaticOrDefer(p, nkDefer) - of tkAsm: result = parseAsm(p) - of tkProc: result = parseRoutine(p, nkProcDef) - of tkMethod: result = parseRoutine(p, nkMethodDef) - of tkIterator: result = parseRoutine(p, nkIteratorDef) - of tkMacro: result = parseRoutine(p, nkMacroDef) - of tkTemplate: result = parseRoutine(p, nkTemplateDef) - of tkConverter: result = parseRoutine(p, nkConverterDef) - of tkType: - getTok(p) - if p.tok.tokType == tkBracketLe: - getTok(p) - result = newNodeP(nkTypeOfExpr, p) - result.addSon(primary(p, pmTypeDesc)) - eat(p, tkBracketRi) - result = parseOperators(p, result, -1, pmNormal) - else: - result = parseSection(p, nkTypeSection, parseTypeDef) - of tkConst: result = parseSection(p, nkConstSection, parseConstant) - of tkLet: result = parseSection(p, nkLetSection, parseVariable) - of tkWhen: result = parseIfOrWhen(p, nkWhenStmt) - of tkVar: result = parseSection(p, nkVarSection, parseVariable) - of tkBind: result = parseBind(p, nkBindStmt) - of tkMixin: result = parseBind(p, nkMixinStmt) - of tkUsing: result = parseSection(p, nkUsingStmt, parseVariable) - else: result = simpleStmt(p) - -proc parseStmt(p: var TParser): PNode = - result = complexOrSimpleStmt(p) - -proc parseAll*(p: var TParser): PNode = - ## Parses the rest of the input stream held by the parser into a PNode. - result = newNodeP(nkStmtList, p) - while p.tok.tokType != tkEof: - var a = complexOrSimpleStmt(p) - if a.kind != nkEmpty: - addSon(result, a) - else: - parMessage(p, errExprExpected, p.tok) - # bugfix: consume a token here to prevent an endless loop: - getTok(p) - -proc parseTopLevelStmt*(p: var TParser): PNode = - ## Implements an iterator which, when called repeatedly, returns the next - ## top-level statement or emptyNode if end of stream. - result = ast.emptyNode - while true: - case p.tok.tokType - of tkSemiColon: getTok(p) - of tkEof: break - else: - result = complexOrSimpleStmt(p) - if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok) - break diff --git a/compiler/reorder.nim b/compiler/reorder.nim index 56d8d5886..2542a08ea 100644 --- a/compiler/reorder.nim +++ b/compiler/reorder.nim @@ -137,7 +137,7 @@ proc hasIncludes(n:PNode): bool = proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex; cache: IdentCache): PNode {.procvar.} = - result = syntaxes.parseFile(fileIdx, cache) + result = syntaxes.parseFile(fileIdx, cache, graph.config) graph.addDep(s, fileIdx) graph.addIncludeDep(FileIndex s.position, fileIdx) @@ -273,9 +273,9 @@ proc hasCommand(n: PNode): bool = of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse, nkStaticStmt, nkLetSection, nkConstSection, nkVarSection, nkIdentDefs: - for a in n: - if a.hasCommand: - return true + for a in n: + if a.hasCommand: + return true else: return false diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index c533f4cb4..6ef42f15e 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -28,7 +28,7 @@ proc listDirs(a: VmArgs, filter: set[PathComponent]) = proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; config: ConfigRef): PEvalContext = # For Nimble we need to export 'setupVM'. - result = newCtx(module, cache) + result = newCtx(module, cache, config) result.mode = emRepl registerAdditionalOps(result) diff --git a/compiler/sem.nim b/compiler/sem.nim index 52282d0e4..d8e5b7f20 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -313,7 +313,7 @@ proc tryConstExpr(c: PContext, n: PNode): PNode = msgs.gErrorMax = high(int) try: - result = evalConstExpr(c.module, c.cache, e) + result = evalConstExpr(c.module, c.cache, c.graph.config, e) if result == nil or result.kind == nkEmpty: result = nil else: @@ -334,7 +334,7 @@ proc semConstExpr(c: PContext, n: PNode): PNode = result = getConstExpr(c.module, e) if result == nil: #if e.kind == nkEmpty: globalError(n.info, errConstExprExpected) - result = evalConstExpr(c.module, c.cache, e) + result = evalConstExpr(c.module, c.cache, c.graph.config, e) if result == nil or result.kind == nkEmpty: if e.info != n.info: pushInfoContext(n.info) @@ -439,7 +439,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, #if c.evalContext == nil: # c.evalContext = c.createEvalContext(emStatic) - result = evalMacroCall(c.module, c.cache, n, nOrig, sym) + result = evalMacroCall(c.module, c.cache, c.graph.config, n, nOrig, sym) if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, sym, flags) result = wrapInComesFrom(nOrig.info, sym, result) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index feca087fc..4a3672aa0 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -605,12 +605,12 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = call.add(a) #echo "NOW evaluating at compile time: ", call.renderTree if sfCompileTime in callee.flags: - result = evalStaticExpr(c.module, c.cache, call, c.p.owner) + result = evalStaticExpr(c.module, c.cache, c.graph.config, call, c.p.owner) if result.isNil: localError(n.info, errCannotInterpretNodeX, renderTree(call)) else: result = fixupTypeAfterEval(c, result, n) else: - result = evalConstExpr(c.module, c.cache, call) + result = evalConstExpr(c.module, c.cache, c.graph.config, call) if result.isNil: result = n else: result = fixupTypeAfterEval(c, result, n) #if result != n: @@ -619,7 +619,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = proc semStaticExpr(c: PContext, n: PNode): PNode = let a = semExpr(c, n.sons[0]) if a.findUnresolvedStatic != nil: return a - result = evalStaticExpr(c.module, c.cache, a, c.p.owner) + result = evalStaticExpr(c.module, c.cache, c.graph.config, a, c.p.owner) if result.isNil: localError(n.info, errCannotInterpretNodeX, renderTree(n)) result = emptyNode diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f5fdc3445..b0bd4e0f6 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -545,7 +545,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = b.sons[j] = newSymNode(v) checkNilable(v) if sfCompileTime in v.flags: hasCompileTime = true - if hasCompileTime: vm.setupCompileTimeVar(c.module, c.cache, result) + if hasCompileTime: + vm.setupCompileTimeVar(c.module, c.cache, c.graph.config, result) proc semConst(c: PContext, n: PNode): PNode = result = copyNode(n) @@ -1755,7 +1756,7 @@ proc semStaticStmt(c: PContext, n: PNode): PNode = #writeStackTrace() let a = semStmt(c, n.sons[0]) n.sons[0] = a - evalStaticStmt(c.module, c.cache, a, c.p.owner) + evalStaticStmt(c.module, c.cache, c.graph.config, a, c.p.owner) result = newNodeI(nkDiscardStmt, n.info, 1) result.sons[0] = emptyNode diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index 5413565e6..974df50fb 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -11,17 +11,17 @@ import strutils, llstream, ast, astalgo, idents, lexer, options, msgs, parser, - pbraces, filters, filter_tmpl, renderer + filters, filter_tmpl, renderer type TFilterKind* = enum filtNone, filtTemplate, filtReplace, filtStrip TParserKind* = enum - skinStandard, skinStrongSpaces, skinBraces, skinEndX + skinStandard, skinStrongSpaces, skinEndX const parserNames*: array[TParserKind, string] = ["standard", "strongspaces", - "braces", "endx"] + "endx"] filterNames*: array[TFilterKind, string] = ["none", "stdtmpl", "replace", "strip"] @@ -34,8 +34,6 @@ proc parseAll*(p: var TParsers): PNode = case p.skin of skinStandard, skinStrongSpaces: result = parser.parseAll(p.parser) - of skinBraces: - result = pbraces.parseAll(p.parser) of skinEndX: internalError("parser to implement") result = ast.emptyNode @@ -44,8 +42,6 @@ proc parseTopLevelStmt*(p: var TParsers): PNode = case p.skin of skinStandard, skinStrongSpaces: result = parser.parseTopLevelStmt(p.parser) - of skinBraces: - result = pbraces.parseTopLevelStmt(p.parser) of skinEndX: internalError("parser to implement") result = ast.emptyNode @@ -62,7 +58,8 @@ proc containsShebang(s: string, i: int): bool = while j < s.len and s[j] in Whitespace: inc(j) result = s[j] == '/' -proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache): PNode = +proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache; + config: ConfigRef): PNode = result = ast.emptyNode var s = llStreamOpen(filename, fmRead) if s != nil: @@ -78,7 +75,7 @@ proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache): PNo inc(i, 2) while i < line.len and line[i] in Whitespace: inc(i) var q: TParser - parser.openParser(q, filename, llStreamOpen(substr(line, i)), cache) + parser.openParser(q, filename, llStreamOpen(substr(line, i)), cache, config) result = parser.parseAll(q) parser.closeParser(q) llStreamClose(s) @@ -139,23 +136,23 @@ proc evalPipe(p: var TParsers, n: PNode, filename: string, result = applyFilter(p, n, filename, result) proc openParsers*(p: var TParsers, fileIdx: FileIndex, inputstream: PLLStream; - cache: IdentCache) = + cache: IdentCache; config: ConfigRef) = var s: PLLStream p.skin = skinStandard let filename = fileIdx.toFullPathConsiderDirty - var pipe = parsePipe(filename, inputstream, cache) + var pipe = parsePipe(filename, inputstream, cache, config) if pipe != nil: s = evalPipe(p, pipe, filename, inputstream) else: s = inputstream case p.skin - of skinStandard, skinBraces, skinEndX: - parser.openParser(p.parser, fileIdx, s, cache, false) + of skinStandard, skinEndX: + parser.openParser(p.parser, fileIdx, s, cache, config, false) of skinStrongSpaces: - parser.openParser(p.parser, fileIdx, s, cache, true) + parser.openParser(p.parser, fileIdx, s, cache, config, true) proc closeParsers*(p: var TParsers) = parser.closeParser(p.parser) -proc parseFile*(fileIdx: FileIndex; cache: IdentCache): PNode {.procvar.} = +proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode {.procvar.} = var p: TParsers f: File @@ -163,6 +160,6 @@ proc parseFile*(fileIdx: FileIndex; cache: IdentCache): PNode {.procvar.} = if not open(f, filename): rawMessage(errCannotOpenFile, filename) return - openParsers(p, fileIdx, llStreamOpen(f), cache) + openParsers(p, fileIdx, llStreamOpen(f), cache, config) result = parseAll(p) closeParsers(p) diff --git a/compiler/vm.nim b/compiler/vm.nim index 32db8f378..6c36a1458 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1341,8 +1341,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = decodeB(rkNode) # c.debug[pc].line.int - countLines(regs[rb].strVal) ? var error: string - let ast = parseString(regs[rb].node.strVal, c.cache, c.debug[pc].toFullPath, - c.debug[pc].line.int, + let ast = parseString(regs[rb].node.strVal, c.cache, c.config, + c.debug[pc].toFullPath, c.debug[pc].line.int, proc (info: TLineInfo; msg: TMsgKind; arg: string) = if error.isNil and msg <= msgs.errMax: error = formatMsg(info, msg, arg)) @@ -1355,8 +1355,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcParseStmtToAst: decodeB(rkNode) var error: string - let ast = parseString(regs[rb].node.strVal, c.cache, c.debug[pc].toFullPath, - c.debug[pc].line.int, + let ast = parseString(regs[rb].node.strVal, c.cache, c.config, + c.debug[pc].toFullPath, c.debug[pc].line.int, proc (info: TLineInfo; msg: TMsgKind; arg: string) = if error.isNil and msg <= msgs.errMax: error = formatMsg(info, msg, arg)) @@ -1643,9 +1643,9 @@ include vmops var globalCtx*: PCtx -proc setupGlobalCtx(module: PSym; cache: IdentCache) = +proc setupGlobalCtx(module: PSym; cache: IdentCache; config: ConfigRef) = if globalCtx.isNil: - globalCtx = newCtx(module, cache) + globalCtx = newCtx(module, cache, config) registerAdditionalOps(globalCtx) else: refresh(globalCtx, module) @@ -1656,7 +1656,7 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = #pushStackFrame(c, newStackFrame()) # XXX produce a new 'globals' environment here: - setupGlobalCtx(module, cache) + setupGlobalCtx(module, cache, graph.config) result = globalCtx when hasFFI: globalCtx.features = {allowFFI, allowCast} @@ -1677,10 +1677,11 @@ proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode = const evalPass* = makePass(myOpen, nil, myProcess, myClose) -proc evalConstExprAux(module: PSym; cache: IdentCache; prc: PSym, n: PNode, +proc evalConstExprAux(module: PSym; cache: IdentCache; + config: ConfigRef; prc: PSym, n: PNode, mode: TEvalMode): PNode = let n = transformExpr(module, n) - setupGlobalCtx(module, cache) + setupGlobalCtx(module, cache, config) var c = globalCtx let oldMode = c.mode defer: c.mode = oldMode @@ -1695,17 +1696,17 @@ proc evalConstExprAux(module: PSym; cache: IdentCache; prc: PSym, n: PNode, result = rawExecute(c, start, tos).regToNode if result.info.col < 0: result.info = n.info -proc evalConstExpr*(module: PSym; cache: IdentCache, e: PNode): PNode = - result = evalConstExprAux(module, cache, nil, e, emConst) +proc evalConstExpr*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode): PNode = + result = evalConstExprAux(module, cache, config, nil, e, emConst) -proc evalStaticExpr*(module: PSym; cache: IdentCache, e: PNode, prc: PSym): PNode = - result = evalConstExprAux(module, cache, prc, e, emStaticExpr) +proc evalStaticExpr*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode, prc: PSym): PNode = + result = evalConstExprAux(module, cache, config, prc, e, emStaticExpr) -proc evalStaticStmt*(module: PSym; cache: IdentCache, e: PNode, prc: PSym) = - discard evalConstExprAux(module, cache, prc, e, emStaticStmt) +proc evalStaticStmt*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode, prc: PSym) = + discard evalConstExprAux(module, cache, config, prc, e, emStaticStmt) -proc setupCompileTimeVar*(module: PSym; cache: IdentCache, n: PNode) = - discard evalConstExprAux(module, cache, nil, n, emStaticStmt) +proc setupCompileTimeVar*(module: PSym; cache: IdentCache, config: ConfigRef; n: PNode) = + discard evalConstExprAux(module, cache, config, nil, n, emStaticStmt) proc setupMacroParam(x: PNode, typ: PType): TFullReg = case typ.kind @@ -1733,8 +1734,8 @@ iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) = const evalMacroLimit = 1000 var evalMacroCounter: int -proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode, - sym: PSym): PNode = +proc evalMacroCall*(module: PSym; cache: IdentCache; config: ConfigRef; + n, nOrig: PNode, sym: PSym): PNode = # XXX globalError() is ugly here, but I don't know a better solution for now inc(evalMacroCounter) if evalMacroCounter > evalMacroLimit: @@ -1746,7 +1747,7 @@ proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode, globalError(n.info, "in call '$#' got $#, but expected $# argument(s)" % [ n.renderTree, $(n.safeLen-1), $(sym.typ.len-1)]) - setupGlobalCtx(module, cache) + setupGlobalCtx(module, cache, config) var c = globalCtx c.comesFromHeuristic.line = 0'u16 diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 66bc8dfd2..b0a559d2c 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -10,7 +10,7 @@ ## This module contains the type definitions for the new evaluation engine. ## An instruction is 1-3 int32s in memory, it is a register based VM. -import ast, passes, msgs, idents, intsets +import ast, passes, msgs, idents, intsets, options const byteExcess* = 128 # we use excess-K for immediates @@ -206,17 +206,19 @@ type callbacks*: seq[tuple[key: string, value: VmCallback]] errorFlag*: string cache*: IdentCache + config*: ConfigRef TPosition* = distinct int PEvalContext* = PCtx -proc newCtx*(module: PSym; cache: IdentCache): PCtx = +proc newCtx*(module: PSym; cache: IdentCache; config: ConfigRef = nil): PCtx = + let conf = if config != nil: config else: newConfigRef() PCtx(code: @[], debug: @[], globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[], prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations, comesFromHeuristic: unknownLineInfo(), callbacks: @[], errorFlag: "", - cache: cache) + cache: cache, config: conf) proc refresh*(c: PCtx, module: PSym) = c.module = module From dfc17e5f8e0652ebc4c693e5a5900a122b85ab95 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 5 May 2018 21:08:45 +0200 Subject: [PATCH 16/47] make Nimble not crash after the refactoring --- compiler/lexer.nim | 3 ++- koch.nim | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 0aeb44ca3..a65587390 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -237,7 +237,8 @@ proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream; openLexer(lex, filename.fileInfoIdx, inputstream, cache, config) proc closeLexer*(lex: var TLexer) = - inc(lex.config.linesCompiled, lex.lineNumber) + if lex.config != nil: + inc(lex.config.linesCompiled, lex.lineNumber) closeBaseLexer(lex) proc getLineInfo(L: TLexer): TLineInfo = diff --git a/koch.nim b/koch.nim index d51b902ee..7a75ebf71 100644 --- a/koch.nim +++ b/koch.nim @@ -252,7 +252,7 @@ proc xz(args: string) = proc buildTool(toolname, args: string) = nimexec("cc $# $#" % [args, toolname]) - copyFile(dest="bin"/ splitFile(toolname).name.exe, source=toolname.exe) + copyFile(dest="bin" / splitFile(toolname).name.exe, source=toolname.exe) proc buildTools(latest: bool) = let nimsugExe = "bin/nimsuggest".exe From bbb0fd4eb734ed1a0445865077c27b05b46d0cbd Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 4 May 2018 14:03:16 +0200 Subject: [PATCH 17/47] remove deprecated stuff from the stdlib; introduce better deprecation warnings --- lib/deprecated/pure/ftpclient.nim | 2 +- lib/packages/docutils/rst.nim | 4 --- lib/packages/docutils/rstast.nim | 3 --- lib/pure/algorithm.nim | 3 --- lib/pure/asyncfutures.nim | 2 -- lib/pure/asynchttpserver.nim | 3 --- lib/pure/asyncnet.nim | 2 -- lib/pure/cgi.nim | 2 -- lib/pure/colors.nim | 2 -- lib/pure/complex.nim | 2 -- lib/pure/db_common.nim | 3 --- lib/pure/dynlib.nim | 6 ++--- lib/pure/encodings.nim | 2 -- lib/pure/events.nim | 3 --- lib/pure/hashes.nim | 1 - lib/pure/htmlparser.nim | 1 - lib/pure/httpclient.nim | 16 ++++------- lib/pure/httpcore.nim | 4 --- lib/pure/httpserver.nim | 2 -- lib/pure/includes/asynccommon.nim | 4 +-- lib/pure/includes/oserr.nim | 44 ------------------------------- lib/pure/json.nim | 15 +++-------- lib/pure/lexbase.nim | 2 -- lib/pure/logging.nim | 4 --- lib/pure/marshal.nim | 1 - lib/pure/memfiles.nim | 2 -- lib/pure/mersenne.nim | 2 -- lib/pure/mimetypes.nim | 2 -- lib/pure/nativesockets.nim | 5 +--- lib/pure/net.nim | 9 ------- lib/pure/nimprof.nim | 2 -- lib/pure/oids.nim | 6 ++--- lib/pure/os.nim | 16 ----------- lib/pure/ospaths.nim | 5 ---- lib/pure/osproc.nim | 33 ++++++++++------------- lib/pure/parsecfg.nim | 3 --- lib/pure/parsecsv.nim | 2 -- lib/pure/parseopt.nim | 2 -- lib/pure/parseopt2.nim | 4 --- lib/pure/parsesql.nim | 2 -- lib/pure/parseutils.nim | 2 -- lib/pure/parsexml.nim | 3 --- lib/pure/pegs.nim | 10 +++---- lib/pure/ropes.nim | 2 -- lib/pure/scgi.nim | 3 --- lib/pure/selectors.nim | 8 +++--- lib/pure/smtp.nim | 2 -- lib/pure/stats.nim | 2 -- lib/pure/streams.nim | 31 ---------------------- lib/pure/strtabs.nim | 19 +++---------- lib/pure/subexes.nim | 3 --- lib/pure/uri.nim | 8 +++--- lib/pure/xmlparser.nim | 2 -- lib/pure/xmltree.nim | 8 ------ 54 files changed, 44 insertions(+), 287 deletions(-) diff --git a/lib/deprecated/pure/ftpclient.nim b/lib/deprecated/pure/ftpclient.nim index ed2f14450..7645258b6 100644 --- a/lib/deprecated/pure/ftpclient.nim +++ b/lib/deprecated/pure/ftpclient.nim @@ -12,7 +12,7 @@ import sockets, strutils, parseutils, times, os, asyncio from asyncnet import nil from nativesockets import nil -from asyncdispatch import PFuture +from asyncdispatch import Future ## **Note**: This module is deprecated since version 0.11.3. ## You should use the async version of this module ## `asyncftpclient `_. diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 223fc836a..ff2bdb8ce 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -853,7 +853,6 @@ type DirKind = enum # must be ordered alphabetically! dkNone, dkAuthor, dkAuthors, dkCode, dkCodeBlock, dkContainer, dkContents, dkFigure, dkImage, dkInclude, dkIndex, dkRaw, dkTitle -{.deprecated: [TDirKind: DirKind].} const DirIds: array[0..12, string] = ["", "author", "authors", "code", @@ -1114,7 +1113,6 @@ proc parseHeadline(p: var RstParser): PRstNode = type IntSeq = seq[int] -{.deprecated: [TIntSeq: IntSeq].} proc tokEnd(p: RstParser): int = result = p.tok[p.idx].col + len(p.tok[p.idx].symbol) - 1 @@ -1408,8 +1406,6 @@ type hasArg, hasOptions, argIsFile, argIsWord DirFlags = set[DirFlag] SectionParser = proc (p: var RstParser): PRstNode {.nimcall.} -{.deprecated: [TDirFlag: DirFlag, TDirFlags: DirFlags, - TSectionParser: SectionParser].} proc parseDirective(p: var RstParser, flags: DirFlags): PRstNode = ## Parses arguments and options for a directive block. diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index 7be4470c1..f3596b571 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -70,8 +70,6 @@ type ## the document or the section level*: int ## valid for some node kinds sons*: RstNodeSeq ## the node's sons -{.deprecated: [TRstNodeKind: RstNodeKind, TRstNodeSeq: RstNodeSeq, - TRstNode: RstNode].} proc len*(n: PRstNode): int = result = len(n.sons) @@ -99,7 +97,6 @@ type RenderContext {.pure.} = object indent: int verbatim: int -{.deprecated: [TRenderContext: RenderContext].} proc renderRstToRst(d: var RenderContext, n: PRstNode, result: var string) {.gcsafe.} diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 5d7348b8d..6918c178d 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -13,9 +13,6 @@ type SortOrder* = enum ## sort order Descending, Ascending -{.deprecated: [TSortOrder: SortOrder].} - - proc `*`*(x: int, order: SortOrder): int {.inline.} = ## flips `x` if ``order == Descending``; ## if ``order == Ascending`` then `x` is returned. diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim index 8fedb16fe..863a6843b 100644 --- a/lib/pure/asyncfutures.nim +++ b/lib/pure/asyncfutures.nim @@ -27,8 +27,6 @@ type FutureError* = object of Exception cause*: FutureBase -{.deprecated: [PFutureBase: FutureBase, PFuture: Future].} - when not defined(release): var currentID = 0 diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index ba1615651..fe5a835d7 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -60,9 +60,6 @@ type reusePort: bool maxBody: int ## The maximum content-length that will be read for the body. -{.deprecated: [TRequest: Request, PAsyncHttpServer: AsyncHttpServer, - THttpCode: HttpCode, THttpVersion: HttpVersion].} - proc newAsyncHttpServer*(reuseAddr = true, reusePort = false, maxBody = 8388608): AsyncHttpServer = ## Creates a new ``AsyncHttpServer`` instance. diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 7c354151b..e7552e3e3 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -134,8 +134,6 @@ type protocol: Protocol AsyncSocket* = ref AsyncSocketDesc -{.deprecated: [PAsyncSocket: AsyncSocket].} - proc newAsyncSocket*(fd: AsyncFD, domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM, protocol: Protocol = IPPROTO_TCP, buffered = true): AsyncSocket = diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim index a5a404497..e0cdc2ec0 100644 --- a/lib/pure/cgi.nim +++ b/lib/pure/cgi.nim @@ -64,8 +64,6 @@ type methodPost, ## query uses the POST method methodGet ## query uses the GET method -{.deprecated: [TRequestMethod: RequestMethod, ECgi: CgiError].} - proc cgiError*(msg: string) {.noreturn.} = ## raises an ECgi exception with message `msg`. var e: ref CgiError diff --git a/lib/pure/colors.nim b/lib/pure/colors.nim index 4ec76dee0..25a2fb870 100644 --- a/lib/pure/colors.nim +++ b/lib/pure/colors.nim @@ -14,8 +14,6 @@ import strutils type Color* = distinct int ## a color stored as RGB -{.deprecated: [TColor: Color].} - proc `==` *(a, b: Color): bool {.borrow.} ## compares two colors. diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim index ccde5ee0a..98cab1a5a 100644 --- a/lib/pure/complex.nim +++ b/lib/pure/complex.nim @@ -25,8 +25,6 @@ type Complex* = tuple[re, im: float] ## a complex number, consisting of a real and an imaginary part -{.deprecated: [TComplex: Complex].} - proc toComplex*(x: SomeInteger): Complex = ## Convert some integer ``x`` to a complex number. result.re = x diff --git a/lib/pure/db_common.nim b/lib/pure/db_common.nim index 957389605..f8689024b 100644 --- a/lib/pure/db_common.nim +++ b/lib/pure/db_common.nim @@ -83,9 +83,6 @@ type foreignKey*: bool ## is this a foreign key? DbColumns* = seq[DbColumn] -{.deprecated: [EDb: DbError, TSqlQuery: SqlQuery, FDb: DbEffect, - FReadDb: ReadDbEffect, FWriteDb: WriteDbEffect].} - template sql*(query: string): SqlQuery = ## constructs a SqlQuery from the string `query`. This is supposed to be ## used as a raw-string-literal modifier: diff --git a/lib/pure/dynlib.nim b/lib/pure/dynlib.nim index ec6cbb232..5bd06f6fb 100644 --- a/lib/pure/dynlib.nim +++ b/lib/pure/dynlib.nim @@ -17,9 +17,9 @@ ## Loading a simple C function ## ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ## -## The following example demonstrates loading a function called 'greet' +## The following example demonstrates loading a function called 'greet' ## from a library that is determined at runtime based upon a language choice. -## If the library fails to load or the function 'greet' is not found, +## If the library fails to load or the function 'greet' is not found, ## it quits with a failure error code. ## ## .. code-block::nim @@ -59,8 +59,6 @@ import strutils type LibHandle* = pointer ## a handle to a dynamically loaded library -{.deprecated: [TLibHandle: LibHandle].} - proc loadLib*(path: string, global_symbols=false): LibHandle {.gcsafe.} ## loads a library from `path`. Returns nil if the library could not ## be loaded. diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim index 731fbbc29..c67cd7579 100644 --- a/lib/pure/encodings.nim +++ b/lib/pure/encodings.nim @@ -27,8 +27,6 @@ type EncodingError* = object of ValueError ## exception that is raised ## for encoding errors -{.deprecated: [EInvalidEncoding: EncodingError, PConverter: EncodingConverter].} - when defined(windows): proc eqEncodingNames(a, b: string): bool = var i = 0 diff --git a/lib/pure/events.nim b/lib/pure/events.nim index 23a8a2c58..a39dbe3bf 100644 --- a/lib/pure/events.nim +++ b/lib/pure/events.nim @@ -43,9 +43,6 @@ type s: seq[EventHandler] EventError* = object of ValueError -{.deprecated: [TEventArgs: EventArgs, TEventHandler: EventHandler, - TEventEmitter: EventEmitter, EInvalidEvent: EventError].} - proc initEventHandler*(name: string): EventHandler = ## Initializes an EventHandler with the specified name and returns it. result.handlers = @[] diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index b015ed311..6535bb0d3 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -45,7 +45,6 @@ type Hash* = int ## a hash value; hash tables using these values should ## always have a size of a power of two and can use the ``and`` ## operator instead of ``mod`` for truncation of the hash value. -{.deprecated: [THash: Hash].} proc `!&`*(h: Hash, val: int): Hash {.inline.} = ## mixes a hash value `h` with `val` to produce a new hash value. This is diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim index 2f833804d..9d4b57dc0 100644 --- a/lib/pure/htmlparser.nim +++ b/lib/pure/htmlparser.nim @@ -178,7 +178,6 @@ type tagVar, ## the HTML ``var`` element tagVideo, ## the HTML ``video`` element tagWbr ## the HTML ``wbr`` element -{.deprecated: [THtmlTag: HtmlTag].} const tagToStr* = [ diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 91b78f59b..3f1a3d067 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -219,10 +219,6 @@ type ## and ``postContent`` proc, ## when the server returns an error -{.deprecated: [TResponse: Response, PProxy: Proxy, - EInvalidProtocol: ProtocolError, EHttpRequestErr: HttpRequestError -].} - const defUserAgent* = "Nim httpclient/" & NimVersion proc httpError(msg: string) = @@ -362,8 +358,6 @@ proc parseResponse(s: Socket, getBody: bool, timeout: int): Response = else: result.body = "" -{.deprecated: [THttpMethod: HttpMethod].} - when not defined(ssl): type SSLContext = ref object var defaultSSLContext {.threadvar.}: SSLContext @@ -585,7 +579,7 @@ proc request*(url: string, httpMethod: string, extraHeaders = "", result = parseResponse(s, httpMethod != "HEAD", timeout) -proc request*(url: string, httpMethod = httpGET, extraHeaders = "", +proc request*(url: string, httpMethod = HttpGET, extraHeaders = "", body = "", sslContext = defaultSSLContext, timeout = -1, userAgent = defUserAgent, proxy: Proxy = nil): Response {.deprecated.} = @@ -627,13 +621,13 @@ proc get*(url: string, extraHeaders = "", maxRedirects = 5, ## server takes longer than specified an ETimeout exception will be raised. ## ## **Deprecated since version 0.15.0**: use ``HttpClient.get`` instead. - result = request(url, httpGET, extraHeaders, "", sslContext, timeout, + result = request(url, HttpGET, extraHeaders, "", sslContext, timeout, userAgent, proxy) var lastURL = url for i in 1..maxRedirects: if result.status.redirection(): let redirectTo = getNewLocation(lastURL, result.headers) - result = request(redirectTo, httpGET, extraHeaders, "", sslContext, + result = request(redirectTo, HttpGET, extraHeaders, "", sslContext, timeout, userAgent, proxy) lastURL = redirectTo @@ -687,13 +681,13 @@ proc post*(url: string, extraHeaders = "", body = "", if not multipart.isNil: xh.add(withNewLine("Content-Type: " & mpContentType)) - result = request(url, httpPOST, xh, xb, sslContext, timeout, userAgent, + result = request(url, HttpPOST, xh, xb, sslContext, timeout, userAgent, proxy) var lastURL = url for i in 1..maxRedirects: if result.status.redirection(): let redirectTo = getNewLocation(lastURL, result.headers) - var meth = if result.status != "307": httpGet else: httpPost + var meth = if result.status != "307": HttpGet else: HttpPost result = request(redirectTo, meth, xh, xb, sslContext, timeout, userAgent, proxy) lastURL = redirectTo diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index 5df26fdd5..f85375111 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -45,10 +45,6 @@ type ## TCP/IP tunnel, usually used for proxies. HttpPatch ## Applies partial modifications to a resource. -{.deprecated: [httpGet: HttpGet, httpHead: HttpHead, httpPost: HttpPost, - httpPut: HttpPut, httpDelete: HttpDelete, httpTrace: HttpTrace, - httpOptions: HttpOptions, httpConnect: HttpConnect].} - const Http100* = HttpCode(100) diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim index 9f54ed9e8..a81e8c0a8 100644 --- a/lib/pure/httpserver.nim +++ b/lib/pure/httpserver.nim @@ -110,7 +110,6 @@ when false: # TODO: Fix this, or get rid of it. type RequestMethod = enum reqGet, reqPost - {.deprecated: [TRequestMethod: RequestMethod].} proc executeCgi(client: Socket, path, query: string, meth: RequestMethod) = var env = newStringTable(modeCaseInsensitive) @@ -225,7 +224,6 @@ type PAsyncHTTPServer* = ref AsyncHTTPServer AsyncHTTPServer = object of Server asyncSocket: AsyncSocket -{.deprecated: [TAsyncHTTPServer: AsyncHTTPServer, TServer: Server].} proc open*(s: var Server, port = Port(80), reuseAddr = false) = ## creates a new server at port `port`. If ``port == 0`` a free port is diff --git a/lib/pure/includes/asynccommon.nim b/lib/pure/includes/asynccommon.nim index 45b10c584..06f4958c6 100644 --- a/lib/pure/includes/asynccommon.nim +++ b/lib/pure/includes/asynccommon.nim @@ -18,13 +18,13 @@ proc createAsyncNativeSocket*(domain: Domain = Domain.AF_INET, createAsyncNativeSocketImpl(domain, sockType, protocol) proc newAsyncNativeSocket*(domain: cint, sockType: cint, - protocol: cint): AsyncFD {.deprecated.} = + protocol: cint): AsyncFD {.deprecated: "use createAsyncNativeSocket instead".} = createAsyncNativeSocketImpl(domain, sockType, protocol) proc newAsyncNativeSocket*(domain: Domain = Domain.AF_INET, sockType: SockType = SOCK_STREAM, protocol: Protocol = IPPROTO_TCP): AsyncFD - {.deprecated.} = + {.deprecated: "use createAsyncNativeSocket instead".} = createAsyncNativeSocketImpl(domain, sockType, protocol) when defined(windows) or defined(nimdoc): diff --git a/lib/pure/includes/oserr.nim b/lib/pure/includes/oserr.nim index 0889d7383..bfb6118f2 100644 --- a/lib/pure/includes/oserr.nim +++ b/lib/pure/includes/oserr.nim @@ -12,50 +12,6 @@ when not defined(nimscript): when defined(windows): import winlean -proc osErrorMsg*(): string {.rtl, extern: "nos$1", deprecated.} = - ## Retrieves the operating system's error flag, ``errno``. - ## On Windows ``GetLastError`` is checked before ``errno``. - ## Returns "" if no error occurred. - ## - ## **Deprecated since version 0.9.4**: use the other ``osErrorMsg`` proc. - - result = "" - when defined(Windows) and not defined(nimscript): - var err = getLastError() - if err != 0'i32: - when useWinUnicode: - var msgbuf: WideCString - if formatMessageW(0x00000100 or 0x00001000 or 0x00000200 or 0x000000FF, - nil, err, 0, addr(msgbuf), 0, nil) != 0'i32: - result = $msgbuf - if msgbuf != nil: localFree(cast[pointer](msgbuf)) - else: - var msgbuf: cstring - if formatMessageA(0x00000100 or 0x00001000 or 0x00000200 or 0x000000FF, - nil, err, 0, addr(msgbuf), 0, nil) != 0'i32: - result = $msgbuf - if msgbuf != nil: localFree(msgbuf) - when not defined(nimscript): - if errno != 0'i32: - result = $c_strerror(errno) - -{.push warning[deprecated]: off.} -proc raiseOSError*(msg: string = "") {.noinline, rtl, extern: "nos$1", - deprecated.} = - ## raises an OSError exception with the given message ``msg``. - ## If ``msg == ""``, the operating system's error flag - ## (``errno``) is converted to a readable error message. On Windows - ## ``GetLastError`` is checked before ``errno``. - ## If no error flag is set, the message ``unknown OS error`` is used. - ## - ## **Deprecated since version 0.9.4**: use the other ``raiseOSError`` proc. - if len(msg) == 0: - var m = osErrorMsg() - raise newException(OSError, if m.len > 0: m else: "unknown OS error") - else: - raise newException(OSError, msg) -{.pop.} - proc `==`*(err1, err2: OSErrorCode): bool {.borrow.} proc `$`*(err: OSErrorCode): string {.borrow.} diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 574b13fbf..b16918959 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -158,9 +158,6 @@ type JsonKindError* = object of ValueError ## raised by the ``to`` macro if the ## JSON kind is incorrect. -{.deprecated: [TJsonEventKind: JsonEventKind, TJsonError: JsonError, - TJsonParser: JsonParser, TTokKind: TokKind].} - const errorMessages: array[JsonError, string] = [ "no error", @@ -622,9 +619,6 @@ type JsonParsingError* = object of ValueError ## is raised for a JSON error -{.deprecated: [EJsonParsingError: JsonParsingError, TJsonNode: JsonNodeObj, - PJsonNode: JsonNode, TJsonNodeKind: JsonNodeKind].} - proc raiseParseErr*(p: JsonParser, msg: string) {.noinline, noreturn.} = ## raises an `EJsonParsingError` exception. raise newException(JsonParsingError, errorMsgExpected(p, msg)) @@ -695,7 +689,7 @@ proc getBiggestInt*(n: JsonNode, default: BiggestInt = 0): BiggestInt = if n.isNil or n.kind != JInt: return default else: return n.num -proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt {.deprecated.} = +proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt {.deprecated: "use getInt or getBiggestInt instead".} = ## **Deprecated since v0.18.2:** use ``getInt`` or ``getBiggestInt`` instead. getBiggestInt(n, default) @@ -709,7 +703,7 @@ proc getFloat*(n: JsonNode, default: float = 0.0): float = of JInt: return float(n.num) else: return default -proc getFNum*(n: JsonNode, default: float = 0.0): float {.deprecated.} = +proc getFNum*(n: JsonNode, default: float = 0.0): float {.deprecated: "use getFloat instead".} = ## **Deprecated since v0.18.2:** use ``getFloat`` instead. getFloat(n, default) @@ -720,7 +714,7 @@ proc getBool*(n: JsonNode, default: bool = false): bool = if n.isNil or n.kind != JBool: return default else: return n.bval -proc getBVal*(n: JsonNode, default: bool = false): bool {.deprecated.} = +proc getBVal*(n: JsonNode, default: bool = false): bool {.deprecated: "use getBool instead".} = ## **Deprecated since v0.18.2:** use ``getBool`` instead. getBool(n, default) @@ -946,7 +940,7 @@ proc contains*(node: JsonNode, val: JsonNode): bool = assert(node.kind == JArray) find(node.elems, val) >= 0 -proc existsKey*(node: JsonNode, key: string): bool {.deprecated.} = node.hasKey(key) +proc existsKey*(node: JsonNode, key: string): bool {.deprecated: "use hasKey instead".} = node.hasKey(key) ## **Deprecated:** use `hasKey` instead. proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} = @@ -1277,7 +1271,6 @@ else: from math import `mod` type JSObject = object - {.deprecated: [TJSObject: JSObject].} proc parseNativeJson(x: cstring): JSObject {.importc: "JSON.parse".} diff --git a/lib/pure/lexbase.nim b/lib/pure/lexbase.nim index 15a390f0b..e38acd5ef 100644 --- a/lib/pure/lexbase.nim +++ b/lib/pure/lexbase.nim @@ -40,8 +40,6 @@ type offsetBase*: int # use ``offsetBase + bufpos`` to get the offset refillChars: set[char] -{.deprecated: [TBaseLexer: BaseLexer].} - const chrSize = sizeof(char) diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index 43b5ab3ab..cdff1f548 100644 --- a/lib/pure/logging.nim +++ b/lib/pure/logging.nim @@ -96,10 +96,6 @@ when not defined(js): logFiles: int # how many log files already created, e.g. basename.1, basename.2... bufSize: int # size of output buffer (-1: use system defaults, 0: unbuffered, >0: fixed buffer size) - {.deprecated: [PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].} - -{.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger].} - var level {.threadvar.}: Level ## global log filter handlers {.threadvar.}: seq[Logger] ## handlers with their own log levels diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim index 6ee830786..b88c9dd85 100644 --- a/lib/pure/marshal.nim +++ b/lib/pure/marshal.nim @@ -309,7 +309,6 @@ when not defined(testing) and isMainModule: Node = object next, prev: PNode data: string - {.deprecated: [TNode: Node].} proc buildList(): PNode = new(result) diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim index 5c73381ff..bf6795b0c 100644 --- a/lib/pure/memfiles.nim +++ b/lib/pure/memfiles.nim @@ -38,8 +38,6 @@ type else: handle: cint -{.deprecated: [TMemFile: MemFile].} - proc mapMem*(m: var MemFile, mode: FileMode = fmRead, mappedSize = -1, offset = 0): pointer = ## returns a pointer to a mapped portion of MemFile `m` diff --git a/lib/pure/mersenne.nim b/lib/pure/mersenne.nim index 6ac0c4e56..b2227f114 100644 --- a/lib/pure/mersenne.nim +++ b/lib/pure/mersenne.nim @@ -12,8 +12,6 @@ type mt: array[0..623, uint32] index: int -{.deprecated: [TMersenneTwister: MersenneTwister].} - proc newMersenneTwister*(seed: uint32): MersenneTwister = result.index = 0 result.mt[0] = seed diff --git a/lib/pure/mimetypes.nim b/lib/pure/mimetypes.nim index b397ef47b..ff69ba61e 100644 --- a/lib/pure/mimetypes.nim +++ b/lib/pure/mimetypes.nim @@ -13,8 +13,6 @@ type MimeDB* = object mimes: StringTableRef -{.deprecated: [TMimeDB: MimeDB].} - const mimes* = { "ez": "application/andrew-inset", "anx": "application/annodex", diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 09fa253f1..5545ca2d1 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -85,9 +85,6 @@ type length*: int addrList*: seq[string] -{.deprecated: [TPort: Port, TDomain: Domain, TType: SockType, - TProtocol: Protocol, TServent: Servent, THostent: Hostent].} - when useWinVersion: let osInvalidSocket* = winlean.INVALID_SOCKET @@ -640,7 +637,7 @@ proc pruneSocketSet(s: var seq[SocketHandle], fd: var TFdSet) = inc(i) setLen(s, L) -proc select*(readfds: var seq[SocketHandle], timeout = 500): int {.deprecated.} = +proc select*(readfds: var seq[SocketHandle], timeout = 500): int {.deprecated: "use selectRead instead".} = ## When a socket in ``readfds`` is ready to be read from then a non-zero ## value will be returned specifying the count of the sockets which can be ## read from. The sockets which can be read from will also be removed diff --git a/lib/pure/net.nim b/lib/pure/net.nim index e522d86fe..06bf12665 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -110,9 +110,6 @@ when defineSsl: serverGetPskFunc: SslServerGetPskFunc clientGetPskFunc: SslClientGetPskFunc - {.deprecated: [ESSL: SSLError, TSSLCVerifyMode: SSLCVerifyMode, - TSSLProtVersion: SSLProtVersion, PSSLContext: SSLContext, - TSSLAcceptResult: SSLAcceptResult].} else: type SslContext* = void # TODO: Workaround #4797. @@ -159,10 +156,6 @@ type Peek, SafeDisconn ## Ensures disconnection exceptions (ECONNRESET, EPIPE etc) are not thrown. -{.deprecated: [TSocketFlags: SocketFlag, ETimeout: TimeoutError, - TReadLineResult: ReadLineResult, TSOBool: SOBool, PSocket: Socket, - TSocketImpl: SocketImpl].} - type IpAddressFamily* {.pure.} = enum ## Describes the type of an IP address IPv6, ## IPv6 address @@ -176,8 +169,6 @@ type of IpAddressFamily.IPv4: address_v4*: array[0..3, uint8] ## Contains the IP address in bytes in ## case of IPv4 -{.deprecated: [TIpAddress: IpAddress].} - proc socketError*(socket: Socket, err: int = -1, async = false, lastError = (-1).OSErrorCode): void {.gcsafe.} diff --git a/lib/pure/nimprof.nim b/lib/pure/nimprof.nim index 4289eb049..506c6bfaa 100644 --- a/lib/pure/nimprof.nim +++ b/lib/pure/nimprof.nim @@ -30,7 +30,6 @@ when not declared(system.StackTrace): type StackTrace = object lines: array[0..20, cstring] files: array[0..20, cstring] - {.deprecated: [TStackTrace: StackTrace].} proc `[]`*(st: StackTrace, i: int): cstring = st.lines[i] # We use a simple hash table of bounded size to keep track of the stack traces: @@ -39,7 +38,6 @@ type total: int st: StackTrace ProfileData = array[0..64*1024-1, ptr ProfileEntry] -{.deprecated: [TProfileEntry: ProfileEntry, TProfileData: ProfileData].} proc `==`(a, b: StackTrace): bool = for i in 0 .. high(a.lines): diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim index 26a55de6c..d6369b5f9 100644 --- a/lib/pure/oids.nim +++ b/lib/pure/oids.nim @@ -23,11 +23,9 @@ type fuzz: int32 ## count: int32 ## -{.deprecated: [Toid: Oid].} - proc `==`*(oid1: Oid, oid2: Oid): bool = - ## Compare two Mongo Object IDs for equality - return (oid1.time == oid2.time) and (oid1.fuzz == oid2.fuzz) and (oid1.count == oid2.count) + ## Compare two Mongo Object IDs for equality + return (oid1.time == oid2.time) and (oid1.fuzz == oid2.fuzz) and (oid1.count == oid2.count) proc hexbyte*(hex: char): int = case hex diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 644afee32..03445a035 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -431,8 +431,6 @@ type fpOthersWrite, ## write access for others fpOthersRead ## read access for others -{.deprecated: [TFilePermission: FilePermission].} - proc getFilePermissions*(filename: string): set[FilePermission] {. rtl, extern: "nos$1", tags: [ReadDirEffect].} = ## retrieves file permissions for `filename`. `OSError` is raised in case of @@ -730,8 +728,6 @@ type pcDir, ## path refers to a directory pcLinkToDir ## path refers to a symbolic link to a directory -{.deprecated: [TPathComponent: PathComponent].} - when defined(posix): proc getSymlinkFileKind(path: string): PathComponent = @@ -1441,18 +1437,6 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} = if result.len == 0: result = getApplHeuristic() -proc getApplicationFilename*(): string {.rtl, extern: "nos$1", deprecated.} = - ## Returns the filename of the application's executable. - ## **Deprecated since version 0.8.12**: use ``getAppFilename`` - ## instead. - result = getAppFilename() - -proc getApplicationDir*(): string {.rtl, extern: "nos$1", deprecated.} = - ## Returns the directory of the application's executable. - ## **Deprecated since version 0.8.12**: use ``getAppDir`` - ## instead. - result = splitFile(getAppFilename()).dir - proc getAppDir*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} = ## Returns the directory of the application's executable. result = splitFile(getAppFilename()).dir diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim index ee2b715d3..c0d3ef512 100644 --- a/lib/pure/ospaths.nim +++ b/lib/pure/ospaths.nim @@ -29,11 +29,6 @@ type OSErrorCode* = distinct int32 ## Specifies an OS Error Code. -{.deprecated: [FReadEnv: ReadEnvEffect, FWriteEnv: WriteEnvEffect, - FReadDir: ReadDirEffect, - FWriteDir: WriteDirEffect, - TOSErrorCode: OSErrorCode -].} const doslikeFileSystem* = defined(windows) or defined(OS2) or defined(DOS) diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index bcab5ad3a..664446d54 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -61,9 +61,6 @@ type Process* = ref ProcessObj ## represents an operating system process -{.deprecated: [TProcess: ProcessObj, PProcess: Process, - TProcessOption: ProcessOption].} - const poUseShell* {.deprecated.} = poUsePath ## Deprecated alias for poUsePath. @@ -373,17 +370,15 @@ template streamAccess(p) = when defined(Windows) and not defined(useNimRtl): # We need to implement a handle stream for Windows: type - PFileHandleStream = ref FileHandleStream - FileHandleStream = object of StreamObj + FileHandleStream = ref object of StreamObj handle: Handle atTheEnd: bool - {.deprecated: [TFileHandleStream: FileHandleStream].} proc hsClose(s: Stream) = discard # nothing to do here - proc hsAtEnd(s: Stream): bool = return PFileHandleStream(s).atTheEnd + proc hsAtEnd(s: Stream): bool = return FileHandleStream(s).atTheEnd proc hsReadData(s: Stream, buffer: pointer, bufLen: int): int = - var s = PFileHandleStream(s) + var s = FileHandleStream(s) if s.atTheEnd: return 0 var br: int32 var a = winlean.readFile(s.handle, buffer, bufLen.cint, addr br, nil) @@ -395,13 +390,13 @@ when defined(Windows) and not defined(useNimRtl): result = br proc hsWriteData(s: Stream, buffer: pointer, bufLen: int) = - var s = PFileHandleStream(s) + var s = FileHandleStream(s) var bytesWritten: int32 var a = winlean.writeFile(s.handle, buffer, bufLen.cint, addr bytesWritten, nil) if a == 0: raiseOSError(osLastError()) - proc newFileHandleStream(handle: Handle): PFileHandleStream = + proc newFileHandleStream(handle: Handle): FileHandleStream = new(result) result.handle = handle result.closeImpl = hsClose @@ -527,7 +522,7 @@ when defined(Windows) and not defined(useNimRtl): if setHandleInformation(he, DWORD(1), DWORD(0)) == 0'i32: raiseOsError(osLastError()) if setHandleInformation(hi, DWORD(1), DWORD(0)) == 0'i32: - raiseOsError(osLastError()) + raiseOsError(osLastError()) if setHandleInformation(ho, DWORD(1), DWORD(0)) == 0'i32: raiseOsError(osLastError()) else: @@ -752,14 +747,14 @@ elif not defined(useNimRtl): copyMem(result[i], addr(x[0]), x.len+1) inc(i) - type StartProcessData = object - sysCommand: string - sysArgs: cstringArray - sysEnv: cstringArray - workingDir: cstring - pStdin, pStdout, pStderr, pErrorPipe: array[0..1, cint] - options: set[ProcessOption] - {.deprecated: [TStartProcessData: StartProcessData].} + type + StartProcessData = object + sysCommand: string + sysArgs: cstringArray + sysEnv: cstringArray + workingDir: cstring + pStdin, pStdout, pStderr, pErrorPipe: array[0..1, cint] + options: set[ProcessOption] const useProcessAuxSpawn = declared(posix_spawn) and not defined(useFork) and not defined(useClone) and not defined(linux) diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index 2a5dbc8f8..5fa2d8dc3 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -125,9 +125,6 @@ type tok: Token filename: string -{.deprecated: [TCfgEventKind: CfgEventKind, TCfgEvent: CfgEvent, - TTokKind: TokKind, TToken: Token, TCfgParser: CfgParser].} - # implementation const diff --git a/lib/pure/parsecsv.nim b/lib/pure/parsecsv.nim index 358ce829d..796114d37 100644 --- a/lib/pure/parsecsv.nim +++ b/lib/pure/parsecsv.nim @@ -66,8 +66,6 @@ type CsvError* = object of IOError ## exception that is raised if ## a parsing error occurs -{.deprecated: [TCsvRow: CsvRow, TCsvParser: CsvParser, EInvalidCsv: CsvError].} - proc raiseEInvalidCsv(filename: string, line, col: int, msg: string) {.noreturn.} = var e: ref CsvError diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim index c1a6161f9..58e1be0e4 100644 --- a/lib/pure/parseopt.nim +++ b/lib/pure/parseopt.nim @@ -54,8 +54,6 @@ type ## or the argument, ``value`` is not "" if ## the option was given a value -{.deprecated: [TCmdLineKind: CmdLineKind, TOptParser: OptParser].} - proc parseWord(s: string, i: int, w: var string, delim: set[char] = {'\x09', ' '}): int = result = i diff --git a/lib/pure/parseopt2.nim b/lib/pure/parseopt2.nim index 7254337d0..b54a56c0c 100644 --- a/lib/pure/parseopt2.nim +++ b/lib/pure/parseopt2.nim @@ -41,8 +41,6 @@ type ## or the argument, ``value`` is not "" if ## the option was given a value -{.deprecated: [TCmdLineKind: CmdLineKind, TOptParser: OptParser].} - proc initOptParser*(cmdline: seq[string]): OptParser {.rtl.} = ## Initalizes option parses with cmdline. cmdline should not contain ## argument 0 - program name. @@ -122,8 +120,6 @@ proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo2$1", deprecat type GetoptResult* = tuple[kind: CmdLineKind, key, val: TaintedString] -{.deprecated: [TGetoptResult: GetoptResult].} - iterator getopt*(p: var OptParser): GetoptResult = ## This is an convenience iterator for iterating over the given OptParser object. ## Example: diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim index fcc757bea..e3bab9a8d 100644 --- a/lib/pure/parsesql.nim +++ b/lib/pure/parsesql.nim @@ -45,8 +45,6 @@ type SqlLexer* = object of BaseLexer ## the parser object. filename: string -{.deprecated: [TToken: Token, TSqlLexer: SqlLexer].} - const tokKindToStr: array[TokKind, string] = [ "invalid", "[EOF]", "identifier", "quoted identifier", "string constant", diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index 1d76234ea..d77790fe0 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -365,8 +365,6 @@ type ikVar, ## ``var`` part of the interpolated string ikExpr ## ``expr`` part of the interpolated string -{.deprecated: [TInterpolatedKind: InterpolatedKind].} - iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind, value: string] = ## Tokenizes the string `s` into substrings for interpolation purposes. diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim index 978c9c516..e0000aad3 100644 --- a/lib/pure/parsexml.nim +++ b/lib/pure/parsexml.nim @@ -98,9 +98,6 @@ type filename: string options: set[XmlParseOption] -{.deprecated: [TXmlParser: XmlParser, TXmlParseOptions: XmlParseOption, - TXmlError: XmlErrorKind, TXmlEventKind: XmlEventKind].} - const errorMessages: array[XmlErrorKind, string] = [ "no error", diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 6d415efd0..6355c4899 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -74,8 +74,8 @@ type line: int ## line the symbol has been declared/used in col: int ## column the symbol has been declared/used in flags: set[NonTerminalFlag] ## the nonterminal's flags - rule: Node ## the rule that the symbol refers to - Node {.shallow.} = object + rule: Peg ## the rule that the symbol refers to + Peg* {.shallow.} = object ## type that represents a PEG case kind: PegKind of pkEmpty..pkWhitespace: nil of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle: term: string @@ -83,13 +83,9 @@ type of pkCharChoice, pkGreedyRepSet: charChoice: ref set[char] of pkNonTerminal: nt: NonTerminal of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns] - else: sons: seq[Node] + else: sons: seq[Peg] NonTerminal* = ref NonTerminalObj - Peg* = Node ## type that represents a PEG - -{.deprecated: [TPeg: Peg, TNode: Node].} - proc term*(t: string): Peg {.nosideEffect, rtl, extern: "npegs$1Str".} = ## constructs a PEG from a terminal string if t.len != 1: diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim index 24ba012e5..9b9cdb52a 100644 --- a/lib/pure/ropes.nim +++ b/lib/pure/ropes.nim @@ -37,8 +37,6 @@ type length: int data: string # != nil if a leaf -{.deprecated: [PRope: Rope].} - proc isConc(r: Rope): bool {.inline.} = return isNil(r.data) # Note that the left and right pointers are not needed for leafs. diff --git a/lib/pure/scgi.nim b/lib/pure/scgi.nim index 1ff26954e..e36803823 100644 --- a/lib/pure/scgi.nim +++ b/lib/pure/scgi.nim @@ -94,9 +94,6 @@ type disp: Dispatcher AsyncScgiState* = ref AsyncScgiStateObj -{.deprecated: [EScgi: ScgiError, TScgiState: ScgiState, - PAsyncScgiState: AsyncScgiState].} - proc recvBuffer(s: var ScgiState, L: int) = if L > s.bufLen: s.bufLen = L diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index dda5658a2..640df8282 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -271,7 +271,7 @@ else: msg.add("Internal Error\n") var err = newException(IOSelectorsException, msg) raise err - + proc setNonBlocking(fd: cint) {.inline.} = setBlocking(fd.SocketHandle, false) @@ -316,18 +316,18 @@ else: include ioselects/ioselectors_poll proc register*[T](s: Selector[T], fd: int | SocketHandle, - events: set[Event], data: T) {.deprecated.} = + events: set[Event], data: T) {.deprecated: "use registerHandle instead".} = ## **Deprecated since v0.18.0:** Use ``registerHandle`` instead. s.registerHandle(fd, events, data) -proc setEvent*(ev: SelectEvent) {.deprecated.} = +proc setEvent*(ev: SelectEvent) {.deprecated: "use trigger instead".} = ## Trigger event ``ev``. ## ## **Deprecated since v0.18.0:** Use ``trigger`` instead. ev.trigger() proc update*[T](s: Selector[T], fd: int | SocketHandle, - events: set[Event]) {.deprecated.} = + events: set[Event]) {.deprecated: "use updateHandle instead".} = ## Update file/socket descriptor ``fd``, registered in selector ## ``s`` with new events set ``event``. ## diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim index 08e6c8112..c2c674b84 100644 --- a/lib/pure/smtp.nim +++ b/lib/pure/smtp.nim @@ -51,8 +51,6 @@ type Smtp* = SmtpBase[Socket] AsyncSmtp* = SmtpBase[AsyncSocket] -{.deprecated: [EInvalidReply: ReplyError, TMessage: Message, TSMTP: Smtp].} - proc debugSend(smtp: Smtp | AsyncSmtp, cmd: string) {.multisync.} = if smtp.debug: echo("C:" & cmd) diff --git a/lib/pure/stats.nim b/lib/pure/stats.nim index 964938133..ce32108c2 100644 --- a/lib/pure/stats.nim +++ b/lib/pure/stats.nim @@ -65,8 +65,6 @@ type y_stats*: RunningStat ## stats for second set of data s_xy: float ## accumulated data for combined xy -{.deprecated: [TFloatClass: FloatClass, TRunningStat: RunningStat].} - # ----------- RunningStat -------------------------- proc clear*(s: var RunningStat) = ## reset `s` diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index 8fb14b6f6..68922f730 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -57,8 +57,6 @@ type tags: [WriteIOEffect], gcsafe.} flushImpl*: proc (s: Stream) {.nimcall, tags: [WriteIOEffect], gcsafe.} -{.deprecated: [PStream: Stream, TStream: StreamObj].} - proc flush*(s: Stream) = ## flushes the buffers that the stream `s` might use. if not isNil(s.flushImpl): s.flushImpl(s) @@ -76,27 +74,14 @@ proc atEnd*(s: Stream): bool = ## been read. result = s.atEndImpl(s) -proc atEnd*(s, unused: Stream): bool {.deprecated.} = - ## checks if more data can be read from `f`. Returns true if all data has - ## been read. - result = s.atEndImpl(s) - proc setPosition*(s: Stream, pos: int) = ## sets the position `pos` of the stream `s`. s.setPositionImpl(s, pos) -proc setPosition*(s, unused: Stream, pos: int) {.deprecated.} = - ## sets the position `pos` of the stream `s`. - s.setPositionImpl(s, pos) - proc getPosition*(s: Stream): int = ## retrieves the current position in the stream `s`. result = s.getPositionImpl(s) -proc getPosition*(s, unused: Stream): int {.deprecated.} = - ## retrieves the current position in the stream `s`. - result = s.getPositionImpl(s) - proc readData*(s: Stream, buffer: pointer, bufLen: int): int = ## low level proc that reads data into an untyped `buffer` of `bufLen` size. result = s.readDataImpl(s, buffer, bufLen) @@ -114,11 +99,6 @@ proc readAll*(s: Stream): string = inc r, bufferSize setLen(result, r+bufferSize) -proc readData*(s, unused: Stream, buffer: pointer, - bufLen: int): int {.deprecated.} = - ## low level proc that reads data into an untyped `buffer` of `bufLen` size. - result = s.readDataImpl(s, buffer, bufLen) - proc peekData*(s: Stream, buffer: pointer, bufLen: int): int = ## low level proc that reads data into an untyped `buffer` of `bufLen` size ## without moving stream position @@ -153,11 +133,6 @@ proc write*(s: Stream, x: string) = else: if x.len > 0: writeData(s, unsafeAddr x[0], x.len) -proc writeLn*(s: Stream, args: varargs[string, `$`]) {.deprecated.} = - ## **Deprecated since version 0.11.4:** Use **writeLine** instead. - for str in args: write(s, str) - write(s, "\n") - proc writeLine*(s: Stream, args: varargs[string, `$`]) = ## writes one or more strings to the the stream `s` followed ## by a new line. No length field or terminating zero is written. @@ -348,8 +323,6 @@ when not defined(js): data*: string pos: int - {.deprecated: [PStringStream: StringStream, TStringStream: StringStreamObj].} - proc ssAtEnd(s: Stream): bool = var s = StringStream(s) return s.pos >= s.data.len @@ -409,7 +382,6 @@ when not defined(js): FileStream* = ref FileStreamObj ## a stream that encapsulates a `File` FileStreamObj* = object of Stream f: File - {.deprecated: [PFileStream: FileStream, TFileStream: FileStreamObj].} proc fsClose(s: Stream) = if FileStream(s).f != nil: @@ -472,9 +444,6 @@ else: handle*: FileHandle pos: int - {.deprecated: [PFileHandleStream: FileHandleStream, - TFileHandleStream: FileHandleStreamObj].} - proc newEOS(msg: string): ref OSError = new(result) result.msg = msg diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 75f9b42cd..d8a23286a 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -17,9 +17,7 @@ import when defined(js): {.pragma: rtlFunc.} - {.pragma: deprecatedGetFunc.} else: - {.pragma: deprecatedGetFunc, deprecatedGet.} {.pragma: rtlFunc, rtl.} import os include "system/inclrtl" @@ -38,9 +36,6 @@ type StringTableRef* = ref StringTableObj ## use this type to declare string tables -{.deprecated: [TStringTableMode: StringTableMode, - TStringTable: StringTableObj, PStringTable: StringTableRef].} - proc len*(t: StringTableRef): int {.rtlFunc, extern: "nst$1".} = ## returns the number of keys in `t`. result = t.counter @@ -73,10 +68,6 @@ type useKey ## do not replace ``$key`` if it is not found ## in the table (or in the environment) -{.deprecated: [TFormatFlag: FormatFlag].} - -# implementation - const growthFactor = 2 startSize = 64 @@ -118,17 +109,12 @@ template get(t: StringTableRef, key: string) = raise newException(KeyError, "key not found") proc `[]`*(t: StringTableRef, key: string): var string {. - rtlFunc, extern: "nstTake", deprecatedGetFunc.} = + rtlFunc, extern: "nstTake".} = ## retrieves the location at ``t[key]``. If `key` is not in `t`, the ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether ## the key exists. get(t, key) -proc mget*(t: StringTableRef, key: string): var string {.deprecated.} = - ## retrieves the location at ``t[key]``. If `key` is not in `t`, the - ## ``KeyError`` exception is raised. Use ```[]``` instead. - get(t, key) - proc getOrDefault*(t: StringTableRef; key: string, default: string = ""): string = var index = rawGet(t, key) if index >= 0: result = t.data[index].val @@ -193,7 +179,8 @@ proc newStringTable*(mode: StringTableMode): StringTableRef {. result.counter = 0 newSeq(result.data, startSize) -proc clear*(s: StringTableRef, mode: StringTableMode) = +proc clear*(s: StringTableRef, mode: StringTableMode) {. + rtlFunc, extern: "nst$1".} = ## resets a string table to be empty again. s.mode = mode s.counter = 0 diff --git a/lib/pure/subexes.nim b/lib/pure/subexes.nim index 9d807abd4..8149c72cc 100644 --- a/lib/pure/subexes.nim +++ b/lib/pure/subexes.nim @@ -31,8 +31,6 @@ type SubexError* = object of ValueError ## exception that is raised for ## an invalid subex -{.deprecated: [EInvalidSubex: SubexError].} - proc raiseInvalidFormat(msg: string) {.noinline.} = raise newException(SubexError, "invalid format string: " & msg) @@ -44,7 +42,6 @@ type else: f: cstring num, i, lineLen: int -{.deprecated: [TFormatParser: FormatParser].} template call(x: untyped): untyped = p.i = i diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index 36ab00580..dd8040928 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -18,14 +18,12 @@ type hostname*, port*, path*, query*, anchor*: string opaque*: bool -{.deprecated: [TUrl: Url, TUri: Uri].} - {.push warning[deprecated]: off.} -proc `$`*(url: Url): string {.deprecated.} = +proc `$`*(url: Url): string {.deprecated: "use Uri instead".} = ## **Deprecated since 0.9.6**: Use ``Uri`` instead. return string(url) -proc `/`*(a, b: Url): Url {.deprecated.} = +proc `/`*(a, b: Url): Url {.deprecated: "use Uri instead".} = ## Joins two URLs together, separating them with / if needed. ## ## **Deprecated since 0.9.6**: Use ``Uri`` instead. @@ -40,7 +38,7 @@ proc `/`*(a, b: Url): Url {.deprecated.} = urlS.add(bs) result = Url(urlS) -proc add*(url: var Url, a: Url) {.deprecated.} = +proc add*(url: var Url, a: Url) {.deprecated: "use Uri instead".} = ## Appends url to url. ## ## **Deprecated since 0.9.6**: Use ``Uri`` instead. diff --git a/lib/pure/xmlparser.nim b/lib/pure/xmlparser.nim index 9159b4bfc..597b80eb5 100644 --- a/lib/pure/xmlparser.nim +++ b/lib/pure/xmlparser.nim @@ -16,8 +16,6 @@ type ## for invalid XML. errors*: seq[string] ## All detected parsing errors. -{.deprecated: [EInvalidXml: XmlError].} - proc raiseInvalidXml(errors: seq[string]) = var e: ref XmlError new(e) diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index 20bec300f..8f85cb5c9 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -33,9 +33,6 @@ type fAttr: XmlAttributes fClientData: int ## for other clients -{.deprecated: [PXmlNode: XmlNode, TXmlNodeKind: XmlNodeKind, PXmlAttributes: - XmlAttributes, TXmlNode: XmlNodeObj].} - proc newXmlNode(kind: XmlNodeKind): XmlNode = ## creates a new ``XmlNode``. new(result) @@ -155,11 +152,6 @@ proc `[]`* (n: var XmlNode, i: int): var XmlNode {.inline.} = assert n.k == xnElement result = n.s[i] -proc mget*(n: var XmlNode, i: int): var XmlNode {.inline, deprecated.} = - ## returns the `i`'th child of `n` so that it can be modified. Use ```[]``` - ## instead. - n[i] - iterator items*(n: XmlNode): XmlNode {.inline.} = ## iterates over any child of `n`. assert n.k == xnElement From d8fde9daba32019a35933cb97f482de5cf3669fa Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 5 May 2018 11:55:53 +0200 Subject: [PATCH 18/47] make tests green --- tests/async/tasyncawait.nim | 12 ++++++------ tests/collections/thashes.nim | 4 ++-- tests/exprs/tstmtexprs.nim | 2 +- tests/misc/tsimplesort.nim | 10 +++++----- tests/trmacros/thoist.nim | 2 +- tests/typerel/texplicitcmp.nim | 4 ++-- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim index 9fe9507ad..74933f063 100644 --- a/tests/async/tasyncawait.nim +++ b/tests/async/tasyncawait.nim @@ -12,11 +12,11 @@ const var clientCount = 0 -proc sendMessages(client: TAsyncFD) {.async.} = +proc sendMessages(client: AsyncFD) {.async.} = for i in 0 .. counter) result = (length * 2 < counter * 3) or (length - counter < 4) -proc nextTry(h, maxHash: THash): THash {.inline.} = +proc nextTry(h, maxHash: Hash): Hash {.inline.} = result = ((5 * h) + 1) and maxHash template rawGetImpl() = - var h: THash = hash(key) and high(t.data) # start with real hash value + var h: Hash = hash(key) and high(t.data) # start with real hash value while t.data[h].slot != seEmpty: if t.data[h].key == key and t.data[h].slot == seFilled: return h @@ -52,7 +52,7 @@ template rawGetImpl() = result = -1 template rawInsertImpl() = - var h: THash = hash(key) and high(data) + var h: Hash = hash(key) and high(data) while data[h].slot == seFilled: h = nextTry(h, high(data)) data[h].key = key @@ -162,7 +162,7 @@ iterator values*[A](t: TCountTable[A]): int = if t.data[h].val != 0: yield t.data[h].val proc RawGet[A](t: TCountTable[A], key: A): int = - var h: THash = hash(key) and high(t.data) # start with real hash value + var h: Hash = hash(key) and high(t.data) # start with real hash value while t.data[h].val != 0: if t.data[h].key == key: return h h = nextTry(h, high(t.data)) @@ -181,7 +181,7 @@ proc hasKey*[A](t: TCountTable[A], key: A): bool = proc rawInsert[A](t: TCountTable[A], data: var seq[tuple[key: A, val: int]], key: A, val: int) = - var h: THash = hash(key) and high(data) + var h: Hash = hash(key) and high(data) while data[h].val != 0: h = nextTry(h, high(data)) data[h].key = key data[h].val = val diff --git a/tests/trmacros/thoist.nim b/tests/trmacros/thoist.nim index 7d14c0abf..657f210a1 100644 --- a/tests/trmacros/thoist.nim +++ b/tests/trmacros/thoist.nim @@ -5,7 +5,7 @@ true''' import pegs -template optPeg{peg(pattern)}(pattern: string{lit}): TPeg = +template optPeg{peg(pattern)}(pattern: string{lit}): Peg = var gl {.global, gensym.} = peg(pattern) gl diff --git a/tests/typerel/texplicitcmp.nim b/tests/typerel/texplicitcmp.nim index 8aec9885a..e91ac2ffe 100644 --- a/tests/typerel/texplicitcmp.nim +++ b/tests/typerel/texplicitcmp.nim @@ -18,7 +18,7 @@ proc works() = sort(f, system.cmp[int]) outp(f) -proc weird(json_params: TTable) = +proc weird(json_params: Table) = var f = @[3, 2, 1] # The following line doesn't compile: type mismatch. Why? sort(f, system.cmp[int]) @@ -29,4 +29,4 @@ when isMainModule: sort(t, system.cmp[int]) outp(t) works() - weird(initTable[string, TJsonNode]()) + weird(initTable[string, JsonNode]()) From cd0985df0688c0e5ad6b1c867b41bbd6bbbc88ca Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 6 May 2018 08:17:32 +0200 Subject: [PATCH 19/47] update the changelog --- changelog.md | 3 + tests/parser/tbraces.nim | 432 --------------------------------------- 2 files changed, 3 insertions(+), 432 deletions(-) delete mode 100644 tests/parser/tbraces.nim diff --git a/changelog.md b/changelog.md index ba7e0ba5d..9af2aae83 100644 --- a/changelog.md +++ b/changelog.md @@ -41,6 +41,9 @@ #### Breaking changes in the compiler +- The undocumented ``#? braces`` parsing mode was removed. +- The undocumented PHP backend was removed. + ### Library additions - ``re.split`` now also supports the ``maxsplit`` parameter for consistency diff --git a/tests/parser/tbraces.nim b/tests/parser/tbraces.nim deleted file mode 100644 index 86c854546..000000000 --- a/tests/parser/tbraces.nim +++ /dev/null @@ -1,432 +0,0 @@ -#? braces - -# -# -# Nim's Runtime Library -# (c) Copyright 2015 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module implements some common generic algorithms. - -type - SortOrder* = enum { ## sort order - Descending, Ascending - } - - -type( - DummyAlias = int - OtherAlias = distinct char - - SomeObject = object of RootObj { ## declaration here - fieldA, fieldB: int - case order: SortOrder { - of Descending {a: string} - of Ascending {b: seq[char]} - } - } - - MyConcept = concept x { - x is int - } -) - -{.deprecated: [TSortOrder: SortOrder].} - - -proc `*`*(x: int, order: SortOrder): int @inline { - ## flips `x` if ``order == Descending``; - ## if ``order == Ascending`` then `x` is returned. - ## `x` is supposed to be the result of a comparator, ie ``< 0`` for - ## *less than*, ``== 0`` for *equal*, ``> 0`` for *greater than*. - var y = order.ord - 1 - result = (x xor y) - y -} - -proc fill*[T](a: var openArray[T], first, last: Natural, value: T) { - ## fills the array ``a[first..last]`` with `value`. - var x = first - while x <= last { - a[x] = value - inc(x) - } -} - -proc fill*[T](a: var openArray[T], value: T) { - ## fills the array `a` with `value`. - fill(a, 0, a.high, value) -} - -proc reverse*[T](a: var openArray[T], first, last: Natural) { - ## reverses the array ``a[first..last]``. - var x = first - var y = last - while x < y { - swap(a[x], a[y]) - dec(y) - inc(x) - } -} - -proc reverse*[T](a: var openArray[T]) { - ## reverses the array `a`. - reverse(a, 0, a.high) -} - -proc reversed*[T](a: openArray[T], first: Natural, last: int): seq[T] { - ## returns the reverse of the array `a[first..last]`. - assert last >= first-1 - var i = last - first - var x = first.int - result = newSeq[T](i + 1) - while i >= 0 { - result[i] = a[x] - dec(i) - inc(x) - } -} - -proc reversed*[T](a: openArray[T]): seq[T] { - ## returns the reverse of the array `a`. - reversed(a, 0, a.high) -} - -proc binarySearch*[T](a: openArray[T], key: T): int { - ## binary search for `key` in `a`. Returns -1 if not found. - var b = len(a) - while result < b { - var mid = (result + b) div 2 - if a[mid] < key { result = mid + 1 } else { b = mid } - } - if result >= len(a) or a[result] != key { result = -1 } -} - -proc smartBinarySearch*[T](a: openArray[T], key: T): int { - ## ``a.len`` must be a power of 2 for this to work. - var step = a.len div 2 - while step > 0 { - if a[result or step] <= key { result = result or step } - step = step shr 1 - } - if a[result] != key { result = -1 } -} - -const ( - onlySafeCode = true -) - -proc lowerBound*[T](a: openArray[T], key: T, cmp: proc(x,y: T): int @closure): int { - ## same as binarySearch except that if key is not in `a` then this - ## returns the location where `key` would be if it were. In other - ## words if you have a sorted sequence and you call - ## insert(thing, elm, lowerBound(thing, elm)) - ## the sequence will still be sorted. - ## - ## `cmp` is the comparator function to use, the expected return values are - ## the same as that of system.cmp. - ## - ## example:: - ## - ## var arr = @[1,2,3,5,6,7,8,9] - ## arr.insert(4, arr.lowerBound(4)) - ## # after running the above arr is `[1,2,3,4,5,6,7,8,9]` - result = a.low - var count = a.high - a.low + 1 - var step, pos: int - while count != 0 { - step = count div 2 - pos = result + step - if cmp(a[pos], key) < 0 { - result = pos + 1 - count -= step + 1 - } else { - count = step - } - } -} - -proc lowerBound*[T](a: openArray[T], key: T): int { lowerBound(a, key, cmp[T]) } -proc merge[T](a, b: var openArray[T], lo, m, hi: int, - cmp: proc (x, y: T): int @closure, order: SortOrder) { - template `<-` (a, b) { - when false { - a = b - } elif onlySafeCode { - shallowCopy(a, b) - } else { - copyMem(addr(a), addr(b), sizeof(T)) - } - } - # optimization: If max(left) <= min(right) there is nothing to do! - # 1 2 3 4 ## 5 6 7 8 - # -> O(n) for sorted arrays. - # On random data this safes up to 40% of merge calls - if cmp(a[m], a[m+1]) * order <= 0 { return } - var j = lo - # copy a[j..m] into b: - assert j <= m - when onlySafeCode { - var bb = 0 - while j <= m { - b[bb] <- a[j] - inc(bb) - inc(j) - } - } else { - copyMem(addr(b[0]), addr(a[j]), sizeof(T)*(m-j+1)) - j = m+1 - } - var i = 0 - var k = lo - # copy proper element back: - while k < j and j <= hi { - if cmp(b[i], a[j]) * order <= 0 { - a[k] <- b[i] - inc(i) - } else { - a[k] <- a[j] - inc(j) - } - inc(k) - } - # copy rest of b: - when onlySafeCode { - while k < j { - a[k] <- b[i] - inc(k) - inc(i) - } - } else { - if k < j { copyMem(addr(a[k]), addr(b[i]), sizeof(T)*(j-k)) } - } -} - -proc sort*[T](a: var openArray[T], - cmp: proc (x, y: T): int @closure, - order = SortOrder.Ascending) { - ## Default Nim sort (an implementation of merge sort). The sorting - ## is guaranteed to be stable and the worst case is guaranteed to - ## be O(n log n). - ## The current implementation uses an iterative - ## mergesort to achieve this. It uses a temporary sequence of - ## length ``a.len div 2``. Currently Nim does not support a - ## sensible default argument for ``cmp``, so you have to provide one - ## of your own. However, the ``system.cmp`` procs can be used: - ## - ## .. code-block:: nim - ## - ## sort(myIntArray, system.cmp[int]) - ## - ## # do not use cmp[string] here as we want to use the specialized - ## # overload: - ## sort(myStrArray, system.cmp) - ## - ## You can inline adhoc comparison procs with the `do notation - ## `_. Example: - ## - ## .. code-block:: nim - ## - ## people.sort do (x, y: Person) -> int: - ## result = cmp(x.surname, y.surname) - ## if result == 0: - ## result = cmp(x.name, y.name) - var n = a.len - var b: seq[T] - newSeq(b, n div 2) - var s = 1 - while s < n { - var m = n-1-s - while m >= 0 { - merge(a, b, max(m-s+1, 0), m, m+s, cmp, order) - dec(m, s*2) - } - s = s*2 - } -} - -proc sorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.}, - order = SortOrder.Ascending): seq[T] { - ## returns `a` sorted by `cmp` in the specified `order`. - result = newSeq[T](a.len) - for i in 0 .. a.high { result[i] = a[i] } - sort(result, cmp, order) -} - -template sortedByIt*(seq1, op: untyped): untyped { - ## Convenience template around the ``sorted`` proc to reduce typing. - ## - ## The template injects the ``it`` variable which you can use directly in an - ## expression. Example: - ## - ## .. code-block:: nim - ## - ## type Person = tuple[name: string, age: int] - ## var - ## p1: Person = (name: "p1", age: 60) - ## p2: Person = (name: "p2", age: 20) - ## p3: Person = (name: "p3", age: 30) - ## p4: Person = (name: "p4", age: 30) - ## people = @[p1,p2,p4,p3] - ## - ## echo people.sortedByIt(it.name) - ## - ## Because the underlying ``cmp()`` is defined for tuples you can do - ## a nested sort like in the following example: - ## - ## .. code-block:: nim - ## - ## echo people.sortedByIt((it.age, it.name)) - ## - var result = sorted(seq1, proc(x, y: type[seq1[0]]): int { - var it {.inject.} = x - let a = op - it = y - let b = op - result = cmp(a, b) - }) - result -} - -proc isSorted*[T](a: openarray[T], - cmp: proc(x, y: T): int {.closure.}, - order = SortOrder.Ascending): bool { - ## Checks to see whether `a` is already sorted in `order` - ## using `cmp` for the comparison. Parameters identical - ## to `sort` - result = true - for i in 0.. 0 { - of true { return false } - of false {} - } - } -} - -proc product*[T](x: openArray[seq[T]]): seq[seq[T]] { - ## produces the Cartesian product of the array. Warning: complexity - ## may explode. - result = newSeq[seq[T]]() - if x.len == 0 { return } - if x.len == 1 { - result = @x - return - } - var ( - indexes = newSeq[int](x.len) - initial = newSeq[int](x.len) - index = 0 - ) - var next = newSeq[T]() - next.setLen(x.len) - for i in 0..(x.len-1) { - if len(x[i]) == 0 { return } - initial[i] = len(x[i])-1 - } - indexes = initial - while true { - while indexes[index] == -1 { - indexes[index] = initial[index] - index += 1 - if index == x.len { return } - indexes[index] -= 1 - } - for ni, i in indexes { - next[ni] = x[ni][i] - } - var res: seq[T] - shallowCopy(res, next) - 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 # @[0, 1, 2, 3, 4, 5, 6, 7, 9, 8] - 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 # @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - 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 -} - -when isMainModule { - # Tests for lowerBound - var arr = @[1,2,3,5,6,7,8,9] - assert arr.lowerBound(0) == 0 - assert arr.lowerBound(4) == 3 - assert arr.lowerBound(5) == 3 - assert arr.lowerBound(10) == 8 - arr = @[1,5,10] - try { - assert arr.lowerBound(4) == 1 - assert arr.lowerBound(5) == 1 - assert arr.lowerBound(6) == 2 - } except ValueError {} - # Tests for isSorted - var srt1 = [1,2,3,4,4,4,4,5] - var srt2 = ["iello","hello"] - var srt3 = [1.0,1.0,1.0] - var srt4: seq[int] = @[] - assert srt1.isSorted(cmp) == true - assert srt2.isSorted(cmp) == false - assert srt3.isSorted(cmp) == true - var srtseq = newSeq[int]() - assert srtseq.isSorted(cmp) == true - # Tests for reversed - var arr1 = @[0,1,2,3,4] - assert arr1.reversed() == @[4,3,2,1,0] - for i in 0 .. high(arr1) { - assert arr1.reversed(0, i) == arr1.reversed()[high(arr1) - i .. high(arr1)] - assert arr1.reversed(i, high(arr1)) == arr1.reversed()[0 .. high(arr1) - i] - } -} From 88cf6573e04bd7ee8762aa336460b9748f0d4644 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 6 May 2018 08:59:39 +0200 Subject: [PATCH 20/47] fixes #7743 --- compiler/cgen.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index d838f9b9c..693930fbc 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -746,7 +746,7 @@ proc genProcAux(m: BModule, prc: PSym) = else: fillResult(resNode) assignParam(p, res) - resetLoc(p, res.loc) + if sfNoInit notin prc.flags: resetLoc(p, res.loc) if skipTypes(res.typ, abstractInst).kind == tyArray: #incl(res.loc.flags, lfIndirect) res.loc.storage = OnUnknown From 6e8d5790c838ecacf3a33bf3162db62b5cdc5304 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 6 May 2018 09:00:41 +0200 Subject: [PATCH 21/47] pegs: fixes another null accessing bug --- lib/pure/pegs.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 6355c4899..830429842 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -617,7 +617,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {. a, b: Rune result = start while i < len(p.term): - while true: + while i < len(p.term): fastRuneAt(p.term, i, a) if a != Rune('_'): break while result < s.len: From 700a2e125becf058f1d9d571e2c30f60888e1c53 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 6 May 2018 09:00:55 +0200 Subject: [PATCH 22/47] make the tester compile without warnings --- tests/testament/tester.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim index f08c83079..0c6f376d3 100644 --- a/tests/testament/tester.nim +++ b/tests/testament/tester.nim @@ -212,18 +212,18 @@ proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest, target: TTarg elif expected.tfile == "" and extractFilename(expected.file) != extractFilename(given.file) and "internal error:" notin expected.msg: r.addResult(test, target, expected.file, given.file, reFilesDiffer) - elif expected.line != given.line and expected.line != 0 or + elif expected.line != given.line and expected.line != 0 or expected.column != given.column and expected.column != 0: r.addResult(test, target, $expected.line & ':' & $expected.column, - $given.line & ':' & $given.column, + $given.line & ':' & $given.column, reLinesDiffer) elif expected.tfile != "" and extractFilename(expected.tfile) != extractFilename(given.tfile) and "internal error:" notin expected.msg: r.addResult(test, target, expected.tfile, given.tfile, reFilesDiffer) - elif expected.tline != given.tline and expected.tline != 0 or + elif expected.tline != given.tline and expected.tline != 0 or expected.tcolumn != given.tcolumn and expected.tcolumn != 0: r.addResult(test, target, $expected.tline & ':' & $expected.tcolumn, - $given.tline & ':' & $given.tcolumn, + $given.tline & ':' & $given.tcolumn, reLinesDiffer) else: r.addResult(test, target, expected.msg, given.msg, reSuccess) From 97056fbb9bd75a6fcf33f8bd0cb9b88f075bbb51 Mon Sep 17 00:00:00 2001 From: alaviss Date: Sun, 6 May 2018 15:34:22 +0700 Subject: [PATCH 23/47] fixes #7774 (#7783) --- compiler/vmgen.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index f7d3237b8..7f91e63db 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1554,7 +1554,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode = of tyCString, tyString: result = newNodeIT(nkStrLit, info, t) result.strVal = "" - of tyVar, tyLent, tyPointer, tyPtr, tySequence, tyExpr, + of tyVar, tyLent, tyPointer, tyPtr, tyExpr, tyStmt, tyTypeDesc, tyStatic, tyRef, tyNil: result = newNodeIT(nkNilLit, info, t) of tyProc: @@ -1585,6 +1585,8 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode = result = newNodeIT(nkCurly, info, t) of tyOpt: result = newNodeIT(nkNilLit, info, t) + of tySequence: + result = newNodeIT(nkBracket, info, t) else: globalError(info, "cannot create null element for: " & $t.kind) From d8dd43e5003d407d105ee9b6f9f2c6f4f45902d8 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 6 May 2018 10:49:09 +0200 Subject: [PATCH 24/47] fixes #7757 --- compiler/destroyer.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim index ffa3e37e5..cd16469de 100644 --- a/compiler/destroyer.nim +++ b/compiler/destroyer.nim @@ -430,6 +430,7 @@ proc injectDestructorCalls*(owner: PSym; n: PNode): PNode = c.tmp.typ = c.tmpObj c.destroys = newNodeI(nkStmtList, n.info) c.topLevelVars = newNodeI(nkVarSection, n.info) + c.toDropBit = initTable[int, PSym]() let cfg = constructCfg(owner, n) shallowCopy(c.g, cfg) c.jumpTargets = initIntSet() From 26d89fa09c3a214c9c2107367c3d3fd76f7b8e1c Mon Sep 17 00:00:00 2001 From: alaviss Date: Sun, 6 May 2018 15:55:19 +0700 Subject: [PATCH 25/47] options: use isSome (#7782) Fixes #7780 --- lib/pure/options.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pure/options.nim b/lib/pure/options.nim index aaffb57ca..bd01b208a 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -134,7 +134,7 @@ proc get*[T](self: Option[T]): T = proc get*[T](self: Option[T], otherwise: T): T = ## Returns the contents of this option or `otherwise` if the option is none. - if self.has: + if self.isSome: self.val else: otherwise @@ -154,7 +154,7 @@ proc map*[T, R](self: Option[T], callback: proc (input: T): R): Option[R] = proc flatten*[A](self: Option[Option[A]]): Option[A] = ## Remove one level of structure in a nested Option. - if self.has: + if self.isSome: self.val else: none(A) @@ -179,14 +179,14 @@ proc filter*[T](self: Option[T], callback: proc (input: T): bool): Option[T] = proc `==`*(a, b: Option): bool = ## Returns ``true`` if both ``Option``s are ``none``, ## or if they have equal values - (a.has and b.has and a.val == b.val) or (not a.has and not b.has) + (a.isSome and b.isSome and a.val == b.val) or (not a.isSome and not b.isSome) proc `$`*[T](self: Option[T]): string = ## Get the string representation of this option. If the option has a value, ## the result will be `Some(x)` where `x` is the string representation of the contained value. ## If the option does not have a value, the result will be `None[T]` where `T` is the name of ## the type contained in the option. - if self.has: + if self.isSome: "Some(" & $self.val & ")" else: "None[" & T.name & "]" From d3ad46702284ad248d2a27bb65812315168c4beb Mon Sep 17 00:00:00 2001 From: Florent Date: Sun, 6 May 2018 10:56:40 +0200 Subject: [PATCH 26/47] Fixes #7764 (#7767) * Fixes #7764 * Change KEY_RECORD_EVENT filter * Update terminal.nim * Revert changes and modify readPasswordFromStdIn --- lib/pure/terminal.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 002181a6f..5249e23c2 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -759,6 +759,10 @@ when defined(windows): x = runeLenAt(password.string, i) inc i, x password.string.setLen(max(password.len - x, 0)) + of chr(0x0): + # modifier key - ignore - for details see + # https://github.com/nim-lang/Nim/issues/7764 + continue else: password.string.add(toUTF8(c.Rune)) stdout.write "\n" From b13296533012426d386e986322009363af8a51bd Mon Sep 17 00:00:00 2001 From: Flaviu Tamas Date: Sun, 6 May 2018 05:23:08 -0400 Subject: [PATCH 27/47] Allow using CC environment variable with csources (#7754) --- tools/niminst/buildsh.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/niminst/buildsh.tmpl b/tools/niminst/buildsh.tmpl index 3e7d8ae6e..be6d43754 100644 --- a/tools/niminst/buildsh.tmpl +++ b/tools/niminst/buildsh.tmpl @@ -39,8 +39,8 @@ do esac done -CC="gcc" -LINKER="gcc" +CC="${CC:-gcc}" +LINKER="${LD:-gcc}" COMP_FLAGS="${CPPFLAGS:-} ${CFLAGS:-} ?{c.ccompiler.flags}$extraBuildArgs" LINK_FLAGS="${LDFLAGS:-} ?{c.linker.flags}" PS4="" From 7897026e575a4abd44583cd453b8d36cac96327e Mon Sep 17 00:00:00 2001 From: alaviss Date: Mon, 7 May 2018 12:30:13 +0700 Subject: [PATCH 28/47] pretty, prettybase: simplify relative paths (#7779) This allows nimble to be built with compiler as a nimble package --- compiler/nimfix/pretty.nim | 2 +- compiler/nimfix/prettybase.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/nimfix/pretty.nim b/compiler/nimfix/pretty.nim index 4627264dc..7af2a86dc 100644 --- a/compiler/nimfix/pretty.nim +++ b/compiler/nimfix/pretty.nim @@ -13,7 +13,7 @@ import strutils, os, intsets, strtabs -import "../compiler" / [options, ast, astalgo, msgs, semdata, ropes, idents] +import ".." / [options, ast, astalgo, msgs, semdata, ropes, idents] import prettybase type diff --git a/compiler/nimfix/prettybase.nim b/compiler/nimfix/prettybase.nim index ecb4b0093..c32dbe623 100644 --- a/compiler/nimfix/prettybase.nim +++ b/compiler/nimfix/prettybase.nim @@ -8,7 +8,7 @@ # import strutils, lexbase, streams -import "../compiler" / [ast, msgs, idents] +import ".." / [ast, msgs, idents] from os import splitFile type From bdcb72959729a5c4b195f9bf6b2ac8783c27f38e Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Wed, 18 Apr 2018 19:40:08 +0300 Subject: [PATCH 29/47] Better support for treating templates and macros as symbols. This allows you to pass a template or a macro to another macro which can then inspect the implementation of the former template/macro using `getImpl`. Since templates can be freely redefined, this allows you to treat their symbols as compile-time variables that have lexical scope. A motivating PoC example for a logging library taking advantage of this will be provided in the next commit. Implementation details: * The name of a template or a macro will be consider a symbol if the template/macro requires parameters * For parameterless templates/macros, you can use `bindSym`, which was extended to also work outside of compile-time procs. --- compiler/ast.nim | 13 +++ compiler/evaltempl.nim | 2 +- compiler/semexprs.nim | 8 +- compiler/semmagic.nim | 4 + compiler/sigmatch.nim | 8 +- lib/core/macros.nim | 2 +- tests/macros/ttemplatesymbols.nim | 173 ++++++++++++++++++++++++++++++ 7 files changed, 202 insertions(+), 8 deletions(-) create mode 100644 tests/macros/ttemplatesymbols.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index b8202abe6..350fa5f6a 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1615,6 +1615,19 @@ proc originatingModule*(s: PSym): PSym = proc isRoutine*(s: PSym): bool {.inline.} = result = s.kind in skProcKinds +proc isCompileTimeProc*(s: PSym): bool {.inline.} = + result = s.kind == skMacro or + s.kind == skProc and sfCompileTime in s.flags + +proc requiredParams*(s: PSym): int = + # Returns the number of required params (without default values) + # XXX: Perhaps we can store this in the `offset` field of the + # symbol instead? + for i in 1 ..< s.typ.len: + if s.typ.n[i].sym.ast != nil: + return i - 1 + return s.typ.len - 1 + proc hasPattern*(s: PSym): bool {.inline.} = result = isRoutine(s) and s.ast.sons[patternPos].kind != nkEmpty diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index fbb7eb2e6..502430815 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -63,7 +63,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode = # if the template has zero arguments, it can be called without ``()`` # `n` is then a nkSym or something similar var totalParams = case n.kind - of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: n.len-1 + of nkCallKinds: n.len-1 else: 0 var diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 4a3672aa0..29f377a19 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -960,18 +960,20 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = else: result = newSymNode(s, n.info) of skMacro: - if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0: + if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or + (n.kind notin nkCallKinds and s.requiredParams > 0): markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) - result = newSymNode(s, n.info) + result = symChoice(c, n, s, scClosed) else: result = semMacroExpr(c, n, n, s, flags) of skTemplate: if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or + (n.kind notin nkCallKinds and s.requiredParams > 0) or sfCustomPragma in sym.flags: markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) - result = newSymNode(s, n.info) + result = symChoice(c, n, s, scClosed) else: result = semTemplateExpr(c, n, s, flags) of skParam: diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 3f0df0065..bf3c55120 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -199,6 +199,10 @@ proc semBindSym(c: PContext, n: PNode): PNode = if s != nil: # we need to mark all symbols: var sc = symChoice(c, id, s, TSymChoiceRule(isMixin.intVal)) + if not getCurrOwner(c).isCompileTimeProc: + # inside regular code, bindSym resolves to the sym-choice + # nodes (see tinspectsymbol) + return sc result.add(sc) else: errorUndeclaredIdentifier(c, n.sons[1].info, sl.strVal) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 4263ef581..7e566afad 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2032,8 +2032,9 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, y.calleeSym = m.calleeSym z.calleeSym = m.calleeSym var best = -1 - for i in countup(0, sonsLen(arg) - 1): - if arg.sons[i].sym.kind in {skProc, skFunc, skMethod, skConverter, skIterator}: + for i in 0 ..< arg.len: + if arg.sons[i].sym.kind in {skProc, skFunc, skMethod, skConverter, + skIterator, skMacro, skTemplate}: copyCandidate(z, m) z.callee = arg.sons[i].typ if tfUnresolved in z.callee.flags: continue @@ -2062,6 +2063,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, x = z elif cmp == 0: y = z # z is as good as x + if x.state == csEmpty: result = nil elif y.state == csMatch and cmpCandidates(x, y) == 0: @@ -2070,7 +2072,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, # ambiguous: more than one symbol fits! # See tsymchoice_for_expr as an example. 'f.kind == tyExpr' should match # anyway: - if f.kind == tyExpr: result = arg + if f.kind in {tyExpr, tyStmt}: result = arg else: result = nil else: # only one valid interpretation found: diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 1dc067e1a..fa5cd67df 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -385,7 +385,7 @@ type {.deprecated: [TBindSymRule: BindSymRule].} -proc bindSym*(ident: string, rule: BindSymRule = brClosed): NimNode {. +proc bindSym*(ident: static[string], rule: BindSymRule = brClosed): NimNode {. magic: "NBindSym", noSideEffect.} ## creates a node that binds `ident` to a symbol node. The bound symbol ## may be an overloaded symbol. diff --git a/tests/macros/ttemplatesymbols.nim b/tests/macros/ttemplatesymbols.nim new file mode 100644 index 000000000..8d9c9ec02 --- /dev/null +++ b/tests/macros/ttemplatesymbols.nim @@ -0,0 +1,173 @@ +import + macros, algorithm, strutils + +proc normalProc(x: int) = + echo x + +template templateWithtouParams = + echo 10 + +proc overloadedProc(x: int) = + echo x + +proc overloadedProc(x: string) = + echo x + +proc overloadedProc[T](x: T) = + echo x + +template normalTemplate(x: int) = + echo x + +template overloadedTemplate(x: int) = + echo x + +template overloadedTemplate(x: string) = + echo x + +macro normalMacro(x: int): untyped = + discard + +macro macroWithoutParams: untyped = + discard + +macro inspectSymbol(sym: typed, expected: static[string]): untyped = + if sym.kind == nnkSym: + echo "Symbol node:" + let res = sym.getImpl.repr & "\n" + echo res + # echo "|", res, "|" + # echo "|", expected, "|" + if expected.len > 0: assert res == expected + elif sym.kind in {nnkClosedSymChoice, nnkOpenSymChoice}: + echo "Begin sym choice:" + var results = newSeq[string](0) + for innerSym in sym: + results.add innerSym.getImpl.repr + sort(results, cmp[string]) + let res = results.join("\n") & "\n" + echo res + if expected.len > 0: assert res == expected + echo "End symchoice." + else: + echo "Non-symbol node: ", sym.kind + if expected.len > 0: assert $sym.kind == expected + +macro inspectUntyped(sym: untyped, expected: static[string]): untyped = + let res = sym.repr + echo "Untyped node: ", res + assert res == expected + +inspectSymbol templateWithtouParams, "nnkCommand" + # this template is expanded, because bindSym was not used + # the end result is the template body (nnkCommand) + +inspectSymbol bindSym("templateWithtouParams"), """ +template templateWithtouParams() = + echo 10 + +""" + +inspectSymbol macroWithoutParams, "nnkEmpty" + # Just like the template above, the macro was expanded + +inspectSymbol bindSym("macroWithoutParams"), """ +macro macroWithoutParams(): untyped = + discard + +""" + +inspectSymbol normalMacro, """ +macro normalMacro(x: int): untyped = + discard + +""" + # Since the normalMacro has params, it's automatically + # treated as a symbol here (no need for `bindSym`) + +inspectSymbol bindSym("normalMacro"), """ +macro normalMacro(x: int): untyped = + discard + +""" + +inspectSymbol normalTemplate, """ +template normalTemplate(x: int) = + echo x + +""" + +inspectSymbol bindSym("normalTemplate"), """ +template normalTemplate(x: int) = + echo x + +""" + +inspectSymbol overloadedTemplate, """ +template overloadedTemplate(x: int) = + echo x + +template overloadedTemplate(x: string) = + echo x + +""" + +inspectSymbol bindSym("overloadedTemplate"), """ +template overloadedTemplate(x: int) = + echo x + +template overloadedTemplate(x: string) = + echo x + +""" + +inspectUntyped bindSym("overloadedTemplate"), """bindSym("overloadedTemplate")""" + # binSym is active only in the presense of `typed` params. + # `untyped` params still get the raw AST + +inspectSymbol normalProc, """ +proc normalProc(x: int) = + echo [x] + +""" + +inspectSymbol bindSym("normalProc"), """ +proc normalProc(x: int) = + echo [x] + +""" + +inspectSymbol overloadedProc, """ +proc overloadedProc(x: int) = + echo [x] + +proc overloadedProc(x: string) = + echo [x] + +proc overloadedProc[T](x: T) = + echo x + +""" + # XXX: There seems to be a repr rendering problem above. + # Notice that `echo [x]` + +inspectSymbol overloadedProc[float], """ +proc overloadedProc(x: T) = + echo [x] + +""" + # As expected, when we select a specific generic, the + # AST is no longer a symChoice + +inspectSymbol bindSym("overloadedProc"), """ +proc overloadedProc(x: int) = + echo [x] + +proc overloadedProc(x: string) = + echo [x] + +proc overloadedProc[T](x: T) = + echo x + +""" + From 2b8bf8fc4ae4204089a9f177c4ba62c5872d4f0a Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Thu, 19 Apr 2018 19:16:05 +0300 Subject: [PATCH 30/47] A motivating example for the new `bindSym` behavior. The example is a proof-of-concept logging library, allowing you to define lexically-scoped environments where certain logging attributes are applied automatically to all logging statements. fixes tmacro1 (use of `bindSym` inside static blocks) --- compiler/semdata.nim | 1 + compiler/semexprs.nim | 2 + compiler/semmagic.nim | 2 +- compiler/semstmts.nim | 2 + tests/macros/tstructuredlogging.nim | 154 ++++++++++++++++++++++++++++ 5 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 tests/macros/tstructuredlogging.nim diff --git a/compiler/semdata.nim b/compiler/semdata.nim index fc0488814..62be471f7 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -89,6 +89,7 @@ type ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot # store this info in the syms themselves!) inGenericContext*: int # > 0 if we are in a generic type + inStaticContext*: int # > 0 if we are inside a static: block inUnrolledContext*: int # > 0 if we are unrolling a loop compilesContextId*: int # > 0 if we are in a ``compiles`` magic compilesContextIdGenerator*: int diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 29f377a19..5ef9916ad 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1780,6 +1780,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = let oldInGenericContext = c.inGenericContext let oldInUnrolledContext = c.inUnrolledContext let oldInGenericInst = c.inGenericInst + let oldInStaticContext = c.inStaticContext let oldProcCon = c.p c.generics = @[] var err: string @@ -1794,6 +1795,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = c.inGenericContext = oldInGenericContext c.inUnrolledContext = oldInUnrolledContext c.inGenericInst = oldInGenericInst + c.inStaticContext = oldInStaticContext c.p = oldProcCon msgs.setInfoContextLen(oldContextLen) setLen(c.graph.owners, oldOwnerLen) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index bf3c55120..e6e29b4d3 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -199,7 +199,7 @@ proc semBindSym(c: PContext, n: PNode): PNode = if s != nil: # we need to mark all symbols: var sc = symChoice(c, id, s, TSymChoiceRule(isMixin.intVal)) - if not getCurrOwner(c).isCompileTimeProc: + if not (c.inStaticContext > 0 or getCurrOwner(c).isCompileTimeProc): # inside regular code, bindSym resolves to the sym-choice # nodes (see tinspectsymbol) return sc diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index b0bd4e0f6..f3cf4196f 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1754,7 +1754,9 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode = proc semStaticStmt(c: PContext, n: PNode): PNode = #echo "semStaticStmt" #writeStackTrace() + inc c.inStaticContext let a = semStmt(c, n.sons[0]) + dec c.inStaticContext n.sons[0] = a evalStaticStmt(c.module, c.cache, c.graph.config, a, c.p.owner) result = newNodeI(nkDiscardStmt, n.info, 1) diff --git a/tests/macros/tstructuredlogging.nim b/tests/macros/tstructuredlogging.nim new file mode 100644 index 000000000..05bb52a40 --- /dev/null +++ b/tests/macros/tstructuredlogging.nim @@ -0,0 +1,154 @@ +discard """ +output: ''' +main started: a=10, b=inner-b, c=10, d=some-d, x=16, z=20 +exiting: a=12, b=overriden-b, c=100, msg=bye bye, x=16 +''' +""" + +import macros, tables + +template scopeHolder = + 0 # scope revision number + +type + BindingsSet = Table[string, NimNode] + +proc actualBody(n: NimNode): NimNode = + # skip over the double StmtList node introduced in `mergeScopes` + result = n.body + if result.kind == nnkStmtList and result[0].kind == nnkStmtList: + result = result[0] + +iterator bindings(n: NimNode, skip = 0): (string, NimNode) = + for i in skip ..< n.len: + let child = n[i] + if child.kind in {nnkAsgn, nnkExprEqExpr}: + let name = $child[0] + let value = child[1] + yield (name, value) + +proc scopeRevision(scopeHolder: NimNode): int = + # get the revision number from a scopeHolder sym + assert scopeHolder.kind == nnkSym + var revisionNode = scopeHolder.getImpl.actualBody[0] + result = int(revisionNode.intVal) + +proc lastScopeHolder(scopeHolders: NimNode): NimNode = + # get the most recent scopeHolder from a symChoice node + if scopeHolders.kind in {nnkClosedSymChoice, nnkOpenSymChoice}: + var bestScopeRev = 0 + assert scopeHolders.len > 0 + for scope in scopeHolders: + let rev = scope.scopeRevision + if result == nil or rev > bestScopeRev: + result = scope + bestScopeRev = rev + else: + result = scopeHolders + + assert result.kind == nnkSym + +macro mergeScopes(scopeHolders: typed, newBindings: untyped): untyped = + var + bestScope = scopeHolders.lastScopeHolder + bestScopeRev = bestScope.scopeRevision + + var finalBindings = initTable[string, NimNode]() + for k, v in bindings(bestScope.getImpl.actualBody, skip = 1): + finalBindings[k] = v + + for k, v in bindings(newBindings): + finalBindings[k] = v + + var newScopeDefinition = newStmtList(newLit(bestScopeRev + 1)) + + for k, v in finalBindings: + newScopeDefinition.add newAssignment(newIdentNode(k), v) + + result = quote: + template scopeHolder = `newScopeDefinition` + +template scope(newBindings: untyped) {.dirty.} = + mergeScopes(bindSym"scopeHolder", newBindings) + +type + TextLogRecord = object + line: string + + StdoutLogRecord = object + +template setProperty(r: var TextLogRecord, key: string, val: string, isFirst: bool) = + if not first: r.line.add ", " + r.line.add key + r.line.add "=" + r.line.add val + +template setEventName(r: var StdoutLogRecord, name: string) = + stdout.write(name & ": ") + +template setProperty(r: var StdoutLogRecord, key: string, val: auto, isFirst: bool) = + when not isFirst: stdout.write ", " + stdout.write key + stdout.write "=" + stdout.write $val + +template flushRecord(r: var StdoutLogRecord) = + stdout.write "\n" + stdout.flushFile + +macro logImpl(scopeHolders: typed, + logStmtProps: varargs[untyped]): untyped = + let lexicalScope = scopeHolders.lastScopeHolder.getImpl.actualBody + var finalBindings = initOrderedTable[string, NimNode]() + + for k, v in bindings(lexicalScope, skip = 1): + finalBindings[k] = v + + for k, v in bindings(logStmtProps, skip = 1): + finalBindings[k] = v + + finalBindings.sort(system.cmp) + + let eventName = logStmtProps[0] + assert eventName.kind in {nnkStrLit} + let record = genSym(nskVar, "record") + + result = quote: + var `record`: StdoutLogRecord + setEventName(`record`, `eventName`) + + var isFirst = true + for k, v in finalBindings: + result.add newCall(newIdentNode"setProperty", + record, newLit(k), v, newLit(isFirst)) + isFirst = false + + result.add newCall(newIdentNode"flushRecord", record) + +template log(props: varargs[untyped]) {.dirty.} = + logImpl(bindSym"scopeHolder", props) + +scope: + a = 12 + b = "original-b" + +scope: + x = 16 + b = "overriden-b" + +scope: + c = 100 + +proc main = + scope: + c = 10 + + scope: + z = 20 + + log("main started", a = 10, b = "inner-b", d = "some-d") + +main() + +log("exiting", msg = "bye bye") + From e678a4285df6e567c5e924bfae941ae6b312790d Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 29 Apr 2018 12:50:54 +0300 Subject: [PATCH 31/47] Bugfix: Allow matching on nkExprEqExpr against varargs[untyped] This enables macros accepting arbitrary keyword arguments: log("foo", prop1 = "bar", prop2 = "baz") As an added bonus, simple templates with varargs arguments can now forward their params to procs accepting keyword arguments. --- compiler/sigmatch.nim | 3 ++- tests/overload/tparam_forwarding.nim | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 7e566afad..716a4f54a 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2173,7 +2173,8 @@ proc matchesAux(c: PContext, n, nOrig: PNode, var formal: PSym = if formalLen > 1: m.callee.n.sons[1].sym else: nil while a < n.len: - if a >= formalLen-1 and formal != nil and formal.typ.isVarargsUntyped: + if a >= formalLen-1 and f < formalLen and m.callee.n[f].typ.isVarargsUntyped: + formal = m.callee.n.sons[f].sym incl(marker, formal.position) if container.isNil: container = newNodeIT(nkArgList, n.sons[a].info, arrayConstr(c, n.info)) diff --git a/tests/overload/tparam_forwarding.nim b/tests/overload/tparam_forwarding.nim index c1b276bfc..cd3de32e3 100644 --- a/tests/overload/tparam_forwarding.nim +++ b/tests/overload/tparam_forwarding.nim @@ -6,6 +6,10 @@ output: '''baz a b c +x: 1, y: test 1 +x: 2, y: test 2 +x: 10, y: test 3 +x: 4, y: test 4 ''' """ @@ -35,3 +39,14 @@ templateForwarding fooVarargs, "test".len > 3, Foo(x: 10), Foo(x: 100), Foo(x: 1 procForwarding "a", "b", "c" +proc hasKeywordArgs(x = 10, y = "y") = + echo "x: ", x, ", y: ", y + +proc hasRegularArgs(x: int, y: string) = + echo "x: ", x, ", y: ", y + +templateForwarding(hasRegularArgs, true, 1, "test 1") +templateForwarding(hasKeywordArgs, true, 2, "test 2") +templateForwarding(hasKeywordArgs, true, y = "test 3") +templateForwarding(hasKeywordArgs, true, y = "test 4", x = 4) + From b0d85b0adf950685e2f7d88665a3d5b03cd06cfd Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 29 Apr 2018 13:30:08 +0300 Subject: [PATCH 32/47] Backwards-compatible support for keyword arguments in the command syntax --- changelog.md | 2 ++ compiler/parser.nim | 17 +++++++++++++---- tests/overload/tparam_forwarding.nim | 7 ++++--- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/changelog.md b/changelog.md index 9af2aae83..fe935106a 100644 --- a/changelog.md +++ b/changelog.md @@ -95,11 +95,13 @@ - ``nil`` for strings/seqs is finally gone. Instead the default value for these is ``"" / @[]``. + - Accessing the binary zero terminator in Nim's native strings is now invalid. Internally a Nim string still has the trailing zero for zero-copy interoperability with ``cstring``. Compile your code with the new switch ``--laxStrings:on`` if you need a transition period. +- The command syntax now supports keyword arguments after the first comma. ### Tool changes diff --git a/compiler/parser.nim b/compiler/parser.nim index 14683e307..0a3815f13 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -702,10 +702,17 @@ proc namedParams(p: var TParser, callee: PNode, # progress guaranteed exprColonEqExprListAux(p, endTok, result) -proc commandParam(p: var TParser): PNode = +proc commandParam(p: var TParser, isFirstParam: var bool): PNode = result = parseExpr(p) if p.tok.tokType == tkDo: result = postExprBlocks(p, result) + elif p.tok.tokType == tkEquals and not isFirstParam: + let lhs = result + result = newNodeP(nkExprEqExpr, p) + getTok(p) + addSon(result, lhs) + addSon(result, parseExpr(p)) + isFirstParam = false proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode = #| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks? @@ -748,10 +755,11 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode = let a = result result = newNodeP(nkCommand, p) addSon(result, a) + var isFirstParam = true when true: # progress NOT guaranteed p.hasProgress = false - addSon result, commandParam(p) + addSon result, commandParam(p, isFirstParam) if not p.hasProgress: break else: while p.tok.tokType != tkEof: @@ -1303,17 +1311,18 @@ proc parseExprStmt(p: var TParser): PNode = addSon(result, b) else: # simpleExpr parsed 'p a' from 'p a, b'? + var isFirstParam = false if p.tok.indent < 0 and p.tok.tokType == tkComma and a.kind == nkCommand: result = a while true: getTok(p) optInd(p, result) - addSon(result, commandParam(p)) + addSon(result, commandParam(p, isFirstParam)) if p.tok.tokType != tkComma: break elif p.tok.indent < 0 and isExprStart(p): result = newNode(nkCommand, a.info, @[a]) while true: - addSon(result, commandParam(p)) + addSon(result, commandParam(p, isFirstParam)) if p.tok.tokType != tkComma: break getTok(p) optInd(p, result) diff --git a/tests/overload/tparam_forwarding.nim b/tests/overload/tparam_forwarding.nim index cd3de32e3..b0eea42c7 100644 --- a/tests/overload/tparam_forwarding.nim +++ b/tests/overload/tparam_forwarding.nim @@ -46,7 +46,8 @@ proc hasRegularArgs(x: int, y: string) = echo "x: ", x, ", y: ", y templateForwarding(hasRegularArgs, true, 1, "test 1") -templateForwarding(hasKeywordArgs, true, 2, "test 2") -templateForwarding(hasKeywordArgs, true, y = "test 3") -templateForwarding(hasKeywordArgs, true, y = "test 4", x = 4) +templateForwarding hasKeywordArgs, true, 2, "test 2" + +templateForwarding(hasKeywordArgs, true, y = "test 3") +templateForwarding hasKeywordArgs, true, y = "test 4", x = 4 From ae5c946a325c8833472173e63017dbed39f23abe Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 29 Apr 2018 13:50:21 +0300 Subject: [PATCH 33/47] Support thread-local variables declared inside procs; fixes #7565 --- changelog.md | 3 ++ compiler/pragmas.nim | 2 +- doc/manual.rst | 5 ++- tests/threads/tthreadvars.nim | 78 +++++++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 tests/threads/tthreadvars.nim diff --git a/changelog.md b/changelog.md index fe935106a..4f87d5fe1 100644 --- a/changelog.md +++ b/changelog.md @@ -103,6 +103,9 @@ - The command syntax now supports keyword arguments after the first comma. +- Thread-local variables can now be declared inside procs. This implies all + the effects of the `global` pragma. + ### Tool changes - ``jsondoc2`` has been renamed ``jsondoc``, similar to how ``doc2`` was renamed diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 5aa903771..0b8bcd374 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -777,7 +777,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, incl(sym.flags, sfRegister) of wThreadVar: noVal(it) - incl(sym.flags, sfThread) + incl(sym.flags, {sfThread, sfGlobal}) of wDeadCodeElimUnused: discard # deprecated, dead code elim always on of wNoForward: pragmaNoForward(c, it) of wReorder: pragmaNoForward(c, it, sfReorder) diff --git a/doc/manual.rst b/doc/manual.rst index fabcf058a..1a4ed19b7 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -7798,8 +7798,9 @@ Future directions: Threadvar pragma ---------------- -A global variable can be marked with the ``threadvar`` pragma; it is -a `thread-local`:idx: variable then: +A variable can be marked with the ``threadvar`` pragma, which makes it a +`thread-local`:idx: variable; Additionally, this implies all the effects +of the ``global`` pragma. .. code-block:: nim var checkpoints* {.threadvar.}: seq[string] diff --git a/tests/threads/tthreadvars.nim b/tests/threads/tthreadvars.nim new file mode 100644 index 000000000..81aa2e5ec --- /dev/null +++ b/tests/threads/tthreadvars.nim @@ -0,0 +1,78 @@ +discard """ +output: ''' +10 +1111 +1222 +3030303 +3060606 +6060606 +6121212 +3030903 +3061206 +3031503 +3061806 +5050505 +5101010 +''' +""" + +import typetraits + +var tls1 {.threadvar.}: int +var g0: int +var g1 {.global.}: int + +proc customInc(x: var int, delta: int) = + x += delta + +customInc(tls1, 10) +echo tls1 + +proc nonGenericProc: int = + var local: int + var nonGenericTls {.threadvar.}: int + var nonGenericGlobal {.global.}: int + var nonGenericMixedPragmas {.global, threadvar.}: int + + customInc local, 1000 + customInc nonGenericTls, 1 + customInc nonGenericGlobal, 10 + customInc nonGenericMixedPragmas, 100 + + return local + nonGenericTls + nonGenericGlobal + nonGenericMixedPragmas + +proc genericProc(T: typedesc): int = + var local: int + var genericTls {.threadvar.}: int + var genericGlobal {.global.}: int + var genericMixedPragmas {.global, threadvar.}: int + + customInc local, T.name.len * 1000000 + customInc genericTls, T.name.len * 1 + customInc genericGlobal, T.name.len * 100 + customInc genericMixedPragmas, T.name.len * 10000 + + return local + genericTls + genericGlobal + genericMixedPragmas + +echo nonGenericProc() +echo nonGenericProc() + +echo genericProc(int) +echo genericProc(int) + +echo genericProc(string) +echo genericProc(string) + +proc echoInThread[T]() {.thread.} = + echo genericProc(T) + echo genericProc(T) + +proc newEchoThread(T: typedesc) = + var t: Thread[void] + createThread(t, echoInThread[T]) + joinThreads(t) + +newEchoThread int +newEchoThread int +newEchoThread float + From 4409c82228ed2aa6d169c3b3dfbcbff914fc9af6 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 29 Apr 2018 13:56:04 +0300 Subject: [PATCH 34/47] The `terminal` module now exports additional procs for generating ANSI color codes as strings. --- changelog.md | 2 ++ lib/pure/terminal.nim | 64 +++++++++++++++++++++++++++++-------------- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/changelog.md b/changelog.md index 4f87d5fe1..2a1e80573 100644 --- a/changelog.md +++ b/changelog.md @@ -72,6 +72,8 @@ - ``algorithm.smartBinarySearch`` and ``algorithm.binarySearch`` is now joined in ``binarySearch``. ``smartbinarySearch`` is now deprecated. +- The `terminal` module now exports additional procs for generating ANSI color + codes as strings. ### Language additions diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 5249e23c2..db16c23b3 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -29,9 +29,7 @@ when not hasThreadSupport: var colorsFGCache = initTable[Color, string]() colorsBGCache = initTable[Color, string]() - when not defined(windows): - var - styleCache = initTable[int, string]() + styleCache = initTable[int, string]() var trueColorIsSupported: bool @@ -41,6 +39,7 @@ var const fgPrefix = "\x1b[38;2;" bgPrefix = "\x1b[48;2;" + ansiResetCode* = "\e[0m" when not defined(windows): const @@ -468,7 +467,7 @@ proc resetAttributes*(f: File) = else: discard setConsoleTextAttribute(hStdout, oldStdoutAttr) else: - f.write("\e[0m") + f.write(ansiResetCode) type Style* = enum ## different styles for text output @@ -487,15 +486,22 @@ when not defined(windows): gFG {.threadvar.}: int gBG {.threadvar.}: int - proc getStyleStr(style: int): string = - when hasThreadSupport: - result = fmt"{stylePrefix}{style}m" +proc ansiStyleCode*(style: int): string = + when hasThreadSupport: + result = fmt"{stylePrefix}{style}m" + else: + if styleCache.hasKey(style): + result = styleCache[style] else: - if styleCache.hasKey(style): - result = styleCache[style] - else: - result = fmt"{stylePrefix}{style}m" - styleCache[style] = result + result = fmt"{stylePrefix}{style}m" + styleCache[style] = result + +template ansiStyleCode*(style: Style): string = + ansiStyleCode(style.int) + +# The styleCache can be skipped when `style` is known at compile-time +template ansiStyleCode*(style: static[Style]): string = + (static(stylePrefix & $style.int & "m")) proc setStyle*(f: File, style: set[Style]) = ## Sets the terminal style. @@ -510,7 +516,7 @@ proc setStyle*(f: File, style: set[Style]) = discard setConsoleTextAttribute(h, old or a) else: for s in items(style): - f.write(getStyleStr(ord(s))) + f.write(ansiStyleCode(s)) proc writeStyled*(txt: string, style: set[Style] = {styleBright}) = ## Writes the text `txt` in a given `style` to stdout. @@ -524,9 +530,9 @@ proc writeStyled*(txt: string, style: set[Style] = {styleBright}) = stdout.write(txt) stdout.resetAttributes() if gFG != 0: - stdout.write(getStyleStr(gFG)) + stdout.write(ansiStyleCode(gFG)) if gBG != 0: - stdout.write(getStyleStr(gBG)) + stdout.write(ansiStyleCode(gBG)) type ForegroundColor* = enum ## terminal's foreground colors @@ -572,7 +578,7 @@ proc setForegroundColor*(f: File, fg: ForegroundColor, bright=false) = else: gFG = ord(fg) if bright: inc(gFG, 60) - f.write(getStyleStr(gFG)) + f.write(ansiStyleCode(gFG)) proc setBackgroundColor*(f: File, bg: BackgroundColor, bright=false) = ## Sets the terminal's background color. @@ -594,10 +600,18 @@ proc setBackgroundColor*(f: File, bg: BackgroundColor, bright=false) = else: gBG = ord(bg) if bright: inc(gBG, 60) - f.write(getStyleStr(gBG)) + f.write(ansiStyleCode(gBG)) +proc ansiForegroundColorCode*(fg: ForegroundColor, bright=false): string = + var style = ord(fg) + if bright: inc(style, 60) + return ansiStyleCode(style) -proc getFGColorStr(color: Color): string = +template ansiForegroundColorCode*(fg: static[ForegroundColor], + bright: static[bool] = false): string = + ansiStyleCode(fg.int + bright.int * 60) + +proc ansiForegroundColorCode*(color: Color): string = when hasThreadSupport: let rgb = extractRGB(color) result = fmt"{fgPrefix}{rgb.r};{rgb.g};{rgb.b}m" @@ -609,7 +623,11 @@ proc getFGColorStr(color: Color): string = result = fmt"{fgPrefix}{rgb.r};{rgb.g};{rgb.b}m" colorsFGCache[color] = result -proc getBGColorStr(color: Color): string = +template ansiForegroundColorCode*(color: static[Color]): string = + let rgb = extractRGB(color) + (static(fmt"{fgPrefix}{rgb.r};{rgb.g};{rgb.b}m")) + +proc ansiBackgroundColorCode*(color: Color): string = when hasThreadSupport: let rgb = extractRGB(color) result = fmt"{bgPrefix}{rgb.r};{rgb.g};{rgb.b}m" @@ -621,15 +639,19 @@ proc getBGColorStr(color: Color): string = result = fmt"{bgPrefix}{rgb.r};{rgb.g};{rgb.b}m" colorsFGCache[color] = result +template ansiBackgroundColorCode*(color: static[Color]): string = + const rgb = extractRGB(color) + (static(fmt"{bgPrefix}{rgb.r};{rgb.g};{rgb.b}m")) + proc setForegroundColor*(f: File, color: Color) = ## Sets the terminal's foreground true color. if trueColorIsEnabled: - f.write(getFGColorStr(color)) + f.write(ansiForegroundColorCode(color)) proc setBackgroundColor*(f: File, color: Color) = ## Sets the terminal's background true color. if trueColorIsEnabled: - f.write(getBGColorStr(color)) + f.write(ansiBackgroundColorCode(color)) proc setTrueColor(f: File, color: Color) = if fgSetColor: From 4ab1cfb0b07b33015652e8f0d0444f1feed18a57 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Thu, 3 May 2018 11:42:15 +0300 Subject: [PATCH 35/47] fix a compiler crash related to the new strings in C++ mode --- compiler/ast.nim | 2 +- compiler/astalgo.nim | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 350fa5f6a..2cace380d 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1684,7 +1684,7 @@ proc isException*(t: PType): bool = var base = t while base != nil: - if base.sym.magic == mException: + if base.sym != nil and base.sym.magic == mException: return true base = base.lastSon return false diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 196ac8690..a35fa4fbb 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -69,22 +69,22 @@ proc debug*(n: PNode) {.deprecated.} template mdbg*: bool {.dirty.} = when compiles(c.module): - c.module.fileIdx == gProjectMainIdx + c.module.fileIdx.int32 == gProjectMainIdx elif compiles(c.c.module): - c.c.module.fileIdx == gProjectMainIdx + c.c.module.fileIdx.int32 == gProjectMainIdx elif compiles(m.c.module): - m.c.module.fileIdx == gProjectMainIdx + m.c.module.fileIdx.int32 == gProjectMainIdx elif compiles(cl.c.module): - cl.c.module.fileIdx == gProjectMainIdx + cl.c.module.fileIdx.int32 == gProjectMainIdx elif compiles(p): when compiles(p.lex): - p.lex.fileIdx == gProjectMainIdx + p.lex.fileIdx.int32 == gProjectMainIdx else: - p.module.module.fileIdx == gProjectMainIdx + p.module.module.fileIdx.int32 == gProjectMainIdx elif compiles(m.module.fileIdx): - m.module.fileIdx == gProjectMainIdx + m.module.fileIdx.int32 == gProjectMainIdx elif compiles(L.fileIdx): - L.fileIdx == gProjectMainIdx + L.fileIdx.int32 == gProjectMainIdx else: error() From 72976139009b9ae74669dc2443474f091c99f2e4 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Thu, 3 May 2018 19:42:20 +0300 Subject: [PATCH 36/47] Bugfix: The compiler were not inserting proper downcasts for generic types This resulted in a codegen error in C++ mode, because the generic types were not defined in modules where calls requiring downcasts were used (generating a downcast forces the inclusion of the full definition of the involved types). --- compiler/sigmatch.nim | 3 ++- compiler/types.nim | 4 ++-- tests/generics/module_with_generics.nim | 14 ++++++++++++++ tests/generics/t5602_inheritence.nim | 8 +++++++- 4 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 tests/generics/module_with_generics.nim diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 716a4f54a..55d83d990 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1962,7 +1962,8 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType, inc(m.genericMatches) if arg.typ == nil: result = arg - elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple: + elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple or + m.inheritancePenalty > 0: result = implicitConv(nkHiddenSubConv, f, arg, m, c) elif arg.typ.isEmptyContainer: result = arg.copyTree diff --git a/compiler/types.nim b/compiler/types.nim index edf4e5b46..b9b6ab33c 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -612,7 +612,7 @@ proc firstOrd*(t: PType): BiggestInt = else: assert(t.n.sons[0].kind == nkSym) result = t.n.sons[0].sym.position - of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic: + of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic, tyInferred: result = firstOrd(lastSon(t)) of tyOrdinal: if t.len > 0: result = firstOrd(lastSon(t)) @@ -651,7 +651,7 @@ proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt = of tyEnum: assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym) result = t.n.sons[sonsLen(t.n) - 1].sym.position - of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic: + of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tyStatic, tyInferred: result = lastOrd(lastSon(t)) of tyProxy: result = 0 of tyOrdinal: diff --git a/tests/generics/module_with_generics.nim b/tests/generics/module_with_generics.nim new file mode 100644 index 000000000..e801a4790 --- /dev/null +++ b/tests/generics/module_with_generics.nim @@ -0,0 +1,14 @@ +type + Base[T] = ref object {.inheritable.} + value*: T + + Derived[T] = ref object of Base[T] + derivedValue*: T + +proc makeDerived*[T](v: T): Derived[T] = + new result + result.value = v + +proc setBaseValue*[T](a: Base[T], value: T) = + a.value = value + diff --git a/tests/generics/t5602_inheritence.nim b/tests/generics/t5602_inheritence.nim index 6d48c796e..ee5ba89d5 100644 --- a/tests/generics/t5602_inheritence.nim +++ b/tests/generics/t5602_inheritence.nim @@ -1,10 +1,11 @@ discard """ output: "seq[float]\n0" + targets: "c cpp" """ # https://github.com/nim-lang/Nim/issues/5602 -import typetraits +import typetraits, module_with_generics type Foo[T] = object of RootObj @@ -16,3 +17,8 @@ proc p[T](f: Foo[T]): T = var s: Bar[float] echo p(s).len # the bug was: p(s) should return seq[float], but returns float instead +# Test overloading and code generation when +# downcasting is required for generic types: +var d = makeDerived(10) +setBaseValue(d, 20) + From cf13c5fba48e757531b3f9cb0e3aeae7710c849c Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Fri, 4 May 2018 17:47:37 +0300 Subject: [PATCH 37/47] implement the export/except statement --- changelog.md | 2 ++ compiler/importer.nim | 13 ++++++++----- compiler/semexprs.nim | 23 +++++++++++++++++++++-- doc/manual.rst | 3 +++ tests/modules/definitions.nim | 4 ++++ tests/modules/proxy_module.nim | 3 +++ 6 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 tests/modules/definitions.nim create mode 100644 tests/modules/proxy_module.nim diff --git a/changelog.md b/changelog.md index 2a1e80573..cbefbc421 100644 --- a/changelog.md +++ b/changelog.md @@ -108,6 +108,8 @@ - Thread-local variables can now be declared inside procs. This implies all the effects of the `global` pragma. +- Nim now supports `except` clause in the export statement. + ### Tool changes - ``jsondoc2`` has been renamed ``jsondoc``, similar to how ``doc2`` was renamed diff --git a/compiler/importer.nim b/compiler/importer.nim index f4903e6c4..a5c361864 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -16,6 +16,13 @@ import proc evalImport*(c: PContext, n: PNode): PNode proc evalFrom*(c: PContext, n: PNode): PNode +proc readExceptSet*(n: PNode): IntSet = + assert n.kind in {nkImportExceptStmt, nkExportExceptStmt} + result = initIntSet() + for i in 1 ..< n.len: + let ident = lookups.considerQuotedIdent(n[i]) + result.incl(ident.id) + proc importPureEnumField*(c: PContext; s: PSym) = var check = strTableGet(c.importTable.symbols, s.name) if check == nil: @@ -198,9 +205,5 @@ proc evalImportExcept*(c: PContext, n: PNode): PNode = if m != nil: n.sons[0] = newSymNode(m) addDecl(c, m, n.info) # add symbol to symbol table of module - var exceptSet = initIntSet() - for i in countup(1, sonsLen(n) - 1): - let ident = lookups.considerQuotedIdent(n.sons[i]) - exceptSet.incl(ident.id) - importAllSymbolsExcept(c, m, exceptSet) + importAllSymbolsExcept(c, m, readExceptSet(n)) #importForwarded(c, m.ast, exceptSet) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 5ef9916ad..1ef284a77 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2160,9 +2160,25 @@ proc semBlock(c: PContext, n: PNode): PNode = closeScope(c) dec(c.p.nestedBlockCounter) +proc semExportExcept(c: PContext, n: PNode): PNode = + let moduleName = semExpr(c, n[0]) + if moduleName.kind != nkSym or moduleName.sym.kind != skModule: + localError(n.info, "The export/except syntax expects a module name") + return + let exceptSet = readExceptSet(n) + let exported = moduleName.sym + strTableAdd(c.module.tab, exported) + var i: TTabIter + var s = initTabIter(i, exported.tab) + while s != nil: + if s.kind in ExportableSymKinds+{skModule} and + s.name.id notin exceptSet: + strTableAdd(c.module.tab, s) + s = nextIter(i, exported.tab) + result = n + proc semExport(c: PContext, n: PNode): PNode = var x = newNodeI(n.kind, n.info) - #let L = if n.kind == nkExportExceptStmt: L = 1 else: n.len for i in 0.. Date: Fri, 4 May 2018 19:56:03 +0300 Subject: [PATCH 38/47] bugfix: strutils.find was broken for strings with uneven number of chars For some reason, the problem was manifesting only inside the VM, it was detecting an attempt to read past the string end (i.e. the formerly accessible null byte). To catch such errors, strutils now performs static tests too. I've solved the problem by re-implementing the Boyer-Moore algotihm in a cleaner way and I took the opportunity to make some other optimisations to strutils. --- lib/pure/strutils.nim | 454 +++++++++++++++++++++++------------------- 1 file changed, 245 insertions(+), 209 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 3f01f0285..ee3072c85 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1262,21 +1262,20 @@ proc initSkipTable*(a: var SkipTable, sub: string) {.noSideEffect, rtl, extern: "nsuInitSkipTable".} = ## Preprocess table `a` for `sub`. let m = len(sub) - let m1 = m + 1 var i = 0 while i <= 0xff-7: - a[chr(i + 0)] = m1 - a[chr(i + 1)] = m1 - a[chr(i + 2)] = m1 - a[chr(i + 3)] = m1 - a[chr(i + 4)] = m1 - a[chr(i + 5)] = m1 - a[chr(i + 6)] = m1 - a[chr(i + 7)] = m1 + a[chr(i + 0)] = m + a[chr(i + 1)] = m + a[chr(i + 2)] = m + a[chr(i + 3)] = m + a[chr(i + 4)] = m + a[chr(i + 5)] = m + a[chr(i + 6)] = m + a[chr(i + 7)] = m i += 8 - for i in 0..m-1: - a[sub[i]] = m-i + for i in 0 ..< m - 1: + a[sub[i]] = m - 1 - i proc find*(a: SkipTable, s, sub: string, start: Natural = 0, last: Natural = 0): int {.noSideEffect, rtl, extern: "nsuFindStrA".} = @@ -1284,18 +1283,29 @@ proc find*(a: SkipTable, s, sub: string, start: Natural = 0, last: Natural = 0): ## If `last` is unspecified, it defaults to `s.high`. ## ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. + let last = if last==0: s.high else: last - m = len(sub) - n = last + 1 - # search: - var j = start - while j <= n - m: - block match: - for k in 0..m-1: - if sub[k] != s[k+j]: break match - return j - inc(j, a[s[j+m]]) + sLen = last - start + 1 + subLast = sub.len - 1 + + if subLast == -1: + # this was an empty needle string, + # we count this as match in the first possible position: + return start + + # This is an implementation of the Boyer-Moore Horspool algorithms + # https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore%E2%80%93Horspool_algorithm + var skip = start + + while last - skip >= subLast: + var i = subLast + while s[skip + i] == sub[i]: + if i == 0: + return skip + dec i + inc skip, a[s[skip + subLast]] + return -1 when not (defined(js) or defined(nimdoc) or defined(nimscript)): @@ -1455,23 +1465,41 @@ proc contains*(s: string, chars: set[char]): bool {.noSideEffect.} = proc replace*(s, sub: string, by = ""): string {.noSideEffect, rtl, extern: "nsuReplaceStr".} = ## Replaces `sub` in `s` by the string `by`. - var a {.noinit.}: SkipTable result = "" - initSkipTable(a, sub) - let last = s.high - var i = 0 - while true: - let j = find(a, s, sub, i, last) - if j < 0: break - add result, substr(s, i, j - 1) + let subLen = sub.len + if subLen == 0: + for c in s: + add result, by + add result, c add result, by - if sub.len == 0: - if i < s.len: add result, s[i] - i = j + 1 - else: - i = j + sub.len - # copy the rest: - add result, substr(s, i) + return + elif subLen == 1: + # when the pattern is a single char, we use a faster + # char-based search that doesn't need a skip table: + var c = sub[0] + let last = s.high + var i = 0 + while true: + let j = find(s, c, i, last) + if j < 0: break + add result, substr(s, i, j - 1) + add result, by + i = j + subLen + # copy the rest: + add result, substr(s, i) + else: + var a {.noinit.}: SkipTable + initSkipTable(a, sub) + let last = s.high + var i = 0 + while true: + let j = find(a, s, sub, i, last) + if j < 0: break + add result, substr(s, i, j - 1) + add result, by + i = j + subLen + # copy the rest: + add result, substr(s, i) proc replace*(s: string, sub, by: char): string {.noSideEffect, rtl, extern: "nsuReplaceChar".} = @@ -1492,6 +1520,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect, ## Each occurrence of `sub` has to be surrounded by word boundaries ## (comparable to ``\\w`` in regular expressions), otherwise it is not ## replaced. + if sub.len == 0: return s const wordChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'} var a {.noinit.}: SkipTable result = "" @@ -2326,236 +2355,243 @@ proc removePrefix*(s: var string, prefix: string) {. s.delete(0, prefix.len - 1) when isMainModule: - doAssert align("abc", 4) == " abc" - doAssert align("a", 0) == "a" - doAssert align("1232", 6) == " 1232" - doAssert align("1232", 6, '#') == "##1232" + proc nonStaticTests = + doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000" + doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235." + doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6" + doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001" + doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in + ["1,0e-11", "1,0e-011"] + # bug #6589 + doAssert formatFloat(123.456, ffScientific, precision = -1) == "1.234560e+02" - doAssert alignLeft("abc", 4) == "abc " - doAssert alignLeft("a", 0) == "a" - doAssert alignLeft("1232", 6) == "1232 " - doAssert alignLeft("1232", 6, '#') == "1232##" + doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c" + doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb" - let - inp = """ this is a long text -- muchlongerthan10chars and here - it goes""" - outp = " this is a\nlong text\n--\nmuchlongerthan10chars\nand here\nit goes" - doAssert wordWrap(inp, 10, false) == outp + block: # formatSize tests + doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB" + doAssert formatSize((2.234*1024*1024).int) == "2.234MiB" + doAssert formatSize(4096) == "4KiB" + doAssert formatSize(4096, prefix=bpColloquial, includeSpace=true) == "4 kB" + doAssert formatSize(4096, includeSpace=true) == "4 KiB" + doAssert formatSize(5_378_934, prefix=bpColloquial, decimalSep=',') == "5,13MB" - let - longInp = """ThisIsOneVeryLongStringWhichWeWillSplitIntoEightSeparatePartsNow""" - longOutp = "ThisIsOn\neVeryLon\ngStringW\nhichWeWi\nllSplitI\nntoEight\nSeparate\nPartsNow" - doAssert wordWrap(longInp, 8, true) == longOutp + block: # formatEng tests + doAssert formatEng(0, 2, trim=false) == "0.00" + doAssert formatEng(0, 2) == "0" + doAssert formatEng(53, 2, trim=false) == "53.00" + doAssert formatEng(0.053, 2, trim=false) == "53.00e-3" + doAssert formatEng(0.053, 4, trim=false) == "53.0000e-3" + doAssert formatEng(0.053, 4, trim=true) == "53e-3" + doAssert formatEng(0.053, 0) == "53e-3" + doAssert formatEng(52731234) == "52.731234e6" + doAssert formatEng(-52731234) == "-52.731234e6" + doAssert formatEng(52731234, 1) == "52.7e6" + doAssert formatEng(-52731234, 1) == "-52.7e6" + doAssert formatEng(52731234, 1, decimalSep=',') == "52,7e6" + doAssert formatEng(-52731234, 1, decimalSep=',') == "-52,7e6" - doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000" - doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235." - doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6" - doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001" - doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in - ["1,0e-11", "1,0e-011"] - # bug #6589 - doAssert formatFloat(123.456, ffScientific, precision = -1) == "1.234560e+02" + doAssert formatEng(4100, siPrefix=true, unit="V") == "4.1 kV" + doAssert formatEng(4.1, siPrefix=true, unit="V", useUnitSpace=true) == "4.1 V" + doAssert formatEng(4.1, siPrefix=true) == "4.1" # Note lack of space + doAssert formatEng(4100, siPrefix=true) == "4.1 k" + doAssert formatEng(4.1, siPrefix=true, unit="", useUnitSpace=true) == "4.1 " # Includes space + doAssert formatEng(4100, siPrefix=true, unit="") == "4.1 k" + doAssert formatEng(4100) == "4.1e3" + doAssert formatEng(4100, unit="V", useUnitSpace=true) == "4.1e3 V" + doAssert formatEng(4100, unit="", useUnitSpace=true) == "4.1e3 " + # Don't use SI prefix as number is too big + doAssert formatEng(3.1e22, siPrefix=true, unit="a", useUnitSpace=true) == "31e21 a" + # Don't use SI prefix as number is too small + doAssert formatEng(3.1e-25, siPrefix=true, unit="A", useUnitSpace=true) == "310e-27 A" - doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c" - doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb" + proc staticTests = + doAssert align("abc", 4) == " abc" + doAssert align("a", 0) == "a" + doAssert align("1232", 6) == " 1232" + doAssert align("1232", 6, '#') == "##1232" - block: # formatSize tests - doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB" - doAssert formatSize((2.234*1024*1024).int) == "2.234MiB" - doAssert formatSize(4096) == "4KiB" - doAssert formatSize(4096, prefix=bpColloquial, includeSpace=true) == "4 kB" - doAssert formatSize(4096, includeSpace=true) == "4 KiB" - doAssert formatSize(5_378_934, prefix=bpColloquial, decimalSep=',') == "5,13MB" + doAssert alignLeft("abc", 4) == "abc " + doAssert alignLeft("a", 0) == "a" + doAssert alignLeft("1232", 6) == "1232 " + doAssert alignLeft("1232", 6, '#') == "1232##" - doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] == - "The cat eats fish." + let + inp = """ this is a long text -- muchlongerthan10chars and here + it goes""" + outp = " this is a\nlong text\n--\nmuchlongerthan10chars\nand here\nit goes" + doAssert wordWrap(inp, 10, false) == outp - doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz " - doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc" + let + longInp = """ThisIsOneVeryLongStringWhichWeWillSplitIntoEightSeparatePartsNow""" + longOutp = "ThisIsOn\neVeryLon\ngStringW\nhichWeWi\nllSplitI\nntoEight\nSeparate\nPartsNow" + doAssert wordWrap(longInp, 8, true) == longOutp - doAssert "-lda-ldz -ld abc".replaceWord("") == "lda-ldz ld abc" - doAssert "oo".replace("", "abc") == "abcoabcoabc" + doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] == + "The cat eats fish." - type MyEnum = enum enA, enB, enC, enuD, enE - doAssert parseEnum[MyEnum]("enu_D") == enuD + doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz " + doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc" - doAssert parseEnum("invalid enum value", enC) == enC + doAssert "-lda-ldz -ld abc".replaceWord("") == "-lda-ldz -ld abc" + doAssert "oo".replace("", "abc") == "abcoabcoabc" - doAssert center("foo", 13) == " foo " - doAssert center("foo", 0) == "foo" - doAssert center("foo", 3, fillChar = 'a') == "foo" - doAssert center("foo", 10, fillChar = '\t') == "\t\t\tfoo\t\t\t\t" + type MyEnum = enum enA, enB, enC, enuD, enE + doAssert parseEnum[MyEnum]("enu_D") == enuD - doAssert count("foofoofoo", "foofoo") == 1 - doAssert count("foofoofoo", "foofoo", overlapping = true) == 2 - doAssert count("foofoofoo", 'f') == 3 - doAssert count("foofoofoobar", {'f','b'}) == 4 + doAssert parseEnum("invalid enum value", enC) == enC - doAssert strip(" foofoofoo ") == "foofoofoo" - doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo" - doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo" - doAssert strip("stripme but don't strip this stripme", - chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) == - " but don't strip this " - doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo" - doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos" + doAssert center("foo", 13) == " foo " + doAssert center("foo", 0) == "foo" + doAssert center("foo", 3, fillChar = 'a') == "foo" + doAssert center("foo", 10, fillChar = '\t') == "\t\t\tfoo\t\t\t\t" - doAssert " foo\n bar".indent(4, "Q") == "QQQQ foo\nQQQQ bar" + doAssert count("foofoofoo", "foofoo") == 1 + doAssert count("foofoofoo", "foofoo", overlapping = true) == 2 + doAssert count("foofoofoo", 'f') == 3 + doAssert count("foofoofoobar", {'f','b'}) == 4 - doAssert "abba".multiReplace(("a", "b"), ("b", "a")) == "baab" - doAssert "Hello World.".multiReplace(("ello", "ELLO"), ("World.", "PEOPLE!")) == "HELLO PEOPLE!" - doAssert "aaaa".multiReplace(("a", "aa"), ("aa", "bb")) == "aaaaaaaa" + doAssert strip(" foofoofoo ") == "foofoofoo" + doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo" + doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo" + doAssert strip("stripme but don't strip this stripme", + chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) == + " but don't strip this " + doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo" + doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos" - doAssert isAlphaAscii('r') - doAssert isAlphaAscii('A') - doAssert(not isAlphaAscii('$')) + doAssert " foo\n bar".indent(4, "Q") == "QQQQ foo\nQQQQ bar" - doAssert isAlphaAscii("Rasp") - doAssert isAlphaAscii("Args") - doAssert(not isAlphaAscii("$Tomato")) + doAssert "abba".multiReplace(("a", "b"), ("b", "a")) == "baab" + doAssert "Hello World.".multiReplace(("ello", "ELLO"), ("World.", "PEOPLE!")) == "HELLO PEOPLE!" + doAssert "aaaa".multiReplace(("a", "aa"), ("aa", "bb")) == "aaaaaaaa" - doAssert isAlphaNumeric('3') - doAssert isAlphaNumeric('R') - doAssert(not isAlphaNumeric('!')) + doAssert isAlphaAscii('r') + doAssert isAlphaAscii('A') + doAssert(not isAlphaAscii('$')) - doAssert isAlphaNumeric("34ABc") - doAssert isAlphaNumeric("Rad") - doAssert isAlphaNumeric("1234") - doAssert(not isAlphaNumeric("@nose")) + doAssert isAlphaAscii("Rasp") + doAssert isAlphaAscii("Args") + doAssert(not isAlphaAscii("$Tomato")) - doAssert isDigit('3') - doAssert(not isDigit('a')) - doAssert(not isDigit('%')) + doAssert isAlphaNumeric('3') + doAssert isAlphaNumeric('R') + doAssert(not isAlphaNumeric('!')) - doAssert isDigit("12533") - doAssert(not isDigit("12.33")) - doAssert(not isDigit("A45b")) + doAssert isAlphaNumeric("34ABc") + doAssert isAlphaNumeric("Rad") + doAssert isAlphaNumeric("1234") + doAssert(not isAlphaNumeric("@nose")) - doAssert isSpaceAscii('\t') - doAssert isSpaceAscii('\l') - doAssert(not isSpaceAscii('A')) + doAssert isDigit('3') + doAssert(not isDigit('a')) + doAssert(not isDigit('%')) - doAssert isSpaceAscii("\t\l \v\r\f") - doAssert isSpaceAscii(" ") - doAssert(not isSpaceAscii("ABc \td")) + doAssert isDigit("12533") + doAssert(not isDigit("12.33")) + doAssert(not isDigit("A45b")) - doAssert(isNilOrWhitespace("")) - doAssert(isNilOrWhitespace(" ")) - doAssert(isNilOrWhitespace("\t\l \v\r\f")) - doAssert(not isNilOrWhitespace("ABc \td")) + doAssert isSpaceAscii('\t') + doAssert isSpaceAscii('\l') + doAssert(not isSpaceAscii('A')) - doAssert isLowerAscii('a') - doAssert isLowerAscii('z') - doAssert(not isLowerAscii('A')) - doAssert(not isLowerAscii('5')) - doAssert(not isLowerAscii('&')) + doAssert isSpaceAscii("\t\l \v\r\f") + doAssert isSpaceAscii(" ") + doAssert(not isSpaceAscii("ABc \td")) - doAssert isLowerAscii("abcd") - doAssert(not isLowerAscii("abCD")) - doAssert(not isLowerAscii("33aa")) + doAssert(isNilOrWhitespace("")) + doAssert(isNilOrWhitespace(" ")) + doAssert(isNilOrWhitespace("\t\l \v\r\f")) + doAssert(not isNilOrWhitespace("ABc \td")) - doAssert isUpperAscii('A') - doAssert(not isUpperAscii('b')) - doAssert(not isUpperAscii('5')) - doAssert(not isUpperAscii('%')) + doAssert isLowerAscii('a') + doAssert isLowerAscii('z') + doAssert(not isLowerAscii('A')) + doAssert(not isLowerAscii('5')) + doAssert(not isLowerAscii('&')) - doAssert isUpperAscii("ABC") - doAssert(not isUpperAscii("AAcc")) - doAssert(not isUpperAscii("A#$")) + doAssert isLowerAscii("abcd") + doAssert(not isLowerAscii("abCD")) + doAssert(not isLowerAscii("33aa")) - doAssert rsplit("foo bar", seps=Whitespace) == @["foo", "bar"] - doAssert rsplit(" foo bar", seps=Whitespace, maxsplit=1) == @[" foo", "bar"] - doAssert rsplit(" foo bar ", seps=Whitespace, maxsplit=1) == @[" foo bar", ""] - doAssert rsplit(":foo:bar", sep=':') == @["", "foo", "bar"] - doAssert rsplit(":foo:bar", sep=':', maxsplit=2) == @["", "foo", "bar"] - doAssert rsplit(":foo:bar", sep=':', maxsplit=3) == @["", "foo", "bar"] - doAssert rsplit("foothebar", sep="the") == @["foo", "bar"] + doAssert isUpperAscii('A') + doAssert(not isUpperAscii('b')) + doAssert(not isUpperAscii('5')) + doAssert(not isUpperAscii('%')) - doAssert(unescape(r"\x013", "", "") == "\x013") + doAssert isUpperAscii("ABC") + doAssert(not isUpperAscii("AAcc")) + doAssert(not isUpperAscii("A#$")) - doAssert join(["foo", "bar", "baz"]) == "foobarbaz" - doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz" - doAssert join([1, 2, 3]) == "123" - doAssert join(@[1, 2, 3], ", ") == "1, 2, 3" + doAssert rsplit("foo bar", seps=Whitespace) == @["foo", "bar"] + doAssert rsplit(" foo bar", seps=Whitespace, maxsplit=1) == @[" foo", "bar"] + doAssert rsplit(" foo bar ", seps=Whitespace, maxsplit=1) == @[" foo bar", ""] + doAssert rsplit(":foo:bar", sep=':') == @["", "foo", "bar"] + doAssert rsplit(":foo:bar", sep=':', maxsplit=2) == @["", "foo", "bar"] + doAssert rsplit(":foo:bar", sep=':', maxsplit=3) == @["", "foo", "bar"] + doAssert rsplit("foothebar", sep="the") == @["foo", "bar"] - doAssert """~~!!foo + doAssert(unescape(r"\x013", "", "") == "\x013") + + doAssert join(["foo", "bar", "baz"]) == "foobarbaz" + doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz" + doAssert join([1, 2, 3]) == "123" + doAssert join(@[1, 2, 3], ", ") == "1, 2, 3" + + doAssert """~~!!foo ~~!!bar ~~!!baz""".unindent(2, "~~!!") == "foo\nbar\nbaz" - doAssert """~~!!foo + doAssert """~~!!foo ~~!!bar ~~!!baz""".unindent(2, "~~!!aa") == "~~!!foo\n~~!!bar\n~~!!baz" - doAssert """~~foo + doAssert """~~foo ~~ bar ~~ baz""".unindent(4, "~") == "foo\n bar\n baz" - doAssert """foo + doAssert """foo bar baz """.unindent(4) == "foo\nbar\nbaz\n" - doAssert """foo + doAssert """foo bar baz """.unindent(2) == "foo\n bar\n baz\n" - doAssert """foo + doAssert """foo bar baz """.unindent(100) == "foo\nbar\nbaz\n" - doAssert """foo + doAssert """foo foo bar """.unindent() == "foo\nfoo\nbar\n" - let s = " this is an example " - let s2 = ":this;is;an:example;;" + let s = " this is an example " + let s2 = ":this;is;an:example;;" - doAssert s.split() == @["", "this", "is", "an", "example", "", ""] - doAssert s2.split(seps={':', ';'}) == @["", "this", "is", "an", "example", "", ""] - doAssert s.split(maxsplit=4) == @["", "this", "is", "an", "example "] - doAssert s.split(' ', maxsplit=1) == @["", "this is an example "] - doAssert s.split(" ", maxsplit=4) == @["", "this", "is", "an", "example "] + doAssert s.split() == @["", "this", "is", "an", "example", "", ""] + doAssert s2.split(seps={':', ';'}) == @["", "this", "is", "an", "example", "", ""] + doAssert s.split(maxsplit=4) == @["", "this", "is", "an", "example "] + doAssert s.split(' ', maxsplit=1) == @["", "this is an example "] + doAssert s.split(" ", maxsplit=4) == @["", "this", "is", "an", "example "] - doAssert s.splitWhitespace() == @["this", "is", "an", "example"] - doAssert s.splitWhitespace(maxsplit=1) == @["this", "is an example "] - doAssert s.splitWhitespace(maxsplit=2) == @["this", "is", "an example "] - doAssert s.splitWhitespace(maxsplit=3) == @["this", "is", "an", "example "] - doAssert s.splitWhitespace(maxsplit=4) == @["this", "is", "an", "example"] + doAssert s.splitWhitespace() == @["this", "is", "an", "example"] + doAssert s.splitWhitespace(maxsplit=1) == @["this", "is an example "] + doAssert s.splitWhitespace(maxsplit=2) == @["this", "is", "an example "] + doAssert s.splitWhitespace(maxsplit=3) == @["this", "is", "an", "example "] + doAssert s.splitWhitespace(maxsplit=4) == @["this", "is", "an", "example"] - block: # formatEng tests - doAssert formatEng(0, 2, trim=false) == "0.00" - doAssert formatEng(0, 2) == "0" - doAssert formatEng(53, 2, trim=false) == "53.00" - doAssert formatEng(0.053, 2, trim=false) == "53.00e-3" - doAssert formatEng(0.053, 4, trim=false) == "53.0000e-3" - doAssert formatEng(0.053, 4, trim=true) == "53e-3" - doAssert formatEng(0.053, 0) == "53e-3" - doAssert formatEng(52731234) == "52.731234e6" - doAssert formatEng(-52731234) == "-52.731234e6" - doAssert formatEng(52731234, 1) == "52.7e6" - doAssert formatEng(-52731234, 1) == "-52.7e6" - doAssert formatEng(52731234, 1, decimalSep=',') == "52,7e6" - doAssert formatEng(-52731234, 1, decimalSep=',') == "-52,7e6" + block: # startsWith / endsWith char tests + var s = "abcdef" + doAssert s.startsWith('a') + doAssert s.startsWith('b') == false + doAssert s.endsWith('f') + doAssert s.endsWith('a') == false + doAssert s.endsWith('\0') == false - doAssert formatEng(4100, siPrefix=true, unit="V") == "4.1 kV" - doAssert formatEng(4.1, siPrefix=true, unit="V", useUnitSpace=true) == "4.1 V" - doAssert formatEng(4.1, siPrefix=true) == "4.1" # Note lack of space - doAssert formatEng(4100, siPrefix=true) == "4.1 k" - doAssert formatEng(4.1, siPrefix=true, unit="", useUnitSpace=true) == "4.1 " # Includes space - doAssert formatEng(4100, siPrefix=true, unit="") == "4.1 k" - doAssert formatEng(4100) == "4.1e3" - doAssert formatEng(4100, unit="V", useUnitSpace=true) == "4.1e3 V" - doAssert formatEng(4100, unit="", useUnitSpace=true) == "4.1e3 " - # Don't use SI prefix as number is too big - doAssert formatEng(3.1e22, siPrefix=true, unit="a", useUnitSpace=true) == "31e21 a" - # Don't use SI prefix as number is too small - doAssert formatEng(3.1e-25, siPrefix=true, unit="A", useUnitSpace=true) == "310e-27 A" + #echo("strutils tests passed") - block: # startsWith / endsWith char tests - var s = "abcdef" - doAssert s.startsWith('a') - doAssert s.startsWith('b') == false - doAssert s.endsWith('f') - doAssert s.endsWith('a') == false - doAssert s.endsWith('\0') == false + nonStaticTests() + staticTests() + static: staticTests() - #echo("strutils tests passed") From 56230071263f9884ed14ab25784834a20dd73c0e Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Fri, 4 May 2018 20:05:05 +0300 Subject: [PATCH 39/47] Fix the compilation of terminal.nim on Windows --- lib/pure/terminal.nim | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index db16c23b3..8b5dcf0c5 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -40,10 +40,7 @@ const fgPrefix = "\x1b[38;2;" bgPrefix = "\x1b[48;2;" ansiResetCode* = "\e[0m" - -when not defined(windows): - const - stylePrefix = "\e[" + stylePrefix = "\e[" when defined(windows): import winlean, os From 6758fbd06e5cd88b620939b60deb5bfa00345efc Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sat, 5 May 2018 17:02:29 +0300 Subject: [PATCH 40/47] Export an 'escapeXml' proc from xmldom The interface is similar to escapeJson --- lib/pure/terminal.nim | 2 +- lib/pure/xmldom.nim | 21 ++++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 8b5dcf0c5..fcca4d5d7 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -621,7 +621,7 @@ proc ansiForegroundColorCode*(color: Color): string = colorsFGCache[color] = result template ansiForegroundColorCode*(color: static[Color]): string = - let rgb = extractRGB(color) + const rgb = extractRGB(color) (static(fmt"{fgPrefix}{rgb.r};{rgb.g};{rgb.b}m")) proc ansiBackgroundColorCode*(color: Color): string = diff --git a/lib/pure/xmldom.nim b/lib/pure/xmldom.nim index c38d36026..8cd47aa39 100644 --- a/lib/pure/xmldom.nim +++ b/lib/pure/xmldom.nim @@ -1069,17 +1069,15 @@ proc splitData*(textNode: PText, offset: int): PText = var newNode: PText = textNode.fOwnerDocument.createTextNode(right) return newNode - # ProcessingInstruction proc target*(pi: PProcessingInstruction): string = ## Returns the Processing Instructions target return pi.fTarget - -# --Other stuff-- -# Writer -proc addEscaped(s: string): string = +proc escapeXml*(s: string; result: var string) = + ## Prepares a string for insertion into a XML document + ## by escaping the XML special characters. result = "" for c in items(s): case c @@ -1089,11 +1087,20 @@ proc addEscaped(s: string): string = of '"': result.add(""") else: result.add(c) +proc escapeXml*(s: string): string = + ## Prepares a string for insertion into a XML document + ## by escaping the XML special characters. + result = newStringOfCap(s.len + s.len shr 4) + escapeXml(s, result) + +# --Other stuff-- +# Writer + proc nodeToXml(n: PNode, indent: int = 0): string = result = spaces(indent) & "<" & n.nodeName if not isNil(n.attributes): for i in items(n.attributes): - result.add(" " & i.name & "=\"" & addEscaped(i.value) & "\"") + result.add(" " & i.name & "=\"" & escapeXml(i.value) & "\"") if isNil(n.childNodes) or n.childNodes.len() == 0: result.add("/>") # No idea why this doesn't need a \n :O @@ -1106,7 +1113,7 @@ proc nodeToXml(n: PNode, indent: int = 0): string = result.add(nodeToXml(i, indent + 2)) of TextNode: result.add(spaces(indent * 2)) - result.add(addEscaped(i.nodeValue)) + result.add(escapeXml(i.nodeValue)) of CDataSectionNode: result.add(spaces(indent * 2)) result.add("") From 7cf87dfac62d68d1d9ef7fbedca05b9950b71ced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Nihlg=C3=A5rd?= Date: Tue, 8 May 2018 12:02:48 +0200 Subject: [PATCH 41/47] VM fix for refs --- compiler/vm.nim | 10 ++++++++-- tests/vm/tref.nim | 12 ++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 tests/vm/tref.nim diff --git a/compiler/vm.nim b/compiler/vm.nim index 6c36a1458..27135d2e7 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -210,8 +210,14 @@ proc putIntoNode(n: var PNode; x: TFullReg) = of rkInt: n.intVal = x.intVal of rkFloat: n.floatVal = x.floatVal of rkNode: - if nfIsRef in x.node.flags: n = x.node - else: n[] = x.node[] + if nfIsRef in x.node.flags: + n = x.node + else: + let destIsRef = nfIsRef in n.flags + n[] = x.node[] + # Ref-ness must be kept for the destination + if destIsRef: + n.flags.incl nfIsRef of rkRegisterAddr: putIntoNode(n, x.regAddr[]) of rkNodeAddr: n[] = x.nodeAddr[][] diff --git a/tests/vm/tref.nim b/tests/vm/tref.nim new file mode 100644 index 000000000..517a67fb0 --- /dev/null +++ b/tests/vm/tref.nim @@ -0,0 +1,12 @@ +static: + var + a: ref string + b: ref string + new a + + a[] = "Hello world" + b = a + + b[5] = 'c' + doAssert a[] == "Hellocworld" + doAssert b[] == "Hellocworld" \ No newline at end of file From 9bde9a1404a979e9a19601a1355f893565d4f218 Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Tue, 8 May 2018 16:50:36 -0500 Subject: [PATCH 42/47] Add nimble dir to path via finish --- tools/finish.nim | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/tools/finish.nim b/tools/finish.nim index b5ef78b65..4f2c72595 100644 --- a/tools/finish.nim +++ b/tools/finish.nim @@ -187,12 +187,14 @@ when defined(windows): proc main() = when defined(windows): - let desiredPath = expandFilename(getCurrentDir() / "bin") + let nimDesiredPath = expandFilename(getCurrentDir() / "bin") + let nimbleDesiredPath = expandFilename(getEnv("USERPROFILE") / ".nimble" / "bin") let p = tryGetUnicodeValue(r"Environment", "Path", HKEY_CURRENT_USER) & ";" & tryGetUnicodeValue( r"System\CurrentControlSet\Control\Session Manager\Environment", "Path", HKEY_LOCAL_MACHINE) - var alreadyInPath = false + var nimAlreadyInPath = false + var nimbleAlreadyInPath = false var mingWchoices: seq[string] = @[] var incompat: seq[string] = @[] for x in p.split(';'): @@ -200,18 +202,29 @@ proc main() = let y = try: expandFilename(if x[0] == '"' and x[^1] == '"': substr(x, 1, x.len-2) else: x) except: "" - if y.cmpIgnoreCase(desiredPath) == 0: alreadyInPath = true - if y.toLowerAscii.contains("mingw"): + if y.cmpIgnoreCase(nimDesiredPath) == 0: + nimAlreadyInPath = true + elif y.cmpIgnoreCase(nimbleDesiredPath) == 0: + nimbleAlreadyInPath = true + elif y.toLowerAscii.contains("mingw"): if dirExists(y): if checkGccArch(y): mingWchoices.add y else: incompat.add y - if alreadyInPath: - echo "bin/nim.exe is already in your PATH [Skipping]" + if nimAlreadyInPath: + echo "bin\\nim.exe is already in your PATH [Skipping]" else: if askBool("nim.exe is not in your PATH environment variable.\n" & "Should it be added permanently? (y/n) "): - addToPathEnv(desiredPath) + addToPathEnv(nimDesiredPath) + + if nimbleAlreadyInPath: + echo nimbleDesiredPath & " is already in your PATH [Skipping]" + else: + if askBool(nimbleDesiredPath & " is not in your PATH environment variable.\n" & + "Should it be added permanently? (y/n) "): + addToPathEnv(nimbleDesiredPath) + if mingWchoices.len == 0: # No mingw in path, so try a few locations: let alternative = tryDirs(incompat, defaultMingwLocations()) From 80f17f94053dbf79e851ac2c90dd6e108c178a61 Mon Sep 17 00:00:00 2001 From: Lolo Iccl Date: Sat, 5 May 2018 05:33:54 +0900 Subject: [PATCH 43/47] Add proc hash for HashSet and for OrderedSet close #7772 --- lib/pure/collections/sets.nim | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 32b6387ad..0019f8e3a 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -120,6 +120,11 @@ iterator items*[A](s: HashSet[A]): A = for h in 0..high(s.data): if isFilled(s.data[h].hcode): yield s.data[h].key +proc hash*[A](x: HashSet[A]): Hash = + ## hashing of HashSet + for item in x: result = result !& hash(item) + result = !$result + const growthFactor = 2 @@ -690,6 +695,11 @@ iterator items*[A](s: OrderedSet[A]): A = forAllOrderedPairs: yield s.data[h].key +proc hash*[A](x: OrderedSet[A]): Hash = + ## hashing of OrderedSet + for item in x: result = result !& hash(item) + result = !$result + iterator pairs*[A](s: OrderedSet[A]): tuple[a: int, b: A] = assert s.isValid, "The set needs to be initialized" forAllOrderedPairs: From ee8313da3ff19d9340285c7177db84e1c62fc108 Mon Sep 17 00:00:00 2001 From: Lolo Iccl Date: Sat, 5 May 2018 06:20:44 +0900 Subject: [PATCH 44/47] Modify previous commit Modify previous commit to use data[h].hcode in proc hash for HashSet and for OrderedSet. --- lib/pure/collections/sets.nim | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 0019f8e3a..900f281e9 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -120,9 +120,11 @@ iterator items*[A](s: HashSet[A]): A = for h in 0..high(s.data): if isFilled(s.data[h].hcode): yield s.data[h].key -proc hash*[A](x: HashSet[A]): Hash = +proc hash*[A](s: HashSet[A]): Hash = ## hashing of HashSet - for item in x: result = result !& hash(item) + assert s.isValid, "The set needs to be initialized." + for h in 0..high(s.data): + result = result !& s.data[h].hcode result = !$result const @@ -695,9 +697,11 @@ iterator items*[A](s: OrderedSet[A]): A = forAllOrderedPairs: yield s.data[h].key -proc hash*[A](x: OrderedSet[A]): Hash = +proc hash*[A](s: OrderedSet[A]): Hash = ## hashing of OrderedSet - for item in x: result = result !& hash(item) + assert s.isValid, "The set needs to be initialized." + forAllOrderedPairs: + result = result !& s.data[h].hcode result = !$result iterator pairs*[A](s: OrderedSet[A]): tuple[a: int, b: A] = From 5c7b66e07a3811b3fa0b8e7bbfe4cf25a6361d3a Mon Sep 17 00:00:00 2001 From: Lolo Iccl Date: Sat, 5 May 2018 08:06:29 +0900 Subject: [PATCH 45/47] Modify previous commit and add tests --- lib/pure/collections/sets.nim | 7 +++-- tests/collections/tsets.nim | 52 +++++++++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 900f281e9..94bdbb860 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -18,7 +18,7 @@ ## that ``=`` performs a copy of the set. import - hashes, math + hashes, math, algorithm {.pragma: myShallow.} when not defined(nimhygiene): @@ -123,8 +123,11 @@ iterator items*[A](s: HashSet[A]): A = proc hash*[A](s: HashSet[A]): Hash = ## hashing of HashSet assert s.isValid, "The set needs to be initialized." + var hcs: seq[Hash] for h in 0..high(s.data): - result = result !& s.data[h].hcode + hcs.add(s.data[h].hcode) + for hc in sorted(hcs, cmp[int]): + result = result !& hc result = !$result const diff --git a/tests/collections/tsets.nim b/tests/collections/tsets.nim index 6139560bd..be624ffe8 100644 --- a/tests/collections/tsets.nim +++ b/tests/collections/tsets.nim @@ -1,4 +1,6 @@ import sets +import hashes +import algorithm block setEquality: var @@ -35,7 +37,7 @@ block setWithSequences: doAssert( not s.contains(@[4, 5, 6]) ) block setClearWorked: - var s = initSet[char]() + var s = initSet[char]() for c in "this is a test": s.incl(c) @@ -68,12 +70,58 @@ block orderedSetClearWorked: for c in "eat at joes": s.incl(c) - r = "" + r = "" for c in items(s): add(r, c) doAssert r == "zeat jos" +block hashForHashedSet: + let + seq1 = "This is the test." + seq2 = "the test is This." + s1 = seq1.toSet() + s2 = seq2.toSet() + var hashSeq: seq[Hash] = @[] + doAssert s1 == s2 + doAssert hash(s1) == hash(s2) + for c in seq1: + if (not (hash(c) in hashSeq)): + hashSeq.add(hash(c)) + doAssert hash(s1) == hash(sorted(hashSeq, cmp[Hash])) +block hashForOrderdSet: + let + str = "This is the test." + rstr = str.reversed + var + s1 = initOrderedSet[char]() + s2 = initOrderedSet[char]() + r = initOrderedSet[char]() + expected: Hash + added: seq[char] = @[] + reversed: Hash + radded: seq[char] = @[] + expected = 0 + for c in str: + if (not (c in added)): + expected = expected !& hash(c) + added.add(c) + s1.incl(c) + s2.incl(c) + expected = !$expected + doAssert hash(s1) == expected + doAssert hash(s1) == hash(s2) + doAssert hash(s1) != hash(r) + + reversed = 0 + for c in rstr: + if (not (c in radded)): + reversed = reversed !& hash(c) + radded.add(c) + r.incl(c) + reversed = !$reversed + doAssert hash(r) == reversed + doAssert hash(s1) != reversed From af591544c59e9b05e539f4583f1143776bb8a9e4 Mon Sep 17 00:00:00 2001 From: Lolo Iccl Date: Tue, 8 May 2018 22:09:37 +0900 Subject: [PATCH 46/47] Modify hash for HashSet to use `xor` to mix hash of items. --- lib/pure/collections/sets.nim | 7 ++----- tests/collections/tsets.nim | 4 ---- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 94bdbb860..59c90bc2b 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -18,7 +18,7 @@ ## that ``=`` performs a copy of the set. import - hashes, math, algorithm + hashes, math {.pragma: myShallow.} when not defined(nimhygiene): @@ -123,11 +123,8 @@ iterator items*[A](s: HashSet[A]): A = proc hash*[A](s: HashSet[A]): Hash = ## hashing of HashSet assert s.isValid, "The set needs to be initialized." - var hcs: seq[Hash] for h in 0..high(s.data): - hcs.add(s.data[h].hcode) - for hc in sorted(hcs, cmp[int]): - result = result !& hc + result = result xor s.data[h].hcode result = !$result const diff --git a/tests/collections/tsets.nim b/tests/collections/tsets.nim index be624ffe8..61e14260a 100644 --- a/tests/collections/tsets.nim +++ b/tests/collections/tsets.nim @@ -85,10 +85,6 @@ block hashForHashedSet: var hashSeq: seq[Hash] = @[] doAssert s1 == s2 doAssert hash(s1) == hash(s2) - for c in seq1: - if (not (hash(c) in hashSeq)): - hashSeq.add(hash(c)) - doAssert hash(s1) == hash(sorted(hashSeq, cmp[Hash])) block hashForOrderdSet: let From 9048bcc54b5fe8d0ae8c24b9cf7454cfa897ce5a Mon Sep 17 00:00:00 2001 From: Mathias Stearn Date: Sat, 28 Apr 2018 18:06:11 -0400 Subject: [PATCH 47/47] Add connectUnix and bindUnix to net docs fixes #7715 --- lib/pure/net.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 06bf12665..fc04ef1af 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -960,7 +960,7 @@ when defined(posix) and not defined(nimdoc): raise newException(ValueError, "socket path too long") copyMem(addr result.sun_path, path.cstring, path.len + 1) -when defined(posix): +when defined(posix) or defined(nimdoc): proc connectUnix*(socket: Socket, path: string) = ## Connects to Unix socket on `path`. ## This only works on Unix-style systems: Mac OS X, BSD and Linux