From 9d000c519a5b21300e4896d9d9a79170ac281387 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 6 Oct 2019 19:38:05 +0200 Subject: [PATCH 01/56] render typeof as typeof --- compiler/renderer.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index cdd0357eeb..a92ce999f1 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -474,7 +474,7 @@ proc lsub(g: TSrcGen; n: PNode): int = len("if_:_") of nkElifExpr: result = lsons(g, n) + len("_elif_:_") of nkElseExpr: result = lsub(g, n.sons[0]) + len("_else:_") # type descriptions - of nkTypeOfExpr: result = (if n.len > 0: lsub(g, n.sons[0]) else: 0)+len("type()") + of nkTypeOfExpr: result = (if n.len > 0: lsub(g, n.sons[0]) else: 0)+len("typeof()") of nkRefTy: result = (if n.len > 0: lsub(g, n.sons[0])+1 else: 0) + len("ref") of nkPtrTy: result = (if n.len > 0: lsub(g, n.sons[0])+1 else: 0) + len("ptr") of nkVarTy: result = (if n.len > 0: lsub(g, n.sons[0])+1 else: 0) + len("var") @@ -1195,7 +1195,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = putWithSpace(g, tkColon, ":") gsub(g, n, 0) of nkTypeOfExpr: - put(g, tkType, "type") + put(g, tkType, "typeof") put(g, tkParLe, "(") if n.len > 0: gsub(g, n.sons[0]) put(g, tkParRi, ")") From a60f18d0255f400cb111eacbad79c81e06f6363e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 6 Oct 2019 19:38:21 +0200 Subject: [PATCH 02/56] fixes #12323 [backport] --- compiler/lambdalifting.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index d783e05543..33eacefbd6 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -477,7 +477,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = w = up of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkTemplateDef, nkTypeSection, nkProcDef, nkMethodDef, - nkConverterDef, nkMacroDef, nkFuncDef, nkCommentStmt: + nkConverterDef, nkMacroDef, nkFuncDef, nkCommentStmt, nkTypeOfExpr: discard of nkLambdaKinds, nkIteratorDef: if n.typ != nil: @@ -760,6 +760,8 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass; n[0].sons[1] = liftCapturedVars(n[0].sons[1], owner, d, c) else: n.sons[0] = liftCapturedVars(n[0], owner, d, c) + of nkTypeOfExpr: + result = n else: if owner.isIterator: if nfLL in n.flags: From f9d95fd6a71f949db5994369da96f1c42d40d2a7 Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Mon, 7 Oct 2019 16:26:27 +0100 Subject: [PATCH 03/56] Refactor closeEmitter to make it more modular (#12365) --- compiler/layouter.nim | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/compiler/layouter.nim b/compiler/layouter.nim index a8e31ae69b..78f6fcfa0c 100644 --- a/compiler/layouter.nim +++ b/compiler/layouter.nim @@ -160,13 +160,11 @@ proc guidingInd(em: Emitter; pos: int): int = inc i result = -1 -proc closeEmitter*(em: var Emitter) = +proc renderTokens*(em: var Emitter): string = + ## Render Emitter tokens to a string of code template defaultCase() = content.add em.tokens[i] inc lineLen, em.tokens[i].len - - let outFile = em.config.absOutFile - var content = newStringOfCap(16_000) var maxLhs = 0 var lineLen = 0 @@ -243,6 +241,11 @@ proc closeEmitter*(em: var Emitter) = defaultCase() inc i + return content + +proc writeOut*(em: Emitter, content: string) = + ## Write to disk + let outFile = em.config.absOutFile if fileExists(outFile) and readFile(outFile.string) == content: discard "do nothing, see #9499" return @@ -253,6 +256,11 @@ proc closeEmitter*(em: var Emitter) = f.llStreamWrite content llStreamClose(f) +proc closeEmitter*(em: var Emitter) = + ## Renders emitter tokens and write to a file + let content = renderTokens(em) + em.writeOut(content) + proc wr(em: var Emitter; x: string; lt: LayoutToken) = em.tokens.add x em.kinds.add lt From 509f53b782273a2ee5e130a7f5e9c57f079cc93e Mon Sep 17 00:00:00 2001 From: Tomohiro Date: Tue, 8 Oct 2019 02:57:16 +0900 Subject: [PATCH 04/56] On windows, os.relativePath returns path as is when roots are different (#12329) * On windows, os.relativePath returns path as is when roots are different * Implement os.sameRoot without windows API * Fix compile error when compiling lib/nimhcr.nim * Fix compile error when compiling lib/nimhcr.nim on Windows --- lib/pure/os.nim | 119 +++++++++++++++++++++++++++++++++---------- tests/stdlib/tos.nim | 15 ++++++ 2 files changed, 106 insertions(+), 28 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 03173708b6..4e7e37698a 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -232,11 +232,92 @@ proc splitPath*(path: string): tuple[head, tail: string] {. result.head = "" result.tail = path +proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1", raises: [].} = + ## Checks whether a given `path` is absolute. + ## + ## On Windows, network paths are considered absolute too. + runnableExamples: + assert not "".isAbsolute + assert not ".".isAbsolute + when defined(posix): + assert "/".isAbsolute + assert not "a/".isAbsolute + assert "/a/".isAbsolute + + if len(path) == 0: return false + + when doslikeFileSystem: + var len = len(path) + result = (path[0] in {'/', '\\'}) or + (len > 1 and path[0] in {'a'..'z', 'A'..'Z'} and path[1] == ':') + elif defined(macos): + # according to https://perldoc.perl.org/File/Spec/Mac.html `:a` is a relative path + result = path[0] != ':' + elif defined(RISCOS): + result = path[0] == '$' + elif defined(posix): + result = path[0] == '/' + when FileSystemCaseSensitive: template `!=?`(a, b: char): bool = a != b else: template `!=?`(a, b: char): bool = toLowerAscii(a) != toLowerAscii(b) +when doslikeFileSystem: + proc isAbsFromCurrentDrive(path: string): bool {.noSideEffect, raises: []} = + ## An absolute path from the root of the current drive (e.g. "\foo") + path.len > 0 and + (path[0] == AltSep or + (path[0] == DirSep and + (path.len == 1 or path[1] notin {DirSep, AltSep, ':'}))) + + proc isUNCPrefix(path: string): bool {.noSideEffect, raises: []} = + path[0] == DirSep and path[1] == DirSep + + proc sameRoot(path1, path2: string): bool {.noSideEffect, raises: []} = + ## Return true if path1 and path2 have a same root. + ## + ## Detail of windows path formats: + ## https://docs.microsoft.com/en-us/dotnet/standard/io/file-path-formats + + assert(isAbsolute(path1)) + assert(isAbsolute(path2)) + + let + len1 = path1.len + len2 = path2.len + assert(len1 != 0 and len2 != 0) + + if isAbsFromCurrentDrive(path1) and isAbsFromCurrentDrive(path2): + return true + elif len1 == 1 or len2 == 1: + return false + else: + if path1[1] == ':' and path2[1] == ':': + return path1[0].toLowerAscii() == path2[0].toLowerAscii() + else: + var + p1, p2: PathIter + pp1 = next(p1, path1) + pp2 = next(p2, path2) + if pp1[1] - pp1[0] == 1 and pp2[1] - pp2[0] == 1 and + isUNCPrefix(path1) and isUNCPrefix(path2): + #UNC + var h = 0 + while p1.hasNext(path1) and p2.hasNext(path2) and h < 2: + pp1 = next(p1, path1) + pp2 = next(p2, path2) + let diff = pp1[1] - pp1[0] + if diff != pp2[1] - pp2[0]: + return false + for i in 0..diff: + if path1[i + pp1[0]] !=? path2[i + pp2[0]]: + return false + inc h + return h == 2 + else: + return false + proc relativePath*(path, base: string; sep = DirSep): string {. noSideEffect, rtl, extern: "nos$1", raises: [].} = ## Converts `path` to a path relative to `base`. @@ -245,6 +326,10 @@ proc relativePath*(path, base: string; sep = DirSep): string {. ## this can be useful to ensure the relative path only contains `'/'` ## so that it can be used for URL constructions. ## + ## On windows, if a root of `path` and a root of `base` are different, + ## returns `path` as is because it is impossible to make a relative path. + ## That means an absolute path can be returned. + ## ## See also: ## * `splitPath proc <#splitPath,string>`_ ## * `parentDir proc <#parentDir,string>`_ @@ -256,9 +341,13 @@ proc relativePath*(path, base: string; sep = DirSep): string {. assert relativePath("/Users/me/bar/z.nim", "/Users/me", '/') == "bar/z.nim" assert relativePath("", "/users/moo", '/') == "" - # Todo: If on Windows, path and base do not agree on the drive letter, - # return `path` as is. if path.len == 0: return "" + + when doslikeFileSystem: + if isAbsolute(path) and isAbsolute(base): + if not sameRoot(path, base): + return path + var f, b: PathIter var ff = (0, -1) var bb = (0, -1) # (int, int) @@ -645,32 +734,6 @@ proc cmpPaths*(pathA, pathB: string): int {. else: result = cmpIgnoreCase(a, b) -proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1".} = - ## Checks whether a given `path` is absolute. - ## - ## On Windows, network paths are considered absolute too. - runnableExamples: - assert not "".isAbsolute - assert not ".".isAbsolute - when defined(posix): - assert "/".isAbsolute - assert not "a/".isAbsolute - assert "/a/".isAbsolute - - if len(path) == 0: return false - - when doslikeFileSystem: - var len = len(path) - result = (path[0] in {'/', '\\'}) or - (len > 1 and path[0] in {'a'..'z', 'A'..'Z'} and path[1] == ':') - elif defined(macos): - # according to https://perldoc.perl.org/File/Spec/Mac.html `:a` is a relative path - result = path[0] != ':' - elif defined(RISCOS): - result = path[0] == '$' - elif defined(posix): - result = path[0] == '/' - proc unixToNativePath*(path: string, drive=""): string {. noSideEffect, rtl, extern: "nos$1".} = ## Converts an UNIX-like path to a native one. diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index ab0cce8de1..35ea348419 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -334,6 +334,21 @@ block ospaths: doAssert relativePath("/foo", "/fOO", '/') == (when FileSystemCaseSensitive: "../foo" else: "") doAssert relativePath("/foO", "/foo", '/') == (when FileSystemCaseSensitive: "../foO" else: "") + when doslikeFileSystem: + doAssert relativePath(r"c:\foo.nim", r"C:\") == r"foo.nim" + doAssert relativePath(r"c:\foo\bar\baz.nim", r"c:\foo") == r"bar\baz.nim" + doAssert relativePath(r"c:\foo\bar\baz.nim", r"d:\foo") == r"c:\foo\bar\baz.nim" + doAssert relativePath(r"\foo\baz.nim", r"\foo") == r"baz.nim" + doAssert relativePath(r"\foo\bar\baz.nim", r"\bar") == r"..\foo\bar\baz.nim" + doAssert relativePath(r"\\foo\bar\baz.nim", r"\\foo\bar") == r"baz.nim" + doAssert relativePath(r"\\foo\bar\baz.nim", r"\\foO\bar") == r"baz.nim" + doAssert relativePath(r"\\foo\bar\baz.nim", r"\\bar\bar") == r"\\foo\bar\baz.nim" + doAssert relativePath(r"\\foo\bar\baz.nim", r"\\foo\car") == r"\\foo\bar\baz.nim" + doAssert relativePath(r"\\foo\bar\baz.nim", r"\\goo\bar") == r"\\foo\bar\baz.nim" + doAssert relativePath(r"\\foo\bar\baz.nim", r"c:\") == r"\\foo\bar\baz.nim" + doAssert relativePath(r"\\foo\bar\baz.nim", r"\foo") == r"\\foo\bar\baz.nim" + doAssert relativePath(r"c:\foo.nim", r"\foo") == r"c:\foo.nim" + doAssert joinPath("usr", "") == unixToNativePath"usr/" doAssert joinPath("", "lib") == "lib" doAssert joinPath("", "/lib") == unixToNativePath"/lib" From 0355c64b92ad388c1dade93415630df16256500b Mon Sep 17 00:00:00 2001 From: cooldome Date: Tue, 8 Oct 2019 07:10:55 +0100 Subject: [PATCH 05/56] External file compilation improvement (#12380) --- compiler/extccomp.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 4c531e8945..c06ade3a54 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -662,6 +662,10 @@ proc addExternalFileToCompile*(conf: ConfigRef; c: var Cfile) = if optForceFullMake notin conf.globalOptions and fileExists(c.obj) and not externalFileChanged(conf, c): c.flags.incl CfileFlag.Cached + else: + # make sure Nim keeps recompiling the external file on reruns + # if compilation is not successful + discard tryRemoveFile(c.obj.string) conf.toCompile.add(c) proc addExternalFileToCompile*(conf: ConfigRef; filename: AbsoluteFile) = From e9fa4c9b9c8e2926449399a69a02676936bb842c Mon Sep 17 00:00:00 2001 From: alaviss Date: Tue, 8 Oct 2019 06:11:18 +0000 Subject: [PATCH 06/56] nimsuggest: fix tcp socket leak (#12377) [backport] A new socket is created for each iteration and leak immediately thanks to the accept() call replacing the created socket with the client socket. This commit fixes that. --- nimsuggest/nimsuggest.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index af87c9e7fa..b61dfe797e 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -319,8 +319,8 @@ proc replTcp(x: ThreadParams) {.thread.} = server.bindAddr(x.port, x.address) server.listen() var inp = "".TaintedString + var stdoutSocket: Socket while true: - var stdoutSocket = newSocket() accept(server, stdoutSocket) stdoutSocket.readLine(inp) From 89c37fada7a569a3e3d149bbc34394fb1fb34cb1 Mon Sep 17 00:00:00 2001 From: pietroppeter Date: Tue, 8 Oct 2019 09:08:38 +0200 Subject: [PATCH 07/56] [doc/tut1] removed discard discussion in comments (#12352) --- doc/tut1.rst | 9 --------- 1 file changed, 9 deletions(-) diff --git a/doc/tut1.rst b/doc/tut1.rst index ff53d3f37c..fc87fa6639 100644 --- a/doc/tut1.rst +++ b/doc/tut1.rst @@ -142,15 +142,6 @@ comments can also be nested. ]# ]# -You can also use the `discard statement <#procedures-discard-statement>`_ together with *long string -literals* to create block comments: - -.. code-block:: nim - :test: "nim c $1" - discard """ You can have any Nim code text commented - out inside this with no indentation restrictions. - yes("May I ask a pointless question?") """ - Numbers ------- From dbcffcfccb39a35f2f8e2447a22776e5e761ce72 Mon Sep 17 00:00:00 2001 From: treeform Date: Tue, 8 Oct 2019 02:00:37 -0700 Subject: [PATCH 08/56] Easier build instructions for windows - just run `build_all.bat`. (#12276) * Easier build instructions for windows. * title letter * Update build_all.bat to be like build_all.sh --- build_all.bat | 16 ++++++++++++++++ readme.md | 27 +++++++++------------------ 2 files changed, 25 insertions(+), 18 deletions(-) create mode 100644 build_all.bat diff --git a/build_all.bat b/build_all.bat new file mode 100644 index 0000000000..59df15594e --- /dev/null +++ b/build_all.bat @@ -0,0 +1,16 @@ +@echo off +rem build development version of the compiler; can be rerun safely +if not exist csources ( + git clone --depth 1 https://github.com/nim-lang/csources.git +) +if not exist bin\nim.exe ( + cd csources + if PROCESSOR_ARCHITECTURE == AMD64 ( + SET ARCH=64 + ) + CALL build.bat + cd .. +) +bin\nim.exe c --skipUserCfg --skipParentCfg koch +koch.exe boot -d:release +koch.exe tools \ No newline at end of file diff --git a/readme.md b/readme.md index f6122c1e8a..f78da5b146 100644 --- a/readme.md +++ b/readme.md @@ -60,29 +60,20 @@ the installation instructions on the website to do so: https://nim-lang.org/inst For package maintainers: see [packaging guidelines](https://nim-lang.github.io/Nim/packaging.html). + +First get Nim from github: + ``` -# step 1: git clone https://github.com/nim-lang/Nim.git cd Nim - -# step 2 (posix) clones `csources.git`, bootstraps Nim compiler and compiles tools -sh build_all.sh - -# step 2 (windows) -git clone --depth 1 https://github.com/nim-lang/csources.git - -cd csources -# requires `gcc` in your PATH, see also https://nim-lang.org/install_windows.html -build.bat # x86 Windows -build64.bat # x86_64 Windows -cd .. - -bin\nim c koch -koch boot -d:release -koch tools # Compile Nimble and other tools -# end of step 2 (windows) ``` +Next run the appropriate build shell script for your platform: + +* `build_all.sh` (Linux, Mac) +* `build_all.bat` (Windows) + + Finally, once you have finished the build steps (on Windows, Mac or Linux) you should add the ``bin`` directory to your PATH. From 7ef4bffa797623c608c15329717f0a9ee06a5d38 Mon Sep 17 00:00:00 2001 From: Ridho Pratama Date: Tue, 8 Oct 2019 16:12:24 +0700 Subject: [PATCH 09/56] renderer letAux fix only for octal literal (#12343) * renderer letAux fix only for octal literal * Handle when it's octal -1 for i64 * Added testcases --- compiler/renderer.nim | 13 +++--- nimdoc/testproject/expected/testproject.html | 47 ++++++++++++++++++++ nimdoc/testproject/expected/theindex.html | 16 +++++++ nimdoc/testproject/testproject.nim | 7 ++- 4 files changed, 77 insertions(+), 6 deletions(-) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index a92ce999f1..54090d844a 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -314,6 +314,7 @@ proc litAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string = while result != nil and result.kind in {tyGenericInst, tyRange, tyVar, tyLent, tyDistinct, tyOrdinal, tyAlias, tySink}: result = lastSon(result) + let typ = n.typ.skip if typ != nil and typ.kind in {tyBool, tyEnum}: if sfPure in typ.sym.flags: @@ -324,11 +325,13 @@ proc litAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string = if e.sym.position == x: result &= e.sym.name.s return - - let y = x and ((1 shl (size*8)) - 1) - if nfBase2 in n.flags: result = "0b" & toBin(y, size * 8) - elif nfBase8 in n.flags: result = "0o" & toOct(y, size * 3) - elif nfBase16 in n.flags: result = "0x" & toHex(y, size * 2) + + if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8) + elif nfBase8 in n.flags: + var y = if size < sizeof(BiggestInt): x and ((1 shl (size*8)) - 1) + else: x + result = "0o" & toOct(y, size * 3) + elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2) else: result = $x proc ulitAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string = diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 273defbbfb..8c9082d7a3 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -849,6 +849,20 @@ function main() { +
  • + Consts + +
  • Procs
      @@ -938,6 +952,39 @@ The enum B. + + + +
      +

      Consts

      +
      + +
      C_A = 0x7FF0000000000000'f64
      +
      + + + +
      + +
      C_B = 0o377'i8
      +
      + + + +
      + +
      C_C = 0o277'i8
      +
      + + + +
      + +
      C_D = 0o177777'i16
      +
      + + +
      diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index f97ea54b92..5b7cefced3 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -840,6 +840,22 @@ function main() {
    • testproject: buzz[T](a, b: T): T
    +
    C_A:
    +
    C_B:
    +
    C_C:
    +
    C_D:
    enumValueA:
    • SomeType.enumValueA
    • diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim index c3ab6a153d..d1fcf58cd8 100644 --- a/nimdoc/testproject/testproject.nim +++ b/nimdoc/testproject/testproject.nim @@ -9,6 +9,11 @@ runnableExamples: # bug #11078 for x in "xx": discard +const + C_A* = 0x7FF0000000000000'f64 + C_B* = 0o377'i8 + C_C* = 0o277'i8 + C_D* = 0o177777'i16 template foo*(a, b: SomeType) = ## This does nothing @@ -31,7 +36,7 @@ import std/macros macro bar*(): untyped = result = newStmtList() -var aVariable*: array[1,int] +var aVariable*: array[1, int] aEnum() bEnum() From 7c23522b2953de8c71fcf21d998493728ac4f393 Mon Sep 17 00:00:00 2001 From: Ray Imber Date: Tue, 8 Oct 2019 02:24:06 -0700 Subject: [PATCH 10/56] Documentation improvements around the db interface (#12362) Added more details about the limits and reasoning behind the API. Came about from this discussion on IRC: https://irclogs.nim-lang.org/04-10-2019.html#16:58:04 --- lib/impure/db_sqlite.nim | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim index 70538b7d67..f182ae65a0 100644 --- a/lib/impure/db_sqlite.nim +++ b/lib/impure/db_sqlite.nim @@ -94,6 +94,18 @@ ## ## db.close() ## +## +## Note +## ==== +## This module does not implement any ORM features such as mapping the types from the schema. +## Instead, a ``seq[string]`` is returned for each row. +## +## The reasoning is as follows: +## 1. it's close to what many DBs offer natively (char**) +## 2. it hides the number of types that the DB supports +## (int? int64? decimal up to 10 places? geo coords?) +## 3. it's convenient when all you do is to forward the data to somewhere else (echo, log, put the data into a new query) +## ## See also ## ======== ## From edb24b7ce0882faaaec406f20c70723ac653ca2e Mon Sep 17 00:00:00 2001 From: alaviss Date: Tue, 8 Oct 2019 12:14:18 +0000 Subject: [PATCH 11/56] nimsuggest: fix tcp socket leak for epc backend (#12384) [backport] Same as e9fa4c9b9c8e2926449399a69a02676936bb842c, but for the epc backend which is used by emacs and vscode plugin. Since the EPC backend only deal with one connection per nimsuggest instance, only one socket is leaked, thus not as servere as with the tcp backend. --- nimsuggest/nimsuggest.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index b61dfe797e..aa45a64e9a 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -353,7 +353,7 @@ proc replEpc(x: ThreadParams) {.thread.} = echo port stdout.flushFile() - var client = newSocket() + var client: Socket # Wait for connection accept(server, client) while true: From 00c31e87660d9db813871f5aa23661bf6b9bbdcb Mon Sep 17 00:00:00 2001 From: Clyybber Date: Tue, 8 Oct 2019 14:15:47 +0200 Subject: [PATCH 12/56] Fixes #12187 (#12321) * Fixes #12187 * Point to fork of compactdict Since the original repo is now archived / read-only --- lib/pure/concurrency/cpuinfo.nim | 2 +- lib/pure/memfiles.nim | 2 +- lib/pure/strutils.nim | 2 +- lib/system.nim | 4 ++-- lib/system/ansi_c.nim | 18 +++++++++++++++++- lib/system/io.nim | 14 +++++++++++--- lib/system/memory.nim | 6 +++--- lib/system/osalloc.nim | 8 ++++---- lib/wrappers/openssl.nim | 4 ++-- testament/important_packages.nim | 3 +-- tests/manyloc/keineschweine/lib/estreams.nim | 2 +- 11 files changed, 44 insertions(+), 21 deletions(-) diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim index 415b9a7872..5a72459a30 100644 --- a/lib/pure/concurrency/cpuinfo.nim +++ b/lib/pure/concurrency/cpuinfo.nim @@ -79,7 +79,7 @@ proc countProcessors*(): int {.rtl, extern: "ncpi$1".} = len: csize mib[0] = CTL_HW mib[1] = HW_AVAILCPU - len = sizeof(numCPU) + len = csize sizeof(numCPU) discard sysctl(addr(mib), 2, addr(numCPU), len, nil, 0) if numCPU < 1: mib[1] = HW_NCPU diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim index 411df14564..7e0478877f 100644 --- a/lib/pure/memfiles.nim +++ b/lib/pure/memfiles.nim @@ -416,7 +416,7 @@ iterator memSlices*(mfile: MemFile, delim = '\l', eat = '\r'): MemSlice {.inline ms.data = mfile.mem var remaining = mfile.size while remaining > 0: - ending = c_memchr(ms.data, delim, remaining) + ending = c_memchr(ms.data, delim, csize remaining) if ending == nil: # unterminated final slice ms.size = remaining # Weird case..check eat? yield ms diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 69cb1efd58..fd5dcf14cc 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1872,7 +1872,7 @@ proc find*(s: string, sub: char, start: Natural = 0, last = 0): int {.noSideEffe when hasCStringBuiltin: let L = last-start+1 if L > 0: - let found = c_memchr(s[start].unsafeAddr, sub, L) + let found = c_memchr(s[start].unsafeAddr, sub, csize L) if not found.isNil: return cast[ByteAddress](found) -% cast[ByteAddress](s.cstring) else: diff --git a/lib/system.nim b/lib/system.nim index 0edc869c2f..9158b61536 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2233,7 +2233,7 @@ type # these work for most platforms: ## This is the same as the type ``short`` in *C*. cint* {.importc: "int", nodecl.} = int32 ## This is the same as the type ``int`` in *C*. - csize* {.importc: "size_t", nodecl.} = int + csize* {.importc: "size_t", nodecl.} = uint ## This is the same as the type ``size_t`` in *C*. clonglong* {.importc: "long long", nodecl.} = int64 ## This is the same as the type ``long long`` in *C*. @@ -3597,7 +3597,7 @@ when not defined(JS): #and not defined(nimscript): when declared(memTrackerOp): memTrackerOp("copyMem", dest, size) proc moveMem(dest, source: pointer, size: Natural) = - c_memmove(dest, source, size) + c_memmove(dest, source, csize size) when declared(memTrackerOp): memTrackerOp("moveMem", dest, size) proc equalMem(a, b: pointer, size: Natural): bool = diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index 16e7a14d60..89058ce4f2 100644 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -17,14 +17,24 @@ when not defined(nimHasHotCodeReloading): proc c_memchr*(s: pointer, c: cint, n: csize): pointer {. importc: "memchr", header: "".} +proc c_memchr*(s: pointer, c: cint, n: int): pointer {. + importc: "memchr", header: "", deprecated: "csize is now uint".} proc c_memcmp*(a, b: pointer, size: csize): cint {. importc: "memcmp", header: "", noSideEffect.} +proc c_memcmp*(a, b: pointer, size: int): cint {. + importc: "memcmp", header: "", noSideEffect, deprecated: "csize is now uint".} proc c_memcpy*(a, b: pointer, size: csize): pointer {. importc: "memcpy", header: "", discardable.} +proc c_memcpy*(a, b: pointer, size: int): pointer {. + importc: "memcpy", header: "", discardable, deprecated: "csize is now uint".} proc c_memmove*(a, b: pointer, size: csize): pointer {. importc: "memmove", header: "",discardable.} +proc c_memmove*(a, b: pointer, size: int): pointer {. + importc: "memmove", header: "",discardable, deprecated: "csize is now uint".} proc c_memset*(p: pointer, value: cint, size: csize): pointer {. importc: "memset", header: "", discardable.} +proc c_memset*(p: pointer, value: cint, size: int): pointer {. + importc: "memset", header: "", discardable, deprecated: "csize is now uint".} proc c_strcmp*(a, b: cstring): cint {. importc: "strcmp", header: "", noSideEffect.} proc c_strlen*(a: cstring): csize {. @@ -134,16 +144,22 @@ proc c_sprintf*(buf, frmt: cstring): cint {. proc c_malloc*(size: csize): pointer {. importc: "malloc", header: "".} +proc c_malloc*(size: int): pointer {. + importc: "malloc", header: "", deprecated: "csize is now uint".} proc c_free*(p: pointer) {. importc: "free", header: "".} proc c_realloc*(p: pointer, newsize: csize): pointer {. importc: "realloc", header: "".} +proc c_realloc*(p: pointer, newsize: int): pointer {. + importc: "realloc", header: "", deprecated: "csize is now uint".} proc c_fwrite*(buf: pointer, size, n: csize, f: CFilePtr): cint {. importc: "fwrite", header: "".} +proc c_fwrite*(buf: pointer, size, n: int, f: CFilePtr): cint {. + importc: "fwrite", header: "", deprecated: "csize is now uint".} proc rawWrite*(f: CFilePtr, s: cstring) {.compilerproc, nonReloadable, inline.} = # we cannot throw an exception here! - discard c_fwrite(s, 1, s.len, f) + discard c_fwrite(s, 1, csize s.len, f) {.pop.} diff --git a/lib/system/io.nim b/lib/system/io.nim index 7ba36a30d3..46863064be 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -85,10 +85,14 @@ proc c_feof(f: File): cint {. when not declared(c_fwrite): proc c_fwrite(buf: pointer, size, n: csize, f: File): cint {. importc: "fwrite", header: "".} + proc c_fwrite(buf: pointer, size, n: int, f: File): cint {. + importc: "fwrite", header: "", deprecated: "csize is now uint".} # C routine that is used here: proc c_fread(buf: pointer, size, n: csize, f: File): csize {. importc: "fread", header: "", tags: [ReadIOEffect].} +proc c_fread(buf: pointer, size, n: int, f: File): int {. + importc: "fread", header: "", tags: [ReadIOEffect], deprecated: "csize is now uint".} when defined(windows): when not defined(amd64): proc c_fseek(f: File, offset: int64, whence: cint): cint {. @@ -109,6 +113,8 @@ proc c_ferror(f: File): cint {. importc: "ferror", header: "", tags: [].} proc c_setvbuf(f: File, buf: pointer, mode: cint, size: csize): cint {. importc: "setvbuf", header: "", tags: [].} +proc c_setvbuf(f: File, buf: pointer, mode: cint, size: int): cint {. + importc: "setvbuf", header: "", tags: [], deprecated: "csize is now uint".} proc c_fprintf(f: File, frmt: cstring): cint {. importc: "fprintf", header: "", varargs, discardable.} @@ -151,7 +157,7 @@ proc readBuffer*(f: File, buffer: pointer, len: Natural): int {. ## reads `len` bytes into the buffer pointed to by `buffer`. Returns ## the actual number of bytes that have been read which may be less than ## `len` (if not as many bytes are remaining), but not greater. - result = c_fread(buffer, 1, len, f) + result = int c_fread(buffer, 1, csize len, f) if result != len: checkErr(f) proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: Natural): int {. @@ -183,7 +189,7 @@ proc writeBuffer*(f: File, buffer: pointer, len: Natural): int {. ## writes the bytes of buffer pointed to by the parameter `buffer` to the ## file `f`. Returns the number of actual written bytes, which may be less ## than `len` in case of an error. - result = c_fwrite(buffer, 1, len, f) + result = c_fwrite(buffer, 1, csize len, f) checkErr(f) proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: Natural): int {. @@ -292,6 +298,8 @@ proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], ## ``false`` is returned `line` contains no new data. proc c_memchr(s: pointer, c: cint, n: csize): pointer {. importc: "memchr", header: "".} + proc c_memchr(s: pointer, c: cint, n: int): pointer {. + importc: "memchr", header: "", deprecated: "csize is now uint".} var pos = 0 @@ -306,7 +314,7 @@ proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], var fgetsSuccess = c_fgets(addr line.string[pos], sp.cint, f) != nil if not fgetsSuccess: checkErr(f) - let m = c_memchr(addr line.string[pos], '\L'.ord, sp) + let m = c_memchr(addr line.string[pos], '\L'.ord, csize sp) if m != nil: # \l found: Could be our own or the one by fgets, in any case, we're done var last = cast[ByteAddress](m) - cast[ByteAddress](addr line.string[0]) diff --git a/lib/system/memory.nim b/lib/system/memory.nim index 13bddf211e..53c9b1c3bd 100644 --- a/lib/system/memory.nim +++ b/lib/system/memory.nim @@ -10,7 +10,7 @@ when useLibC: proc nimCopyMem*(dest, source: pointer, size: Natural) {.nonReloadable, compilerproc, inline.} = when useLibC: - c_memcpy(dest, source, size) + c_memcpy(dest, source, csize size) else: let d = cast[ptr UncheckedArray[byte]](dest) let s = cast[ptr UncheckedArray[byte]](source) @@ -21,7 +21,7 @@ proc nimCopyMem*(dest, source: pointer, size: Natural) {.nonReloadable, compiler proc nimSetMem*(a: pointer, v: cint, size: Natural) {.nonReloadable, inline.} = when useLibC: - c_memset(a, v, size) + c_memset(a, v, csize size) else: let a = cast[ptr UncheckedArray[byte]](a) var i = 0 @@ -35,7 +35,7 @@ proc nimZeroMem*(p: pointer, size: Natural) {.compilerproc, nonReloadable, inlin proc nimCmpMem*(a, b: pointer, size: Natural): cint {.compilerproc, nonReloadable, inline.} = when useLibC: - c_memcmp(a, b, size) + c_memcmp(a, b, csize size) else: let a = cast[ptr UncheckedArray[byte]](a) let b = cast[ptr UncheckedArray[byte]](b) diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim index 06e89f1305..e29f997d23 100644 --- a/lib/system/osalloc.nim +++ b/lib/system/osalloc.nim @@ -153,7 +153,7 @@ elif defined(nintendoswitch): # size, as well as space to store our structure let realSize = alignSize(size + sizeof(NSwitchBlock)) - let heap = memalign(PageSize, realSize) + let heap = memalign(PageSize, realSize.csize) if heap.isNil: outOfMemoryStmt @@ -221,18 +221,18 @@ elif defined(posix): proc munmap(adr: pointer, len: csize): cint {.header: "".} proc osAllocPages(size: int): pointer {.inline.} = - result = mmap(nil, size, PROT_READ or PROT_WRITE, + result = mmap(nil, csize size, PROT_READ or PROT_WRITE, MAP_PRIVATE or MAP_ANONYMOUS, -1, 0) if result == nil or result == cast[pointer](-1): raiseOutOfMem() proc osTryAllocPages(size: int): pointer {.inline.} = - result = mmap(nil, size, PROT_READ or PROT_WRITE, + result = mmap(nil, csize size, PROT_READ or PROT_WRITE, MAP_PRIVATE or MAP_ANONYMOUS, -1, 0) if result == cast[pointer](-1): result = nil proc osDeallocPages(p: pointer, size: int) {.inline.} = - when reallyOsDealloc: discard munmap(p, size) + when reallyOsDealloc: discard munmap(p, csize size) elif defined(windows): const diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 482062617b..46c9d7bd8d 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -712,7 +712,7 @@ proc md5_File*(file: string): string {.raises: [IOError,Exception].} = discard md5_Init(ctx) while(let bytes = f.readChars(buf, 0, sz); bytes > 0): - discard md5_Update(ctx, buf[0].addr, bytes) + discard md5_Update(ctx, buf[0].addr, csize bytes) discard md5_Final(buf[0].addr, ctx) f.close @@ -731,7 +731,7 @@ proc md5_Str*(str: string): string = var i = 0 while i < str.len: let L = min(str.len - i, 512) - discard md5_Update(ctx, input[i].addr, L) + discard md5_Update(ctx, input[i].addr, csize L) i += L discard md5_Final(addr res, ctx) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 6fd135fd19..dfa448c955 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -20,9 +20,8 @@ pkg "chroma" pkg "chronicles", "nim c -o:chr -r chronicles.nim", true pkg "chronos" pkg "cligen", "nim c -o:cligenn -r cligen.nim" -pkg "coco", "", true pkg "combparser" -pkg "compactdict" +pkg "compactdict", "", false, "https://github.com/Clyybber/compactdict" pkg "comprehension", "", false, "https://github.com/alehander42/comprehension" pkg "criterion" pkg "dashing", "nim c tests/functional.nim" diff --git a/tests/manyloc/keineschweine/lib/estreams.nim b/tests/manyloc/keineschweine/lib/estreams.nim index 99cbb63d18..e8a036f03c 100644 --- a/tests/manyloc/keineschweine/lib/estreams.nim +++ b/tests/manyloc/keineschweine/lib/estreams.nim @@ -26,7 +26,7 @@ proc newBuffer*(pkt: PPacket): PBuffer = copyMem(addr result.data[0], pkt.data, pkt.dataLength) proc toPacket*(buffer: PBuffer; flags: TPacketFlag): PPacket = buffer.data.setLen buffer.pos - result = createPacket(cstring(buffer.data), buffer.pos, flags) + result = createPacket(cstring(buffer.data), csize buffer.pos, flags) proc isDirty*(buffer: PBuffer): bool {.inline.} = result = (buffer.pos != 0) From f30da2f26628d58274363b527e7099bdd44f707d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 8 Oct 2019 20:49:45 +0200 Subject: [PATCH 13/56] fixes #12315 [backport]; refs #12314 (#12385) --- lib/system/io.nim | 6 ++++++ tests/system/techo_unicode.nim | 20 +++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/system/io.nim b/lib/system/io.nim index 46863064be..888ff8e7f1 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -118,6 +118,8 @@ proc c_setvbuf(f: File, buf: pointer, mode: cint, size: int): cint {. proc c_fprintf(f: File, frmt: cstring): cint {. importc: "fprintf", header: "", varargs, discardable.} +proc c_fputc(c: char, f: File): cint {. + importc: "fputc", header: "".} ## When running nim in android app stdout goes no where, so echo gets ignored ## To redreict echo to the android logcat use -d:androidNDK @@ -218,6 +220,10 @@ when defined(windows): var i = c_fprintf(f, "%s", s) while i < s.len: if s[i] == '\0': + let w = c_fputc('\0', f) + if w != 0: + if doRaise: raiseEIO("cannot write string to file") + break inc i else: let w = c_fprintf(f, "%s", unsafeAddr s[i]) diff --git a/tests/system/techo_unicode.nim b/tests/system/techo_unicode.nim index d0395224b1..cb7c49c686 100644 --- a/tests/system/techo_unicode.nim +++ b/tests/system/techo_unicode.nim @@ -4,7 +4,7 @@ abasdfdsmÄhmaИ Иnastystring A你好 ИnastystringA你好 -ÖÜhmabasdfdsmÄhmaИ''' +ÖÜhmabasdfdsmÄhmaИOK''' disabled: "posix" joinable: "false" """ @@ -13,10 +13,10 @@ import winlean echo "ÄhmÖÜ" echo "abasdfdsmÄhmaИ" -echo "И\0nasty\0\0\0\0string\0" +echo "Иnastystring" echo "A你好" -write stdout, "И\0nasty\0\0\0\0string\0" +write stdout, "Иnastystring" writeLine stdout, "A你好" stdout.flushFile() @@ -25,3 +25,17 @@ var a = "ÖÜhmabasdfdsmÄhmaИ" var ac = 0'i32 discard writeFile(handle, addr a[0], int32(len(a)), addr ac, nil) stdout.flushFile() + +import os + +let str = "some nulls: \0\0\0 (three of them)" + +let fpath = getTempDir() / "file_with_nulls.bin" + +writeFile(fpath, str) + +doAssert(getFileSize(fpath) == 31) +doAssert(readFile(fpath) == str) +removeFile(fpath) + +echo "OK" From 84c956d9dadfac0fa149dbc1eb7adef6888c95dc Mon Sep 17 00:00:00 2001 From: Nindaleth Date: Tue, 8 Oct 2019 21:24:34 +0200 Subject: [PATCH 14/56] fix a few dead links and a missing sentence in documentation (#12387) --- lib/pure/strscans.nim | 2 +- lib/system/io.nim | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index e517d8c78c..0125a19266 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -76,7 +76,7 @@ One very nice advantage over regular expressions is that ``scanf`` is extensible with ordinary Nim procs. The proc is either enclosed in ``${}`` or in ``$[]``. ``${}`` matches and binds the result to a variable (that was passed to the ``scanf`` macro) while ``$[]`` merely -optional tokens. +matches optional tokens without any result binding. In this example, we define a helper proc ``someSep`` that skips some separators diff --git a/lib/system/io.nim b/lib/system/io.nim index 888ff8e7f1..89ceb4ea20 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -667,10 +667,10 @@ when defined(windows) and appType == "console" and proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.} = ## Opens a file named `filename` for reading, calls `readAll - ## <#readAll>`_ and closes the file afterwards. Returns the string. - ## Raises an IO exception in case of an error. If # you need to call + ## <#readAll,File>`_ and closes the file afterwards. Returns the string. + ## Raises an IO exception in case of an error. If you need to call ## this inside a compile time macro you can use `staticRead - ## <#staticRead>`_. + ## `_. var f: File if open(f, filename): try: From 82fe19769ab7c796b82110c05e1a6b2d77648971 Mon Sep 17 00:00:00 2001 From: Gampol T Date: Wed, 9 Oct 2019 15:48:15 +0700 Subject: [PATCH 15/56] documented behaviour of recv on bufferd socket (#12374) --- lib/pure/net.nim | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 9f8c8bc5ac..878665690d 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -1143,6 +1143,15 @@ proc recv*(socket: Socket, data: var string, size: int, timeout = -1, flags = {SocketFlag.SafeDisconn}): int = ## Higher-level version of ``recv``. ## + ## Reads **up to** ``size`` bytes from ``socket`` into ``buf``. + ## + ## For buffered sockets this function will attempt to read all the requested + ## data. It will read this data in ``BufferSize`` chunks. + ## + ## For unbuffered sockets this function makes no effort to read + ## all the data requested. It will return as much data as the operating system + ## gives it. + ## ## When 0 is returned the socket's connection has been closed. ## ## This function will throw an OSError exception when an error occurs. A value @@ -1171,6 +1180,15 @@ proc recv*(socket: Socket, size: int, timeout = -1, flags = {SocketFlag.SafeDisconn}): string {.inline.} = ## Higher-level version of ``recv`` which returns a string. ## + ## Reads **up to** ``size`` bytes from ``socket`` into ``buf``. + ## + ## For buffered sockets this function will attempt to read all the requested + ## data. It will read this data in ``BufferSize`` chunks. + ## + ## For unbuffered sockets this function makes no effort to read + ## all the data requested. It will return as much data as the operating system + ## gives it. + ## ## When ``""`` is returned the socket's connection has been closed. ## ## This function will throw an OSError exception when an error occurs. From f728614ef8d47ad2ed92eb71dc39d5d0fc83671d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 9 Oct 2019 14:48:42 +0200 Subject: [PATCH 16/56] fixes #12366 [backport] (#12393) --- lib/pure/collections/intsets.nim | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim index 8b7703804d..8338ceaca9 100644 --- a/lib/pure/collections/intsets.nim +++ b/lib/pure/collections/intsets.nim @@ -387,6 +387,7 @@ proc assign*(dest: var IntSet, src: IntSet) = else: dest.counter = src.counter dest.max = src.max + dest.elems = src.elems newSeq(dest.data, src.data.len) var it = src.head @@ -653,3 +654,19 @@ when isMainModule: xs = toSeq(items(x)) xs.sort(cmp[int]) assert xs == @[1, 4, 7, 1001, 1056] + + proc bug12366 = + var + x = initIntSet() + y = initIntSet() + n = 3584 + + for i in 0..n: + x.incl(i) + y.incl(i) + + let z = symmetricDifference(x, y) + doAssert z.len == 0 + doAssert $z == "{}" + + bug12366() From 3b1760df7265309f75c8cce4e9a34d928bea69e6 Mon Sep 17 00:00:00 2001 From: awr1 <41453959+awr1@users.noreply.github.com> Date: Thu, 10 Oct 2019 02:28:54 -0500 Subject: [PATCH 17/56] [backport] Mention "lambdas" and `=>` in the manual (#12397) [ci skip] (so that "lambda" can be CTRL+F'd) --- doc/manual.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index f7e1c939b6..5f45970b10 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -3511,8 +3511,8 @@ for details on how to change this behavior. Anonymous Procs --------------- -Procs can also be treated as expressions, in which case it's allowed to omit -the proc's name. +Unnamed procedures can be used as lambda expressions to pass into other +procedures: .. code-block:: nim var cities = @["Frankfurt", "Tokyo", "New York", "Kyiv"] @@ -3522,7 +3522,9 @@ the proc's name. Procs as expressions can appear both as nested procs and inside top level -executable code. +executable code. The `sugar `_ module contains the `=>` macro +which enables a more succinct syntax for anonymous procedures resembling +lambdas as they are in languages like JavaScript, C#, etc. Func From 7f904e2c663163e327cbe784a982ac2af8bbd6f3 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 10 Oct 2019 10:00:41 +0200 Subject: [PATCH 18/56] fixes #12244 [backport] --- compiler/vm.nim | 1 - tests/vm/tmisc_vm.nim | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index b264dfe17a..4589d3a25c 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -710,7 +710,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of rkNode: if regs[ra].node.kind == nkNilLit: stackTrace(c, tos, pc, errNilAccess) - assert nfIsRef in regs[ra].node.flags regs[ra].node[] = regs[rc].regToNode[] regs[ra].node.flags.incl nfIsRef else: stackTrace(c, tos, pc, errNilAccess) diff --git a/tests/vm/tmisc_vm.nim b/tests/vm/tmisc_vm.nim index 7733314dbd..7d7275426c 100644 --- a/tests/vm/tmisc_vm.nim +++ b/tests/vm/tmisc_vm.nim @@ -1,6 +1,8 @@ discard """ output: '''[127, 127, 0, 255] [127, 127, 0, 255] + +(data: 1) ''' nimout: '''caught Exception @@ -180,3 +182,21 @@ static: var stream = initCtsStream(file) parseAtlas(stream) echo "Done!" + + +# bug #12244 + +type + Apple = object + data: int + +func what(x: var Apple) = + x = Apple(data: 1) + +func oh_no(): Apple = + what(result) + +const + vmCrash = oh_no() + +debugEcho vmCrash From d783c0f7ff51e85d85bb7c85d2d2c9556cfcbe60 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 10 Oct 2019 11:56:01 +0200 Subject: [PATCH 19/56] fixes a koch regression that made 'koch boot --listcmd' not work anymore [backport] (#12400) --- koch.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/koch.nim b/koch.nim index 083394e00b..a0a7dd903d 100644 --- a/koch.nim +++ b/koch.nim @@ -320,8 +320,8 @@ proc boot(args: string) = # jsonbuild then uses the $project.json file to build the Nim binary. exec "$# $# $# $# --nimcache:$# --compileOnly compiler" / "nim.nim" % [nimi, bootOptions, extraOption, args, smartNimcache] - exec "$# jsonscript --nimcache:$# compiler" / "nim.nim" % - [nimi, smartNimcache] + exec "$# jsonscript $# --nimcache:$# compiler" / "nim.nim" % + [nimi, args, smartNimcache] if sameFileContent(output, i.thVersion): copyExe(output, finalDest) From 00e06bba2808a3a75f7543d89a60078356c71127 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 10 Oct 2019 13:47:47 +0200 Subject: [PATCH 20/56] minor improvements for htmlgen.nim --- lib/pure/htmlgen.nim | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim index 7a39e6d401..3a1ed23065 100644 --- a/lib/pure/htmlgen.nim +++ b/lib/pure/htmlgen.nim @@ -10,6 +10,10 @@ ## Do yourself a favor and import the module ## as ``from htmlgen import nil`` and then fully qualify the macros. ## +## *Note*: The Karax project (``nimble install karax``) has a better +## way to achieve the same, see `https://github.com/pragmagic/karax/blob/master/tests/nativehtmlgen.nim`_ +## for an example. +## ## ## This module implements a simple `XML`:idx: and `HTML`:idx: code ## generator. Each commonly used HTML tag has a corresponding macro @@ -20,11 +24,11 @@ ## ## .. code-block:: Nim ## var nim = "Nim" -## echo h1(a(href="http://nim-lang.org", nim)) +## echo h1(a(href="https://nim-lang.org", nim)) ## ## Writes the string:: ## -##

      Nim

      +##

      Nim

      ## import @@ -606,7 +610,7 @@ macro wbr*(e: varargs[untyped]): untyped = runnableExamples: let nim = "Nim" - assert h1(a(href = "http://nim-lang.org", nim)) == - """

      Nim

      """ + assert h1(a(href = "https://nim-lang.org", nim)) == + """

      Nim

      """ assert form(action = "test", `accept-charset` = "Content-Type") == """
      """ From 0a29c05a1b4523dbaa0b1ed7c368df35de0289a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Thu, 10 Oct 2019 14:35:26 +0200 Subject: [PATCH 21/56] fix #12332 (#12402) [backport] --- compiler/int128.nim | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/compiler/int128.nim b/compiler/int128.nim index ce8f574bd2..44f77b8e83 100644 --- a/compiler/int128.nim +++ b/compiler/int128.nim @@ -436,7 +436,7 @@ proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] = result.quotient = -quotient else: result.quotient = quotient - if isNegativeB: + if isNegativeA: result.remainder = -dividend else: result.remainder = dividend @@ -676,3 +676,12 @@ when isMainModule: doAssert $high(Int128) == "170141183460469231731687303715884105727" doAssert $low(Int128) == "-170141183460469231731687303715884105728" + + var ma = 100'i64 + var mb = 13 + + # sign correctness + doAssert divMod(toInt128( ma),toInt128( mb)) == (toInt128( ma div mb), toInt128( ma mod mb)) + doAssert divMod(toInt128(-ma),toInt128( mb)) == (toInt128(-ma div mb), toInt128(-ma mod mb)) + doAssert divMod(toInt128( ma),toInt128(-mb)) == (toInt128( ma div -mb), toInt128( ma mod -mb)) + doAssert divMod(toInt128(-ma),toInt128(-mb)) == (toInt128(-ma div -mb), toInt128(-ma mod -mb)) From 45030972b94110b4e3c48afc9d80629e96cfc385 Mon Sep 17 00:00:00 2001 From: Euan Date: Thu, 10 Oct 2019 16:28:47 +0100 Subject: [PATCH 22/56] #12389: Check working directory for getAppFilename() (#12390) * Check working directory for exe * Expand symlinks * Use expandFilename() to expand symlinks * Move OpenBSD code to getApplOpenBsd() --- lib/pure/os.nim | 52 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 4e7e37698a..9894831a6c 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -15,18 +15,18 @@ ## import os ## ## let myFile = "/path/to/my/file.nim" -## +## ## let pathSplit = splitPath(myFile) ## assert pathSplit.head == "/path/to/my" ## assert pathSplit.tail == "file.nim" -## +## ## assert parentDir(myFile) == "/path/to/my" -## +## ## let fileSplit = splitFile(myFile) ## assert fileSplit.dir == "/path/to/my" ## assert fileSplit.name == "file" ## assert fileSplit.ext == ".nim" -## +## ## assert myFile.changeFileExt("c") == "/path/to/my/file.c" ## @@ -2721,6 +2721,47 @@ when not weirdTarget and (defined(linux) or defined(solaris) or defined(bsd) or len = readlink(procPath, result, len) setLen(result, len) +when defined(openbsd): + proc isExecutable(path: string): bool = + let p = getFilePermissions(path) + result = fpUserExec in p and fpGroupExec in p and fpOthersExec in p + + proc getApplOpenBsd(): string = + # similar to getApplHeuristic, but checks current working directory + when declared(paramStr): + result = "" + + # POSIX guaranties that this contains the executable + # as it has been executed by the calling process + let exePath = string(paramStr(0)) + + if len(exePath) == 0: + return "" + + if exePath[0] == DirSep: + # path is absolute + result = exePath + else: + # not an absolute path, check if it's relative to the current working directory + for i in 1.. 0: + if isExecutable(result): + return expandFilename(result) + + return "" + + # search in path + for p in split(string(getEnv("PATH")), {PathSep}): + var x = joinPath(p, exePath) + if existsFile(x) and isExecutable(x): + return expandFilename(x) + else: + result = "" + when not (defined(windows) or defined(macosx) or weirdTarget): proc getApplHeuristic(): string = when declared(paramStr): @@ -2824,6 +2865,9 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noN result = getApplFreebsd() elif defined(haiku): result = getApplHaiku() + elif defined(openbsd): + result = getApplOpenBsd() + # little heuristic that may work on other POSIX-like systems: if result.len == 0: result = getApplHeuristic() From 9e62876647e4b7d5c31854abf16596b76cd03b4a Mon Sep 17 00:00:00 2001 From: genotrance Date: Fri, 11 Oct 2019 00:39:18 -0500 Subject: [PATCH 23/56] Fixes #12286 - require explicit disabling of boehm interior pointer checking (#12406) [backport] --- lib/system/mmdisp.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index ae30dbc733..cba88104d4 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -152,7 +152,9 @@ when defined(boehmgc): proc nimGC_setStackBottom(theStackBottom: pointer) = discard proc initGC() = - boehmGC_set_all_interior_pointers(0) + when defined(boehmNoIntPtr): + # See #12286 + boehmGC_set_all_interior_pointers(0) boehmGCinit() when hasThreadSupport: boehmGC_allow_register_threads() From 245a954b250b3e95f68c6bdadeba6ef1425442aa Mon Sep 17 00:00:00 2001 From: Jasper Jenkins Date: Thu, 10 Oct 2019 23:38:08 -0700 Subject: [PATCH 24/56] ungeneric unsigned ops (#12230) * ungenericise unsigned ops, remove nimNewShiftOps * fix/remove tests * update t6448 * fix line info * disable on 32bit * fix different line info * add changelog entry --- changelog.md | 1 + compiler/condsyms.nim | 1 - lib/system.nim | 187 ++++++++++++++++----------- tests/arithm/tarithm.nim | 22 ++++ tests/concepts/t3330.nim | 16 +-- tests/errmsgs/twrong_at_operator.nim | 8 +- tests/generics/tgenerics_issues.nim | 8 -- tests/pragmas/t6448.nim | 3 +- 8 files changed, 149 insertions(+), 97 deletions(-) diff --git a/changelog.md b/changelog.md index 7381e66975..681d5166d7 100644 --- a/changelog.md +++ b/changelog.md @@ -30,6 +30,7 @@ ## Language changes +- Unsigned integer operators have been fixed to allow promotion of the first operand. ### Tool changes diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index a4dd25045d..dd4ad3b3a0 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -53,7 +53,6 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimKnowsNimvm") defineSymbol("nimArrIdx") defineSymbol("nimHasalignOf") - defineSymbol("nimNewShiftOps") defineSymbol("nimDistros") defineSymbol("nimHasCppDefine") defineSymbol("nimGenericInOutFlags") diff --git a/lib/system.nim b/lib/system.nim index 9158b61536..fdbd91c2f1 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1323,65 +1323,51 @@ proc `mod`*(x, y: int16): int16 {.magic: "ModI", noSideEffect.} proc `mod`*(x, y: int32): int32 {.magic: "ModI", noSideEffect.} proc `mod`*(x, y: int64): int64 {.magic: "ModI", noSideEffect.} -when defined(nimNewShiftOps): - - when defined(nimOldShiftRight) or not defined(nimAshr): - const shrDepMessage = "`shr` will become sign preserving." - proc `shr`*(x: int, y: SomeInteger): int {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} - proc `shr`*(x: int8, y: SomeInteger): int8 {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} - proc `shr`*(x: int16, y: SomeInteger): int16 {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} - proc `shr`*(x: int32, y: SomeInteger): int32 {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} - proc `shr`*(x: int64, y: SomeInteger): int64 {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} - else: - proc `shr`*(x: int, y: SomeInteger): int {.magic: "AshrI", noSideEffect.} - ## Computes the `shift right` operation of `x` and `y`, filling - ## vacant bit positions with the sign bit. - ## - ## **Note**: `Operator precedence `_ - ## is different than in *C*. - ## - ## See also: - ## * `ashr proc <#ashr,int,SomeInteger>`_ for arithmetic shift right - ## - ## .. code-block:: Nim - ## 0b0001_0000'i8 shr 2 == 0b0000_0100'i8 - ## 0b0000_0001'i8 shr 1 == 0b0000_0000'i8 - ## 0b1000_0000'i8 shr 4 == 0b1111_1000'i8 - ## -1 shr 5 == -1 - ## 1 shr 5 == 0 - ## 16 shr 2 == 4 - ## -16 shr 2 == -4 - proc `shr`*(x: int8, y: SomeInteger): int8 {.magic: "AshrI", noSideEffect.} - proc `shr`*(x: int16, y: SomeInteger): int16 {.magic: "AshrI", noSideEffect.} - proc `shr`*(x: int32, y: SomeInteger): int32 {.magic: "AshrI", noSideEffect.} - proc `shr`*(x: int64, y: SomeInteger): int64 {.magic: "AshrI", noSideEffect.} - - - proc `shl`*(x: int, y: SomeInteger): int {.magic: "ShlI", noSideEffect.} - ## Computes the `shift left` operation of `x` and `y`. +when defined(nimOldShiftRight) or not defined(nimAshr): + const shrDepMessage = "`shr` will become sign preserving." + proc `shr`*(x: int, y: SomeInteger): int {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} + proc `shr`*(x: int8, y: SomeInteger): int8 {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} + proc `shr`*(x: int16, y: SomeInteger): int16 {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} + proc `shr`*(x: int32, y: SomeInteger): int32 {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} + proc `shr`*(x: int64, y: SomeInteger): int64 {.magic: "ShrI", noSideEffect, deprecated: shrDepMessage.} +else: + proc `shr`*(x: int, y: SomeInteger): int {.magic: "AshrI", noSideEffect.} + ## Computes the `shift right` operation of `x` and `y`, filling + ## vacant bit positions with the sign bit. ## ## **Note**: `Operator precedence `_ ## is different than in *C*. ## + ## See also: + ## * `ashr proc <#ashr,int,SomeInteger>`_ for arithmetic shift right + ## ## .. code-block:: Nim - ## 1'i32 shl 4 == 0x0000_0010 - ## 1'i64 shl 4 == 0x0000_0000_0000_0010 - proc `shl`*(x: int8, y: SomeInteger): int8 {.magic: "ShlI", noSideEffect.} - proc `shl`*(x: int16, y: SomeInteger): int16 {.magic: "ShlI", noSideEffect.} - proc `shl`*(x: int32, y: SomeInteger): int32 {.magic: "ShlI", noSideEffect.} - proc `shl`*(x: int64, y: SomeInteger): int64 {.magic: "ShlI", noSideEffect.} -else: - proc `shr`*(x, y: int): int {.magic: "ShrI", noSideEffect.} - proc `shr`*(x, y: int8): int8 {.magic: "ShrI", noSideEffect.} - proc `shr`*(x, y: int16): int16 {.magic: "ShrI", noSideEffect.} - proc `shr`*(x, y: int32): int32 {.magic: "ShrI", noSideEffect.} - proc `shr`*(x, y: int64): int64 {.magic: "ShrI", noSideEffect.} + ## 0b0001_0000'i8 shr 2 == 0b0000_0100'i8 + ## 0b0000_0001'i8 shr 1 == 0b0000_0000'i8 + ## 0b1000_0000'i8 shr 4 == 0b1111_1000'i8 + ## -1 shr 5 == -1 + ## 1 shr 5 == 0 + ## 16 shr 2 == 4 + ## -16 shr 2 == -4 + proc `shr`*(x: int8, y: SomeInteger): int8 {.magic: "AshrI", noSideEffect.} + proc `shr`*(x: int16, y: SomeInteger): int16 {.magic: "AshrI", noSideEffect.} + proc `shr`*(x: int32, y: SomeInteger): int32 {.magic: "AshrI", noSideEffect.} + proc `shr`*(x: int64, y: SomeInteger): int64 {.magic: "AshrI", noSideEffect.} - proc `shl`*(x, y: int): int {.magic: "ShlI", noSideEffect.} - proc `shl`*(x, y: int8): int8 {.magic: "ShlI", noSideEffect.} - proc `shl`*(x, y: int16): int16 {.magic: "ShlI", noSideEffect.} - proc `shl`*(x, y: int32): int32 {.magic: "ShlI", noSideEffect.} - proc `shl`*(x, y: int64): int64 {.magic: "ShlI", noSideEffect.} + +proc `shl`*(x: int, y: SomeInteger): int {.magic: "ShlI", noSideEffect.} + ## Computes the `shift left` operation of `x` and `y`. + ## + ## **Note**: `Operator precedence `_ + ## is different than in *C*. + ## + ## .. code-block:: Nim + ## 1'i32 shl 4 == 0x0000_0010 + ## 1'i64 shl 4 == 0x0000_0000_0000_0010 +proc `shl`*(x: int8, y: SomeInteger): int8 {.magic: "ShlI", noSideEffect.} +proc `shl`*(x: int16, y: SomeInteger): int16 {.magic: "ShlI", noSideEffect.} +proc `shl`*(x: int32, y: SomeInteger): int32 {.magic: "ShlI", noSideEffect.} +proc `shl`*(x: int64, y: SomeInteger): int64 {.magic: "ShlI", noSideEffect.} when defined(nimAshr): proc ashr*(x: int, y: SomeInteger): int {.magic: "AshrI", noSideEffect.} @@ -1518,54 +1504,105 @@ template `>%`*(x, y: untyped): untyped = y <% x # unsigned integer operations: -proc `not`*[T: SomeUnsignedInt](x: T): T {.magic: "BitnotI", noSideEffect.} +proc `not`*(x: uint): uint {.magic: "BitnotI", noSideEffect.} ## Computes the `bitwise complement` of the integer `x`. +proc `not`*(x: uint8): uint8 {.magic: "BitnotI", noSideEffect.} +proc `not`*(x: uint16): uint16 {.magic: "BitnotI", noSideEffect.} +proc `not`*(x: uint32): uint32 {.magic: "BitnotI", noSideEffect.} +proc `not`*(x: uint64): uint64 {.magic: "BitnotI", noSideEffect.} -when defined(nimNewShiftOps): - proc `shr`*[T: SomeUnsignedInt](x: T, y: SomeInteger): T {.magic: "ShrI", noSideEffect.} - ## Computes the `shift right` operation of `x` and `y`. - proc `shl`*[T: SomeUnsignedInt](x: T, y: SomeInteger): T {.magic: "ShlI", noSideEffect.} - ## Computes the `shift left` operation of `x` and `y`. -else: - proc `shr`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ShrI", noSideEffect.} - ## Computes the `shift right` operation of `x` and `y`. - proc `shl`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ShlI", noSideEffect.} - ## Computes the `shift left` operation of `x` and `y`. +proc `shr`*(x: uint, y: SomeInteger): uint {.magic: "ShrI", noSideEffect.} + ## Computes the `shift right` operation of `x` and `y`. +proc `shr`*(x: uint8, y: SomeInteger): uint8 {.magic: "ShrI", noSideEffect.} +proc `shr`*(x: uint16, y: SomeInteger): uint16 {.magic: "ShrI", noSideEffect.} +proc `shr`*(x: uint32, y: SomeInteger): uint32 {.magic: "ShrI", noSideEffect.} +proc `shr`*(x: uint64, y: SomeInteger): uint64 {.magic: "ShrI", noSideEffect.} -proc `and`*[T: SomeUnsignedInt](x, y: T): T {.magic: "BitandI", noSideEffect.} +proc `shl`*(x: uint, y: SomeInteger): uint {.magic: "ShlI", noSideEffect.} + ## Computes the `shift left` operation of `x` and `y`. +proc `shl`*(x: uint8, y: SomeInteger): uint8 {.magic: "ShlI", noSideEffect.} +proc `shl`*(x: uint16, y: SomeInteger): uint16 {.magic: "ShlI", noSideEffect.} +proc `shl`*(x: uint32, y: SomeInteger): uint32 {.magic: "ShlI", noSideEffect.} +proc `shl`*(x: uint64, y: SomeInteger): uint64 {.magic: "ShlI", noSideEffect.} + +proc `and`*(x, y: uint): uint {.magic: "BitandI", noSideEffect.} ## Computes the `bitwise and` of numbers `x` and `y`. +proc `and`*(x, y: uint8): uint8 {.magic: "BitandI", noSideEffect.} +proc `and`*(x, y: uint16): uint16 {.magic: "BitandI", noSideEffect.} +proc `and`*(x, y: uint32): uint32 {.magic: "BitandI", noSideEffect.} +proc `and`*(x, y: uint64): uint64 {.magic: "BitandI", noSideEffect.} -proc `or`*[T: SomeUnsignedInt](x, y: T): T {.magic: "BitorI", noSideEffect.} +proc `or`*(x, y: uint): uint {.magic: "BitorI", noSideEffect.} ## Computes the `bitwise or` of numbers `x` and `y`. +proc `or`*(x, y: uint8): uint8 {.magic: "BitorI", noSideEffect.} +proc `or`*(x, y: uint16): uint16 {.magic: "BitorI", noSideEffect.} +proc `or`*(x, y: uint32): uint32 {.magic: "BitorI", noSideEffect.} +proc `or`*(x, y: uint64): uint64 {.magic: "BitorI", noSideEffect.} -proc `xor`*[T: SomeUnsignedInt](x, y: T): T {.magic: "BitxorI", noSideEffect.} +proc `xor`*(x, y: uint): uint {.magic: "BitxorI", noSideEffect.} ## Computes the `bitwise xor` of numbers `x` and `y`. +proc `xor`*(x, y: uint8): uint8 {.magic: "BitxorI", noSideEffect.} +proc `xor`*(x, y: uint16): uint16 {.magic: "BitxorI", noSideEffect.} +proc `xor`*(x, y: uint32): uint32 {.magic: "BitxorI", noSideEffect.} +proc `xor`*(x, y: uint64): uint64 {.magic: "BitxorI", noSideEffect.} -proc `==`*[T: SomeUnsignedInt](x, y: T): bool {.magic: "EqI", noSideEffect.} +proc `==`*(x, y: uint): bool {.magic: "EqI", noSideEffect.} ## Compares two unsigned integers for equality. +proc `==`*(x, y: uint8): bool {.magic: "EqI", noSideEffect.} +proc `==`*(x, y: uint16): bool {.magic: "EqI", noSideEffect.} +proc `==`*(x, y: uint32): bool {.magic: "EqI", noSideEffect.} +proc `==`*(x, y: uint64): bool {.magic: "EqI", noSideEffect.} -proc `+`*[T: SomeUnsignedInt](x, y: T): T {.magic: "AddU", noSideEffect.} +proc `+`*(x, y: uint): uint {.magic: "AddU", noSideEffect.} ## Binary `+` operator for unsigned integers. +proc `+`*(x, y: uint8): uint8 {.magic: "AddU", noSideEffect.} +proc `+`*(x, y: uint16): uint16 {.magic: "AddU", noSideEffect.} +proc `+`*(x, y: uint32): uint32 {.magic: "AddU", noSideEffect.} +proc `+`*(x, y: uint64): uint64 {.magic: "AddU", noSideEffect.} -proc `-`*[T: SomeUnsignedInt](x, y: T): T {.magic: "SubU", noSideEffect.} +proc `-`*(x, y: uint): uint {.magic: "SubU", noSideEffect.} ## Binary `-` operator for unsigned integers. +proc `-`*(x, y: uint8): uint8 {.magic: "SubU", noSideEffect.} +proc `-`*(x, y: uint16): uint16 {.magic: "SubU", noSideEffect.} +proc `-`*(x, y: uint32): uint32 {.magic: "SubU", noSideEffect.} +proc `-`*(x, y: uint64): uint64 {.magic: "SubU", noSideEffect.} -proc `*`*[T: SomeUnsignedInt](x, y: T): T {.magic: "MulU", noSideEffect.} +proc `*`*(x, y: uint): uint {.magic: "MulU", noSideEffect.} ## Binary `*` operator for unsigned integers. +proc `*`*(x, y: uint8): uint8 {.magic: "MulU", noSideEffect.} +proc `*`*(x, y: uint16): uint16 {.magic: "MulU", noSideEffect.} +proc `*`*(x, y: uint32): uint32 {.magic: "MulU", noSideEffect.} +proc `*`*(x, y: uint64): uint64 {.magic: "MulU", noSideEffect.} -proc `div`*[T: SomeUnsignedInt](x, y: T): T {.magic: "DivU", noSideEffect.} +proc `div`*(x, y: uint): uint {.magic: "DivU", noSideEffect.} ## Computes the integer division for unsigned integers. ## This is roughly the same as ``trunc(x/y)``. +proc `div`*(x, y: uint8): uint8 {.magic: "DivU", noSideEffect.} +proc `div`*(x, y: uint16): uint16 {.magic: "DivU", noSideEffect.} +proc `div`*(x, y: uint32): uint32 {.magic: "DivU", noSideEffect.} +proc `div`*(x, y: uint64): uint64 {.magic: "DivU", noSideEffect.} -proc `mod`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ModU", noSideEffect.} +proc `mod`*(x, y: uint): uint {.magic: "ModU", noSideEffect.} ## Computes the integer modulo operation (remainder) for unsigned integers. ## This is the same as ``x - (x div y) * y``. +proc `mod`*(x, y: uint8): uint8 {.magic: "ModU", noSideEffect.} +proc `mod`*(x, y: uint16): uint16 {.magic: "ModU", noSideEffect.} +proc `mod`*(x, y: uint32): uint32 {.magic: "ModU", noSideEffect.} +proc `mod`*(x, y: uint64): uint64 {.magic: "ModU", noSideEffect.} -proc `<=`*[T: SomeUnsignedInt](x, y: T): bool {.magic: "LeU", noSideEffect.} +proc `<=`*(x, y: uint): bool {.magic: "LeU", noSideEffect.} ## Returns true if ``x <= y``. +proc `<=`*(x, y: uint8): bool {.magic: "LeU", noSideEffect.} +proc `<=`*(x, y: uint16): bool {.magic: "LeU", noSideEffect.} +proc `<=`*(x, y: uint32): bool {.magic: "LeU", noSideEffect.} +proc `<=`*(x, y: uint64): bool {.magic: "LeU", noSideEffect.} -proc `<`*[T: SomeUnsignedInt](x, y: T): bool {.magic: "LtU", noSideEffect.} +proc `<`*(x, y: uint): bool {.magic: "LtU", noSideEffect.} ## Returns true if ``unsigned(x) < unsigned(y)``. +proc `<`*(x, y: uint8): bool {.magic: "LtU", noSideEffect.} +proc `<`*(x, y: uint16): bool {.magic: "LtU", noSideEffect.} +proc `<`*(x, y: uint32): bool {.magic: "LtU", noSideEffect.} +proc `<`*(x, y: uint64): bool {.magic: "LtU", noSideEffect.} # floating point operations: proc `+`*(x: float32): float32 {.magic: "UnaryPlusF64", noSideEffect.} diff --git a/tests/arithm/tarithm.nim b/tests/arithm/tarithm.nim index 4625a5ecf3..fcb78bd7a4 100644 --- a/tests/arithm/tarithm.nim +++ b/tests/arithm/tarithm.nim @@ -4,6 +4,14 @@ int32 int32 1280 1280 +3 +1 +2 +2 +3 +4294967295 +2 +0 ''' """ @@ -145,3 +153,17 @@ block tsubrange: level = min(level + 2, maxLevel).n16 doAssert level == 1 + +block tissue12177: + var a: uint16 = 1 + var b: uint32 = 2 + + echo(b + a) + echo(b - a) + echo(b * a) + echo(b div a) + + echo(a + b) + echo(a - b) + echo(a * b) + echo(a div b) diff --git a/tests/concepts/t3330.nim b/tests/concepts/t3330.nim index ed1590e165..ab77dd3475 100644 --- a/tests/concepts/t3330.nim +++ b/tests/concepts/t3330.nim @@ -9,23 +9,23 @@ proc test(foo: Foo[int]) required type for foo: Foo[int] but expression 'bar' is of type: Bar[system.int] t3330.nim(63, 8) Hint: Non-matching candidates for add(k, string, T) -proc add[T](x: var seq[T]; y: openArray[T]) - first type mismatch at position: 1 - required type for x: var seq[T] - but expression 'k' is of type: Alias proc add[T](x: var seq[T]; y: T) first type mismatch at position: 1 required type for x: var seq[T] but expression 'k' is of type: Alias +proc add(x: var string; y: string) + first type mismatch at position: 1 + required type for x: var string + but expression 'k' is of type: Alias proc add(result: var string; x: float) first type mismatch at position: 1 required type for result: var string but expression 'k' is of type: Alias -proc add(x: var string; y: cstring) +proc add(x: var string; y: char) first type mismatch at position: 1 required type for x: var string but expression 'k' is of type: Alias -proc add(x: var string; y: string) +proc add(x: var string; y: cstring) first type mismatch at position: 1 required type for x: var string but expression 'k' is of type: Alias @@ -33,9 +33,9 @@ proc add(result: var string; x: int64) first type mismatch at position: 1 required type for result: var string but expression 'k' is of type: Alias -proc add(x: var string; y: char) +proc add[T](x: var seq[T]; y: openArray[T]) first type mismatch at position: 1 - required type for x: var string + required type for x: var seq[T] but expression 'k' is of type: Alias t3330.nim(63, 8) template/generic instantiation of `add` from here diff --git a/tests/errmsgs/twrong_at_operator.nim b/tests/errmsgs/twrong_at_operator.nim index 9933b0f39a..ebf6d966b8 100644 --- a/tests/errmsgs/twrong_at_operator.nim +++ b/tests/errmsgs/twrong_at_operator.nim @@ -4,14 +4,14 @@ line: 22 nimout: ''' twrong_at_operator.nim(22, 30) Error: type mismatch: got but expected one of: -proc `@`[T](a: openArray[T]): seq[T] - first type mismatch at position: 1 - required type for a: openArray[T] - but expression '[int]' is of type: array[0..0, type int] proc `@`[IDX, T](a: sink array[IDX, T]): seq[T] first type mismatch at position: 1 required type for a: sink array[IDX, T] but expression '[int]' is of type: array[0..0, type int] +proc `@`[T](a: openArray[T]): seq[T] + first type mismatch at position: 1 + required type for a: openArray[T] + but expression '[int]' is of type: array[0..0, type int] expression: @[int] ''' diff --git a/tests/generics/tgenerics_issues.nim b/tests/generics/tgenerics_issues.nim index 3d5d65c750..af71a89380 100644 --- a/tests/generics/tgenerics_issues.nim +++ b/tests/generics/tgenerics_issues.nim @@ -762,11 +762,3 @@ block t3717: var f: Foo[Foo[int]] discard foo(f) - - - -block t5707: - proc foo[T]: seq[int] = - return lc[x | (x <- 1..10, x mod 2 == 0), int] - - doAssert foo[float32]() == @[2, 4, 6, 8, 10] diff --git a/tests/pragmas/t6448.nim b/tests/pragmas/t6448.nim index a1bd747a0b..ab2e3811f9 100644 --- a/tests/pragmas/t6448.nim +++ b/tests/pragmas/t6448.nim @@ -1,6 +1,7 @@ discard """ errormsg: '''ambiguous call; both foobar.async''' - line: 9 + line: 10 + disabled: "32bit" """ import foobar From 7cf3395d857d2e05fb3a83dc67173a69c828807f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Fri, 11 Oct 2019 08:43:58 +0200 Subject: [PATCH 25/56] refactor illegal iterator assignment detection (#12212) * refactor illegal iterator assignment detection * delete crappy test --- compiler/ast.nim | 8 ++++---- compiler/injectdestructors.nim | 2 +- compiler/semexprs.nim | 4 ++-- compiler/semstmts.nim | 12 +----------- compiler/types.nim | 5 ++++- tests/ccgbugs/t5701.nim | 27 --------------------------- tests/ccgbugs/tccgissues.nim | 14 ++++++++++++++ tests/errmsgs/ttypeAllowed.nim | 28 ++++++++++++++++++++++++++++ tests/iter/titerassignerr.nim | 8 -------- 9 files changed, 54 insertions(+), 54 deletions(-) delete mode 100644 tests/ccgbugs/t5701.nim create mode 100644 tests/ccgbugs/tccgissues.nim create mode 100644 tests/errmsgs/ttypeAllowed.nim delete mode 100644 tests/iter/titerassignerr.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index f24008b305..fdf01cb77e 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1810,11 +1810,11 @@ template getBody*(s: PSym): PNode = s.ast[bodyPos] template detailedInfo*(sym: PSym): string = sym.name.s -proc isInlineIterator*(s: PSym): bool {.inline.} = - s.kind == skIterator and s.typ.callConv != ccClosure +proc isInlineIterator*(typ: PType): bool {.inline.} = + typ.kind == tyProc and tfIterator in typ.flags and typ.callConv != ccClosure -proc isClosureIterator*(s: PSym): bool {.inline.} = - s.kind == skIterator and s.typ.callConv == ccClosure +proc isClosureIterator*(typ: PType): bool {.inline.} = + typ.kind == tyProc and tfIterator in typ.flags and typ.callConv == ccClosure proc isSinkParam*(s: PSym): bool {.inline.} = s.kind == skParam and (s.typ.kind == tySink or tfHasOwned in s.typ.flags) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 95de5777ef..5765721d7e 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -636,7 +636,7 @@ proc reverseDestroys(destroys: seq[PNode]): seq[PNode] = result.add destroys[i] proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode = - if sfGeneratedOp in owner.flags or isInlineIterator(owner): return n + if sfGeneratedOp in owner.flags or (owner.kind == skIterator and isInlineIterator(owner.typ)): return n var c: Con c.owner = owner c.destroys = newNodeI(nkStmtList, n.info) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 7a72f16023..019c302262 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1724,7 +1724,7 @@ proc semReturn(c: PContext, n: PNode): PNode = result = n checkSonsLen(n, 1, c.config) if c.p.owner.kind in {skConverter, skMethod, skProc, skFunc, skMacro} or - isClosureIterator(c.p.owner): + isClosureIterator(c.p.owner.typ): if n.sons[0].kind != nkEmpty: # transform ``return expr`` to ``result = expr; return`` if c.p.resultSym != nil: @@ -1771,7 +1771,7 @@ proc semProcBody(c: PContext, n: PNode): PNode = else: localError(c.config, c.p.resultSym.info, errCannotInferReturnType % c.p.owner.name.s) - if isInlineIterator(c.p.owner) and c.p.owner.typ.sons[0] != nil and + if isInlineIterator(c.p.owner.typ) and c.p.owner.typ.sons[0] != nil and c.p.owner.typ.sons[0].kind == tyUntyped: localError(c.config, c.p.owner.info, errCannotInferReturnType % c.p.owner.name.s) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 8acc5ce2fd..f5a82b910a 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -38,7 +38,6 @@ const errPragmaOnlyInHeaderOfProcX = "pragmas are only allowed in the header of a proc; redefinition of $1" errCannotAssignMacroSymbol = "cannot assign macro symbol to $1 here. Forgot to invoke the macro with '()'?" errInvalidTypeDescAssign = "'typedesc' metatype is not valid here; typed '=' instead of ':'?" - errInlineIteratorNotFirstClass = "inline iterators are not first-class / cannot be assigned to variables" proc semDiscard(c: PContext, n: PNode): PNode = result = n @@ -456,9 +455,6 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if def.sym.kind == skMacro: localError(c.config, def.info, errCannotAssignMacroSymbol % "variable") def.typ = errorType(c) - elif isInlineIterator(def.sym): - localError(c.config, def.info, errInlineIteratorNotFirstClass) - def.typ = errorType(c) elif def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro: # prevent the all too common 'var x = int' bug: localError(c.config, def.info, errInvalidTypeDescAssign) @@ -601,9 +597,6 @@ proc semConst(c: PContext, n: PNode): PNode = if def.sym.kind == skMacro: localError(c.config, def.info, errCannotAssignMacroSymbol % "constant") def.typ = errorType(c) - elif isInlineIterator(def.sym): - localError(c.config, def.info, errInlineIteratorNotFirstClass) - def.typ = errorType(c) elif def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro: # prevent the all too common 'const x = int' bug: localError(c.config, def.info, errInvalidTypeDescAssign) @@ -1589,7 +1582,7 @@ proc maybeAddResult(c: PContext, s: PSym, n: PNode) = let resultType = sysTypeFromName(c.graph, n.info, "NimNode") addResult(c, resultType, n.info, s.kind) addResultNode(c, n) - elif s.typ.sons[0] != nil and not isInlineIterator(s): + elif s.typ.sons[0] != nil and not isInlineIterator(s.typ): addResult(c, s.typ.sons[0], n.info, s.kind) addResultNode(c, n) @@ -1969,7 +1962,6 @@ proc determineType(c: PContext, s: PSym) = proc semIterator(c: PContext, n: PNode): PNode = # gensym'ed iterator? - let isAnon = n[namePos].kind == nkEmpty if n[namePos].kind == nkSym: # gensym'ed iterators might need to become closure iterators: n[namePos].sym.owner = getCurrOwner(c) @@ -1983,8 +1975,6 @@ proc semIterator(c: PContext, n: PNode): PNode = var t = s.typ if t.sons[0] == nil and s.typ.callConv != ccClosure: localError(c.config, n.info, "iterator needs a return type") - if isAnon and s.typ.callConv == ccInline: - localError(c.config, n.info, errInlineIteratorNotFirstClass) # iterators are either 'inline' or 'closure'; for backwards compatibility, # we require first class iterators to be marked with 'closure' explicitly # -- at least for 0.9.2. diff --git a/compiler/types.nim b/compiler/types.nim index 8ff109b378..dc5068d0e2 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1280,10 +1280,13 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, if kind notin {skParam, skResult}: result = t else: result = typeAllowedAux(marker, t2, kind, flags) of tyProc: + if isInlineIterator(typ) and kind in {skVar, skLet, skConst, skParam, skResult}: + # only closure iterators my be assigned to anything. + result = t let f = if kind in {skProc, skFunc}: flags+{taNoUntyped} else: flags for i in 1 ..< len(t): - result = typeAllowedAux(marker, t.sons[i], skParam, f-{taIsOpenArray}) if result != nil: break + result = typeAllowedAux(marker, t.sons[i], skParam, f-{taIsOpenArray}) if result.isNil and t.sons[0] != nil: result = typeAllowedAux(marker, t.sons[0], skResult, flags) of tyTypeDesc: diff --git a/tests/ccgbugs/t5701.nim b/tests/ccgbugs/t5701.nim deleted file mode 100644 index 19d64a2304..0000000000 --- a/tests/ccgbugs/t5701.nim +++ /dev/null @@ -1,27 +0,0 @@ -discard """ - output: '''(1, 1) -(2, 2) -(3, 3) -@[1, 2, 3, 4] -''' -""" - -iterator zip[T1, T2](a: openarray[T1], b: openarray[T2]): iterator() {.inline.} = - let len = min(a.len, b.len) - for i in 0.. Date: Fri, 11 Oct 2019 14:55:15 +0700 Subject: [PATCH 26/56] nimsuggest: add option to force finding the project file (#12409) --- nimsuggest/nimsuggest.nim | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index aa45a64e9a..26cb0ce31d 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -48,6 +48,7 @@ Options: --maxresults:N limit the number of suggestions to N --tester implies --stdin and outputs a line '""" & DummyEof & """' for the tester + --find attempts to find the project file of the current project The server then listens to the connection and takes line-based commands. @@ -549,6 +550,7 @@ proc mainCommand(graph: ModuleGraph) = proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) = var p = parseopt.initOptParser(cmd) + var findProject = false while true: parseopt.next(p) case p.kind @@ -594,6 +596,8 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) = gRefresh = true of "maxresults": conf.suggestMaxResults = parseInt(p.val) + of "find": + findProject = true else: processSwitch(pass, p, conf) of cmdArgument: let a = unixToNativePath(p.key) @@ -602,7 +606,12 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) = # don't make it worse, report the error the old way: if conf.projectName.len == 0: conf.projectName = a else: - conf.projectName = a + if findProject: + conf.projectName = findProjectNimFile(conf, a.parentDir()) + if conf.projectName.len == 0: + conf.projectName = a + else: + conf.projectName = a # if processArgument(pass, p, argsCount): break proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = From f957266574652865bc60b289327e6444f9f07f49 Mon Sep 17 00:00:00 2001 From: alaviss Date: Fri, 11 Oct 2019 23:00:38 +0700 Subject: [PATCH 27/56] nimsuggest: add a command that returns the project file (#12411) This can be used to let nimsuggest users know which project is nimsuggest being in charge of, so they can know when should a new nimsuggest instance be spawned. An additional feature is to debug the project file finding feature. --- compiler/options.nim | 4 +++- nimsuggest/nimsuggest.nim | 11 ++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/compiler/options.nim b/compiler/options.nim index 52c38e34e2..af97ba1909 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -118,7 +118,7 @@ type IdeCmd* = enum ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod, - ideHighlight, ideOutline, ideKnown, ideMsg + ideHighlight, ideOutline, ideKnown, ideMsg, ideProject Feature* = enum ## experimental features; DO NOT RENAME THESE! implicitDeref, @@ -709,6 +709,7 @@ proc parseIdeCmd*(s: string): IdeCmd = of "outline": ideOutline of "known": ideKnown of "msg": ideMsg + of "project": ideProject else: ideNone proc `$`*(c: IdeCmd): string = @@ -725,6 +726,7 @@ proc `$`*(c: IdeCmd): string = of ideOutline: "outline" of ideKnown: "known" of ideMsg: "msg" + of ideProject: "project" proc floatInt64Align*(conf: ConfigRef): int16 = ## Returns either 4 or 8 depending on reasons. diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index 26cb0ce31d..7e31427620 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -93,7 +93,7 @@ proc myLog(s: string) = const seps = {':', ';', ' ', '\t'} - Help = "usage: sug|con|def|use|dus|chk|mod|highlight|outline|known file.nim[;dirtyfile.nim]:line:col\n" & + Help = "usage: sug|con|def|use|dus|chk|mod|highlight|outline|known|project file.nim[;dirtyfile.nim]:line:col\n" & "type 'quit' to quit\n" & "type 'debug' to toggle debug mode on/off\n" & "type 'terse' to toggle terse mode on/off" @@ -245,6 +245,7 @@ proc toStdout() {.gcsafe.} = of ideNone: break of ideMsg: echo res.doc of ideKnown: echo res.quality == 1 + of ideProject: echo res.filePath else: echo res proc toSocket(stdoutSocket: Socket) {.gcsafe.} = @@ -254,6 +255,7 @@ proc toSocket(stdoutSocket: Socket) {.gcsafe.} = of ideNone: break of ideMsg: stdoutSocket.send(res.doc & "\c\L") of ideKnown: stdoutSocket.send($(res.quality == 1) & "\c\L") + of ideProject: stdoutSocket.send(res.filePath & "\c\L") else: stdoutSocket.send($res & "\c\L") proc toEpc(client: Socket; uid: BiggestInt) {.gcsafe.} = @@ -266,6 +268,8 @@ proc toEpc(client: Socket; uid: BiggestInt) {.gcsafe.} = list.add sexp(res.doc) of ideKnown: list.add sexp(res.quality == 1) + of ideProject: + list.add sexp(res.filePath) else: list.add sexp(res) returnEpc(client, uid, list) @@ -435,6 +439,7 @@ proc execCmd(cmd: string; graph: ModuleGraph; cachedMsgs: CachedMsgs) = of "debug": toggle optIdeDebug of "terse": toggle optIdeTerse of "known": conf.ideCmd = ideKnown + of "project": conf.ideCmd = ideProject else: err() var dirtyfile = "" var orig = "" @@ -454,6 +459,8 @@ proc execCmd(cmd: string; graph: ModuleGraph; cachedMsgs: CachedMsgs) = if conf.ideCmd == ideKnown: results.send(Suggest(section: ideKnown, quality: ord(fileInfoKnown(conf, AbsoluteFile orig)))) + elif conf.ideCmd == ideProject: + results.send(Suggest(section: ideProject, filePath: string conf.projectFull)) else: if conf.ideCmd == ideChk: for cm in cachedMsgs: errorHook(conf, cm.info, cm.msg, cm.sev) @@ -741,6 +748,8 @@ else: stderr.write s & "\n" if conf.ideCmd == ideKnown: retval.add(Suggest(section: ideKnown, quality: ord(fileInfoKnown(conf, file)))) + elif conf.ideCmd == ideProject: + retval.add(Suggest(section: ideProject, filePath: string conf.projectFull)) else: if conf.ideCmd == ideChk: for cm in nimsuggest.cachedMsgs: errorHook(conf, cm.info, cm.msg, cm.sev) From 94c1695be6a81f82de07340fc1c2010281111fad Mon Sep 17 00:00:00 2001 From: alaviss Date: Fri, 11 Oct 2019 23:04:52 +0700 Subject: [PATCH 28/56] compiler/options: improve project file detection (#12404) The compiler can now correctly find the project file of a nimble package. The algorithm is based on what used by nim.nvim, which has yielded good results. --- compiler/options.nim | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/compiler/options.nim b/compiler/options.nim index af97ba1909..3f7ca4720c 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -662,20 +662,40 @@ proc findModule*(conf: ConfigRef; modulename, currentModule: string): AbsoluteFi proc findProjectNimFile*(conf: ConfigRef; pkg: string): string = const extensions = [".nims", ".cfg", ".nimcfg", ".nimble"] - var candidates: seq[string] = @[] - var dir = pkg + var + candidates: seq[string] = @[] + dir = pkg + nimblepkg = "" + let pkgname = pkg.lastPathPart() while true: - for k, f in os.walkDir(dir, relative=true): + for k, f in os.walkDir(dir, relative = true): if k == pcFile and f != "config.nims": let (_, name, ext) = splitFile(f) if ext in extensions: let x = changeFileExt(dir / name, ".nim") if fileExists(x): candidates.add x + if ext == ".nimble": + if nimblepkg.len == 0: + nimblepkg = name + # Scan subfolders for package source since nimble supports that. + # To save time we only scan with the depth of one as that's the + # common scenario. + let x = x.extractFilename() + for k, d in os.walkDir(dir): + if k == pcDir: + for k, f in os.walkDir(d, relative = true): + if k == pcFile and f == x: + candidates.add d / f + else: + # If we found more than one nimble file, chances are that we + # missed the real project file, or this is an invalid nimble + # package. Either way, bailing is the better choice. + return "" + let pkgname = if nimblepkg.len > 0: nimblepkg else: pkgname for c in candidates: - # nim-foo foo or foo nfoo - if (pkg in c) or (c in pkg): return c - if candidates.len >= 1: + if pkgname in c.extractFilename(): return c + if candidates.len > 0: return candidates[0] dir = parentDir(dir) if dir == "": break From 990aadc43c3b492a1df61582d5bd212a0643aee4 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Fri, 11 Oct 2019 19:05:23 +0300 Subject: [PATCH 29/56] Fixes semCustomPragma when nkSym (#12414) [backport] --- compiler/pragmas.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 208f6dae3d..383eaacedd 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -720,7 +720,7 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym = proc semCustomPragma(c: PContext, n: PNode): PNode = var callNode: PNode - if n.kind == nkIdent: + if n.kind in {nkIdent, nkSym}: # pragma -> pragma() callNode = newTree(nkCall, n) elif n.kind == nkExprColonExpr: From 48975bb3e7c1d5f8e1f81981cd5e3c028ccf37a5 Mon Sep 17 00:00:00 2001 From: narimiran Date: Mon, 14 Oct 2019 11:51:41 +0200 Subject: [PATCH 30/56] [ci skip] disable two packages until #11764 is merged --- testament/important_packages.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index dfa448c955..a6e712009e 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -36,8 +36,8 @@ pkg "gnuplot" pkg "hts", "nim c -o:htss -r src/hts.nim" pkg "illwill", "nimble examples" pkg "inim" -pkg "itertools", "nim doc src/itertools.nim" -pkg "iterutils" +# pkg "itertools", "nim doc src/itertools.nim" +# pkg "iterutils" pkg "jstin" pkg "karax", "nim c -r tests/tester.nim" pkg "loopfusion" From 1aed455e7cc22368299a40bb16f73d43ed8c544e Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Tue, 15 Oct 2019 10:16:06 +0300 Subject: [PATCH 31/56] Fixed yield in nkCheckedFieldExpr (#12429) [backport] --- compiler/closureiters.nim | 5 +++-- tests/async/tasync_misc.nim | 10 ++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index 84da6a84d5..7d3637645f 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -683,7 +683,8 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode = n[0] = ex result.add(n) - of nkCast, nkHiddenStdConv, nkHiddenSubConv, nkConv, nkObjDownConv: + of nkCast, nkHiddenStdConv, nkHiddenSubConv, nkConv, nkObjDownConv, + nkDerefExpr, nkHiddenDeref: var ns = false for i in 0 ..< n.len: n[i] = ctx.lowerStmtListExprs(n[i], ns) @@ -757,7 +758,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode = n[0] = newSymNode(ctx.g.getSysSym(n[0].info, "true")) n[1] = newBody - of nkDotExpr: + of nkDotExpr, nkCheckedFieldExpr: var ns = false n[0] = ctx.lowerStmtListExprs(n[0], ns) if ns: diff --git a/tests/async/tasync_misc.nim b/tests/async/tasync_misc.nim index dbc2ea434f..1febdedb3b 100644 --- a/tests/async/tasync_misc.nim +++ b/tests/async/tasync_misc.nim @@ -43,4 +43,14 @@ block: #8399 waitFor foo("$asd") +block: # nkCheckedFieldExpr + proc bar(): Future[JsonNode] {.async.} = + return newJInt(5) + + proc foo() {.async.} = + let n = 10 + (await bar()).num + doAssert(n == 15) + + waitFor foo() + echo "ok" From 5f5ac8ce1616c7a68002b99ba4ffc36ab3a3ec42 Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 15 Oct 2019 16:29:32 +0200 Subject: [PATCH 32/56] [backport] fix #12418, fix `random.randomize` on JS backend (#12432) --- lib/pure/random.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/random.nim b/lib/pure/random.nim index c3ccd121bf..b10bc43c82 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -642,7 +642,7 @@ when not defined(nimscript): ## * `randomize proc<#randomize,int64>`_ that accepts a seed ## * `initRand proc<#initRand,int64>`_ when defined(JS): - let time = int64(times.epochTime() * 1000) + let time = int64(times.epochTime() * 1000) and 0x7fff_ffff randomize(time) else: let now = times.getTime() From 734da9e1dfdd5cb441a5c1461539f10ab331596a Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 15 Oct 2019 16:31:07 +0200 Subject: [PATCH 33/56] fixes #11764, faster hashing of (u)int (#12407) --- lib/pure/collections/sets.nim | 4 ++-- lib/pure/hashes.nim | 15 +++++++++------ tests/collections/ttables.nim | 4 ++-- tests/collections/ttablesthreads.nim | 2 +- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 322cb5486d..4b896b12b7 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -1019,9 +1019,9 @@ when isMainModule and not defined(release): # --> {1, 3, 5} block toSeqAndString: - var a = toHashSet([2, 4, 5]) + var a = toHashSet([2, 7, 5]) var b = initHashSet[int]() - for x in [2, 4, 5]: b.incl(x) + for x in [2, 7, 5]: b.incl(x) assert($a == $b) #echo a #echo toHashSet(["no", "esc'aping", "is \" provided"]) diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index cb0250dbd3..f5b9cda851 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -112,29 +112,32 @@ proc hash*[T: proc](x: T): Hash {.inline.} = else: result = hash(pointer(x)) +const + prime = uint(11) + proc hash*(x: int): Hash {.inline.} = ## Efficient hashing of integers. - result = x + result = cast[Hash](cast[uint](x) * prime) proc hash*(x: int64): Hash {.inline.} = ## Efficient hashing of `int64` integers. - result = cast[int](x) + result = cast[Hash](cast[uint](x) * prime) proc hash*(x: uint): Hash {.inline.} = ## Efficient hashing of unsigned integers. - result = cast[int](x) + result = cast[Hash](x * prime) proc hash*(x: uint64): Hash {.inline.} = ## Efficient hashing of `uint64` integers. - result = cast[int](x) + result = cast[Hash](cast[uint](x) * prime) proc hash*(x: char): Hash {.inline.} = ## Efficient hashing of characters. - result = ord(x) + result = cast[Hash](cast[uint](ord(x)) * prime) proc hash*[T: Ordinal](x: T): Hash {.inline.} = ## Efficient hashing of other ordinal types (e.g. enums). - result = ord(x) + result = cast[Hash](cast[uint](ord(x)) * prime) proc hash*(x: float): Hash {.inline.} = ## Efficient hashing of floats. diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index 0a5a013679..9eccf345a6 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -233,7 +233,7 @@ block tablesref: for y in 0..1: assert t[(x,y)] == $x & $y assert($t == - "{(x: 0, y: 1): \"01\", (x: 0, y: 0): \"00\", (x: 1, y: 0): \"10\", (x: 1, y: 1): \"11\"}") + "{(x: 1, y: 1): \"11\", (x: 0, y: 0): \"00\", (x: 0, y: 1): \"01\", (x: 1, y: 0): \"10\"}") block tableTest2: var t = newTable[string, float]() @@ -340,7 +340,7 @@ block tablesref: block anonZipTest: let keys = @['a','b','c'] let values = @[1, 2, 3] - doAssert "{'a': 1, 'b': 2, 'c': 3}" == $ toTable zip(keys, values) + doAssert "{'c': 3, 'a': 1, 'b': 2}" == $ toTable zip(keys, values) block clearTableTest: var t = newTable[string, float]() diff --git a/tests/collections/ttablesthreads.nim b/tests/collections/ttablesthreads.nim index 7fe4c79b13..5553b31ef8 100644 --- a/tests/collections/ttablesthreads.nim +++ b/tests/collections/ttablesthreads.nim @@ -48,7 +48,7 @@ block tableTest1: for y in 0..1: assert t[(x,y)] == $x & $y assert($t == - "{(x: 0, y: 1): \"01\", (x: 0, y: 0): \"00\", (x: 1, y: 0): \"10\", (x: 1, y: 1): \"11\"}") + "{(x: 1, y: 1): \"11\", (x: 0, y: 0): \"00\", (x: 0, y: 1): \"01\", (x: 1, y: 0): \"10\"}") block tableTest2: var t = initTable[string, float]() From 37dfb7ecc6b482578bdd8778379f506032b961c9 Mon Sep 17 00:00:00 2001 From: alaviss Date: Wed, 16 Oct 2019 11:03:11 +0000 Subject: [PATCH 34/56] compiler/options: only check the last folder for a candidate (#12421) This prevents a nimble file from causing a different project to be targeted instead of the desired one. --- compiler/options.nim | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/compiler/options.nim b/compiler/options.nim index 3f7ca4720c..d115a20bd6 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -665,6 +665,7 @@ proc findProjectNimFile*(conf: ConfigRef; pkg: string): string = var candidates: seq[string] = @[] dir = pkg + prev = dir nimblepkg = "" let pkgname = pkg.lastPathPart() while true: @@ -678,15 +679,12 @@ proc findProjectNimFile*(conf: ConfigRef; pkg: string): string = if ext == ".nimble": if nimblepkg.len == 0: nimblepkg = name - # Scan subfolders for package source since nimble supports that. - # To save time we only scan with the depth of one as that's the - # common scenario. - let x = x.extractFilename() - for k, d in os.walkDir(dir): - if k == pcDir: - for k, f in os.walkDir(d, relative = true): - if k == pcFile and f == x: - candidates.add d / f + # Since nimble packages can have their source in a subfolder, + # check the last folder we were in for a possible match. + if dir != prev: + let x = prev / x.extractFilename() + if fileExists(x): + candidates.add x else: # If we found more than one nimble file, chances are that we # missed the real project file, or this is an invalid nimble @@ -697,6 +695,7 @@ proc findProjectNimFile*(conf: ConfigRef; pkg: string): string = if pkgname in c.extractFilename(): return c if candidates.len > 0: return candidates[0] + prev = dir dir = parentDir(dir) if dir == "": break return "" From 5ba932e43c9c971555d8fdc9e25e2edcdcdd70b4 Mon Sep 17 00:00:00 2001 From: treeform Date: Thu, 17 Oct 2019 00:50:00 -0700 Subject: [PATCH 35/56] About 50% faster base64 implemention. (#12436) --- changelog.md | 2 + lib/pure/base64.nim | 254 +++++++++++++++++++++------------------ lib/pure/httpclient.nim | 2 +- tests/stdlib/tbase64.nim | 44 +++++++ 4 files changed, 186 insertions(+), 116 deletions(-) create mode 100644 tests/stdlib/tbase64.nim diff --git a/changelog.md b/changelog.md index 681d5166d7..22b0b130d6 100644 --- a/changelog.md +++ b/changelog.md @@ -7,6 +7,7 @@ ### Breaking changes in the standard library +- `base64.encode` no longer supports `lineLen` and `newLine` use `base64.encodeMIME` instead. ### Breaking changes in the compiler @@ -22,6 +23,7 @@ ## Library changes +- `base64.encode` and `base64.decode` was made faster by about 50%. ## Language additions diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim index a5b69fadbd..615af24d1c 100644 --- a/lib/pure/base64.nim +++ b/lib/pure/base64.nim @@ -56,100 +56,119 @@ const cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + invalidChar = 255 -template encodeInternal(s: typed, lineLen: int, newLine: string): untyped = - ## encodes `s` into base64 representation. After `lineLen` characters, a - ## `newline` is added. - var total = ((len(s) + 2) div 3) * 4 - let numLines = (total + lineLen - 1) div lineLen - if numLines > 0: inc(total, (numLines - 1) * newLine.len) +template encodeInternal(s: typed): untyped = + ## encodes `s` into base64 representation. + proc encodeSize(size: int): int = + return (size * 4 div 3) + 6 + + result.setLen(encodeSize(s.len)) - result = newString(total) var - i = 0 - r = 0 - currLine = 0 - while i < s.len - 2: - let - a = ord(s[i]) - b = ord(s[i+1]) - c = ord(s[i+2]) - result[r] = cb64[a shr 2] - result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)] - result[r+2] = cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)] - result[r+3] = cb64[c and 0x3F] - inc(r, 4) - inc(i, 3) - inc(currLine, 4) - # avoid index out of bounds when lineLen == encoded length - if currLine >= lineLen and i != s.len-2 and r < total: - for x in items(newLine): - result[r] = x - inc(r) - currLine = 0 + inputIndex = 0 + outputIndex = 0 + inputEnds = s.len - s.len mod 3 + n: uint32 + b: uint32 - if i < s.len-1: - let - a = ord(s[i]) - b = ord(s[i+1]) - result[r] = cb64[a shr 2] - result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)] - result[r+2] = cb64[((b and 0x0F) shl 2)] - result[r+3] = '=' - if r+4 != result.len: - setLen(result, r+4) - elif i < s.len: - let a = ord(s[i]) - result[r] = cb64[a shr 2] - result[r+1] = cb64[(a and 3) shl 4] - result[r+2] = '=' - result[r+3] = '=' - if r+4 != result.len: - setLen(result, r+4) - else: - if r != result.len: - setLen(result, r) - #assert(r == result.len) - discard + template inputByte(exp: untyped) = + b = uint32(s[inputIndex]) + n = exp + inc inputIndex -proc encode*[T: SomeInteger|char](s: openArray[T], lineLen = 75, - newLine = ""): string = - ## Encodes ``s`` into base64 representation. After ``lineLen`` characters, a - ## ``newline`` is added. + template outputChar(x: untyped) = + result[outputIndex] = cb64[x and 63] + inc outputIndex + + template outputChar(c: char) = + result[outputIndex] = c + inc outputIndex + + while inputIndex != inputEnds: + inputByte(b shl 16) + inputByte(n or b shl 8) + inputByte(n or b shl 0) + outputChar(n shr 18) + outputChar(n shr 12) + outputChar(n shr 6) + outputChar(n shr 0) + + var padding = s.len mod 3 + if padding == 1: + inputByte(b shl 16) + outputChar(n shr 18) + outputChar(n shr 12) + outputChar('=') + outputChar('=') + + elif padding == 2: + inputByte(b shl 16) + inputByte(n or b shl 8) + outputChar(n shr 18) + outputChar(n shr 12) + outputChar(n shr 6) + outputChar('=') + + result.setLen(outputIndex) + +proc encode*[T: SomeInteger|char](s: openarray[T]): string = + ## Encodes `s` into base64 representation. ## ## This procedure encodes an openarray (array or sequence) of either integers ## or characters. ## ## **See also:** - ## * `encode proc<#encode,string,int,string>`_ for encoding a string + ## * `encode proc<#encode,string>`_ for encoding a string ## * `decode proc<#decode,string>`_ for decoding a string runnableExamples: assert encode(['n', 'i', 'm']) == "bmlt" assert encode(@['n', 'i', 'm']) == "bmlt" assert encode([1, 2, 3, 4, 5]) == "AQIDBAU=" - encodeInternal(s, lineLen, newLine) + encodeInternal(s) -proc encode*(s: string, lineLen = 75, newLine = ""): string = - ## Encodes ``s`` into base64 representation. After ``lineLen`` characters, a - ## ``newline`` is added. +proc encode*(s: string): string = + ## Encodes ``s`` into base64 representation. ## ## This procedure encodes a string. ## ## **See also:** - ## * `encode proc<#encode,openArray[T],int,string>`_ for encoding an openarray + ## * `encode proc<#encode,openArray[T]>`_ for encoding an openarray ## * `decode proc<#decode,string>`_ for decoding a string runnableExamples: assert encode("Hello World") == "SGVsbG8gV29ybGQ=" - assert encode("Hello World", 3, "\n") == "SGVs\nbG8g\nV29ybGQ=" - encodeInternal(s, lineLen, newLine) + encodeInternal(s) -proc decodeByte(b: char): int {.inline.} = - case b - of '+': result = ord('>') - of '0'..'9': result = ord(b) + 4 - of 'A'..'Z': result = ord(b) - ord('A') - of 'a'..'z': result = ord(b) - 71 - else: result = 63 +proc encodeMIME*(s: string, lineLen = 75, newLine = "\r\n"): string = + ## Encodes ``s`` into base64 representation as lines. + ## Used in email MIME forma, use ``lineLen`` and ``newline``. + ## + ## This procedure encodes a string according to MIME spec. + ## + ## **See also:** + ## * `encode proc<#encode,string>`_ for encoding a string + ## * `decode proc<#decode,string>`_ for decoding a string + runnableExamples: + assert encodeMIME("Hello World", 4, "\n") == "SGVs\nbG8g\nV29y\nbGQ=" + for i, c in encode(s): + if i != 0 and (i mod lineLen == 0): + result.add(newLine) + result.add(c) + +proc initDecodeTable*(): array[256, char] = + # computes a decode table at compile time + for i in 0 ..< 256: + let ch = char(i) + var code = invalidChar + if ch >= 'A' and ch <= 'Z': code = i - 0x00000041 + if ch >= 'a' and ch <= 'z': code = i - 0x00000047 + if ch >= '0' and ch <= '9': code = i + 0x00000004 + if ch == '+' or ch == '-': code = 0x0000003E + if ch == '/' or ch == '_': code = 0x0000003F + result[i] = char(code) + +const + decodeTable = initDecodeTable() proc decode*(s: string): string = ## Decodes string ``s`` in base64 representation back into its original form. @@ -161,53 +180,58 @@ proc decode*(s: string): string = runnableExamples: assert decode("SGVsbG8gV29ybGQ=") == "Hello World" assert decode(" SGVsbG8gV29ybGQ=") == "Hello World" - const Whitespace = {' ', '\t', '\v', '\r', '\l', '\f'} - var total = ((len(s) + 3) div 4) * 3 - # total is an upper bound, as we will skip arbitrary whitespace: - result = newString(total) + if s.len == 0: return + proc decodeSize(size: int): int = + return (size * 3 div 4) + 6 + + template inputChar(x: untyped) = + let x = int decode_table[ord(s[inputIndex])] + inc inputIndex + if x == invalidChar: + raise newException(ValueError, + "Invalid base64 format character " & repr(s[inputIndex]) & + " at location " & $inputIndex & ".") + + template outputChar(x: untyped) = + result[outputIndex] = char(x and 255) + inc outputIndex + + # pre allocate output string once + result.setLen(decodeSize(s.len)) var - i = 0 - r = 0 - while true: - while i < s.len and s[i] in Whitespace: inc(i) - if i < s.len-3: - let - a = s[i].decodeByte - b = s[i+1].decodeByte - c = s[i+2].decodeByte - d = s[i+3].decodeByte + inputIndex = 0 + outputIndex = 0 + inputLen = s.len + inputEnds = 0 + # strip trailing characters + while s[inputLen - 1] in {'\n', '\r', ' ', '='}: + dec inputLen + # hot loop: read 4 characters at at time + inputEnds = inputLen - 4 + while inputIndex <= inputEnds: + while s[inputIndex] in {'\n', '\r', ' '}: + inc inputIndex + inputChar(a) + inputChar(b) + inputChar(c) + inputChar(d) + outputChar(a shl 2 or b shr 4) + outputChar(b shl 4 or c shr 2) + outputChar(c shl 6 or d shr 0) + # do the last 2 or 3 characters + var leftLen = abs((inputIndex - inputLen) mod 4) + if leftLen == 2: + inputChar(a) + inputChar(b) + outputChar(a shl 2 or b shr 4) + elif leftLen == 3: + inputChar(a) + inputChar(b) + inputChar(c) + outputChar(a shl 2 or b shr 4) + outputChar(b shl 4 or c shr 2) + result.setLen(outputIndex) - result[r] = chr((a shl 2) and 0xff or ((b shr 4) and 0x03)) - result[r+1] = chr((b shl 4) and 0xff or ((c shr 2) and 0x0F)) - result[r+2] = chr((c shl 6) and 0xff or (d and 0x3F)) - inc(r, 3) - inc(i, 4) - else: break - assert i == s.len - # adjust the length: - if i > 0 and s[i-1] == '=': - dec(r) - if i > 1 and s[i-2] == '=': dec(r) - setLen(result, r) -when isMainModule: - assert encode("leasure.") == "bGVhc3VyZS4=" - assert encode("easure.") == "ZWFzdXJlLg==" - assert encode("asure.") == "YXN1cmUu" - assert encode("sure.") == "c3VyZS4=" - const testInputExpandsTo76 = "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++" - const testInputExpands = "++++++++++++++++++++++++++++++" - const longText = """Man is distinguished, not only by his reason, but by this - singular passion from other animals, which is a lust of the mind, - that by a perseverance of delight in the continued and indefatigable - generation of knowledge, exceeds the short vehemence of any carnal - pleasure.""" - const tests = ["", "abc", "xyz", "man", "leasure.", "sure.", "easure.", - "asure.", longText, testInputExpandsTo76, testInputExpands] - - for t in items(tests): - assert decode(encode(t)) == t - assert decode(encode(t, lineLen = 40)) == t - assert decode(encode(t, lineLen = 76)) == t diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index c26d8920c2..430e15c5a1 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -454,7 +454,7 @@ proc generateHeaders(requestUrl: Uri, httpMethod: string, # Proxy auth header. if not proxy.isNil and proxy.auth != "": - let auth = base64.encode(proxy.auth, newline = "") + let auth = base64.encode(proxy.auth) add(result, "Proxy-Authorization: basic " & auth & "\c\L") for key, val in headers: diff --git a/tests/stdlib/tbase64.nim b/tests/stdlib/tbase64.nim new file mode 100644 index 0000000000..9db6e8802a --- /dev/null +++ b/tests/stdlib/tbase64.nim @@ -0,0 +1,44 @@ +discard """ + output: "OK" +""" +import base64 + +proc main() = + doAssert encode("Hello World") == "SGVsbG8gV29ybGQ=" + doAssert encode("leasure.") == "bGVhc3VyZS4=" + doAssert encode("easure.") == "ZWFzdXJlLg==" + doAssert encode("asure.") == "YXN1cmUu" + doAssert encode("sure.") == "c3VyZS4=" + doAssert encode([1,2,3]) == "AQID" + doAssert encode(['h','e','y']) == "aGV5" + + doAssert encode("") == "" + doAssert decode("") == "" + + const testInputExpandsTo76 = "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++" + const testInputExpands = "++++++++++++++++++++++++++++++" + const longText = """Man is distinguished, not only by his reason, but by this + singular passion from other animals, which is a lust of the mind, + that by a perseverance of delight in the continued and indefatigable + generation of knowledge, exceeds the short vehemence of any carnal + pleasure.""" + const tests = ["", "abc", "xyz", "man", "leasure.", "sure.", "easure.", + "asure.", longText, testInputExpandsTo76, testInputExpands] + + doAssert encodeMIME("foobarbaz", lineLen=4) == "Zm9v\r\nYmFy\r\nYmF6" + doAssert decode("Zm9v\r\nYmFy\r\nYmF6") == "foobarbaz" + + for t in items(tests): + doAssert decode(encode(t)) == t + doAssert decode(encodeMIME(t, lineLen=40)) == t + doAssert decode(encodeMIME(t, lineLen=76)) == t + + const invalid = "SGVsbG\x008gV29ybGQ=" + try: + doAssert decode(invalid) == "will throw error" + except ValueError: + discard + + echo "OK" + +main() From 21cbfd72ec9fce04fab98326376651806c8adf0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Thu, 17 Oct 2019 09:55:41 +0200 Subject: [PATCH 36/56] Refactor json macro (#12391) * closes #12316 * make tjsonmacro work at js target * closes #12289 * closes #11988 * also fixed gdb related stuff --- compiler/condsyms.nim | 1 + compiler/types.nim | 13 +- lib/pure/json.nim | 889 +++++------------- lib/pure/sugar.nim | 1 - tests/generics/tforwardgenericconstrained.nim | 73 ++ tests/stdlib/tjsonmacro.nim | 42 +- tests/stdlib/tjsonmacro_reject2.nim | 21 - .../gdb/gdb_pretty_printer_test_output.txt | 2 +- tools/nim-gdb.py | 8 +- 9 files changed, 387 insertions(+), 663 deletions(-) create mode 100644 tests/generics/tforwardgenericconstrained.nim delete mode 100644 tests/stdlib/tjsonmacro_reject2.nim diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index dd4ad3b3a0..7707c1c0d2 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -98,3 +98,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasStyleChecks") defineSymbol("nimToOpenArrayCString") defineSymbol("nimHasUsed") + defineSymbol("nimFixedForwardGeneric") diff --git a/compiler/types.nim b/compiler/types.nim index dc5068d0e2..022995fa39 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1121,9 +1121,16 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = result = sameChildrenAux(a, b, c) and sameFlags(a, b) if result and {ExactGenericParams, ExactTypeDescValues} * c.flags != {}: result = a.sym.position == b.sym.position - of tyGenericInvocation, tyGenericBody, tySequence, - tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyLent, tySink, tyUncheckedArray, - tyArray, tyProc, tyVarargs, tyOrdinal, tyTypeClasses, tyOpt, tyOwned: + of tyBuiltInTypeClass: + assert a.len == 1 + assert a[0].len == 0 + assert b.len == 1 + assert b[0].len == 0 + result = a[0].kind == b[0].kind + of tyGenericInvocation, tyGenericBody, tySequence, tyOpenArray, tySet, tyRef, + tyPtr, tyVar, tyLent, tySink, tyUncheckedArray, tyArray, tyProc, tyVarargs, + tyOrdinal, tyCompositeTypeClass, tyUserTypeClass, tyUserTypeClassInst, + tyAnd, tyOr, tyNot, tyAnything, tyOpt, tyOwned: cycleCheck() if a.kind == tyUserTypeClass and a.n != nil: return a.n == b.n result = sameChildrenAux(a, b, c) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 4dad325bc7..e833f61230 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -833,50 +833,37 @@ proc parseJson(p: var JsonParser): JsonNode = of tkError, tkCurlyRi, tkBracketRi, tkColon, tkComma, tkEof: raiseParseErr(p, "{") -when not defined(js): - iterator parseJsonFragments*(s: Stream, filename: string = ""): JsonNode = - ## Parses from a stream `s` into `JsonNodes`. `filename` is only needed - ## for nice error messages. - ## The JSON fragments are separated by whitespace. This can be substantially - ## faster than the comparable loop - ## ``for x in splitWhitespace(s): yield parseJson(x)``. - ## This closes the stream `s` after it's done. - var p: JsonParser - p.open(s, filename) - try: - discard getTok(p) # read first token - while p.tok != tkEof: - yield p.parseJson() - finally: - p.close() +iterator parseJsonFragments*(s: Stream, filename: string = ""): JsonNode = + ## Parses from a stream `s` into `JsonNodes`. `filename` is only needed + ## for nice error messages. + ## The JSON fragments are separated by whitespace. This can be substantially + ## faster than the comparable loop + ## ``for x in splitWhitespace(s): yield parseJson(x)``. + ## This closes the stream `s` after it's done. + var p: JsonParser + p.open(s, filename) + try: + discard getTok(p) # read first token + while p.tok != tkEof: + yield p.parseJson() + finally: + p.close() - proc parseJson*(s: Stream, filename: string = ""): JsonNode = - ## Parses from a stream `s` into a `JsonNode`. `filename` is only needed - ## for nice error messages. - ## If `s` contains extra data, it will raise `JsonParsingError`. - ## This closes the stream `s` after it's done. - var p: JsonParser - p.open(s, filename) - try: - discard getTok(p) # read first token - result = p.parseJson() - eat(p, tkEof) # check if there is no extra data - finally: - p.close() +proc parseJson*(s: Stream, filename: string = ""): JsonNode = + ## Parses from a stream `s` into a `JsonNode`. `filename` is only needed + ## for nice error messages. + ## If `s` contains extra data, it will raise `JsonParsingError`. + ## This closes the stream `s` after it's done. + var p: JsonParser + p.open(s, filename) + try: + discard getTok(p) # read first token + result = p.parseJson() + eat(p, tkEof) # check if there is no extra data + finally: + p.close() - proc parseJson*(buffer: string): JsonNode = - ## Parses JSON from `buffer`. - ## If `buffer` contains extra data, it will raise `JsonParsingError`. - result = parseJson(newStringStream(buffer), "input") - - proc parseFile*(filename: string): JsonNode = - ## Parses `file` into a `JsonNode`. - ## If `file` contains extra data, it will raise `JsonParsingError`. - var stream = newFileStream(filename, fmRead) - if stream == nil: - raise newException(IOError, "cannot read from file: " & filename) - result = parseJson(stream, filename) -else: +when defined(js): from math import `mod` type JSObject = object @@ -946,38 +933,32 @@ else: result = newJNull() proc parseJson*(buffer: string): JsonNode = - return parseNativeJson(buffer).convertObject() + when nimvm: + return parseJson(newStringStream(buffer), "input") + else: + return parseNativeJson(buffer).convertObject() -# -- Json deserialiser macro. -- +else: + proc parseJson*(buffer: string): JsonNode = + ## Parses JSON from `buffer`. + ## If `buffer` contains extra data, it will raise `JsonParsingError`. + result = parseJson(newStringStream(buffer), "input") -proc createJsonIndexer(jsonNode: NimNode, - index: string | int | NimNode): NimNode - {.compileTime.} = - when index is string: - let indexNode = newStrLitNode(index) - elif index is int: - let indexNode = newIntLitNode(index) - elif index is NimNode: - let indexNode = index + proc parseFile*(filename: string): JsonNode = + ## Parses `file` into a `JsonNode`. + ## If `file` contains extra data, it will raise `JsonParsingError`. + var stream = newFileStream(filename, fmRead) + if stream == nil: + raise newException(IOError, "cannot read from file: " & filename) + result = parseJson(stream, filename) - result = newNimNode(nnkBracketExpr).add( - jsonNode, - indexNode - ) - -proc transformJsonIndexer(jsonNode: NimNode): NimNode = - case jsonNode.kind - of nnkBracketExpr: - result = newNimNode(nnkCurlyExpr) - else: - result = jsonNode.copy() - - for child in jsonNode: - result.add(transformJsonIndexer(child)) +# -- Json deserialiser. -- template verifyJsonKind(node: JsonNode, kinds: set[JsonNodeKind], ast: string) = - if node.kind notin kinds: + if node == nil: + raise newException(KeyError, "key not found: " & ast) + elif node.kind notin kinds: let msg = "Incorrect JSON kind. Wanted '$1' in '$2' but got '$3'." % [ $kinds, ast, @@ -985,588 +966,232 @@ template verifyJsonKind(node: JsonNode, kinds: set[JsonNodeKind], ] raise newException(JsonKindError, msg) -proc getEnum(node: JsonNode, ast: string, T: typedesc): T = - when T is SomeInteger: - # TODO: I shouldn't need this proc. - proc convert[T](x: BiggestInt): T = T(x) - verifyJsonKind(node, {JInt}, ast) - return convert[T](node.getBiggestInt()) - else: - verifyJsonKind(node, {JString}, ast) - return parseEnum[T](node.getStr()) -proc toIdentNode(typeNode: NimNode): NimNode = - ## Converts a Sym type node (returned by getType et al.) into an - ## Ident node. Placing Sym type nodes inside the resulting code AST is - ## unsound (according to @Araq) so this is necessary. - case typeNode.kind - of nnkSym: - return newIdentNode($typeNode) - of nnkBracketExpr: - result = typeNode - for i in 0.. getEnum(`jsonNode`, `kindType`) - result = newCall(bindSym("getEnum"), jsonNode, toStrLit(jsonNode), kindType) + # forward declare all initFromJson -proc createOfBranchCond(ofBranch, getEnumCall: NimNode): NimNode = - ## Creates an expression that acts as the condition for an ``of`` branch. - var cond = newIdentNode("false") - for ofCond in ofBranch: - if ofCond.kind == nnkRecList: - break + proc initFromJson(dst: var string; jsonNode: JsonNode; jsonPath: string) + proc initFromJson(dst: var bool; jsonNode: JsonNode; jsonPath: string) + proc initFromJson(dst: var JsonNode; jsonNode: JsonNode; jsonPath: string) + proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: string) + proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: string) + proc initFromJson[T: enum](dst: var T; jsonNode: JsonNode; jsonPath: string) + proc initFromJson[T](dst: var seq[T]; jsonNode: JsonNode; jsonPath: string) + proc initFromJson[S,T](dst: var array[S,T]; jsonNode: JsonNode; jsonPath: string) + proc initFromJson[T](dst: var Table[string,T];jsonNode: JsonNode; jsonPath: string) + proc initFromJson[T](dst: var OrderedTable[string,T];jsonNode: JsonNode; jsonPath: string) + proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: string) + proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: string) + proc initFromJson[T: distinct](dst: var T;jsonNode: JsonNode; jsonPath: string) + proc initFromJson[T: object|tuple](dst: var T; jsonNode: JsonNode; jsonPath: string) - let comparison = infix(getEnumCall, "==", ofCond) - cond = infix(cond, "or", comparison) + # initFromJson definitions - return cond - -proc processObjField(field, jsonNode: NimNode): seq[NimNode] {.compileTime.} -proc processOfBranch(ofBranch, jsonNode, kindType, - kindJsonNode: NimNode): seq[NimNode] {.compileTime.} = - ## Processes each field inside of an object's ``of`` branch. - ## For each field a new ExprColonExpr node is created and put in the - ## resulting list. - ## - ## Sample ``ofBranch`` AST: - ## - ## .. code-block::plain - ## OfBranch of 0, 1: - ## IntLit 0 foodPos: float - ## IntLit 1 enemyPos: float - ## RecList - ## Sym "foodPos" - ## Sym "enemyPos" - result = @[] - let getEnumCall = createGetEnumCall(kindJsonNode, kindType) - - for branchField in ofBranch[^1]: - let objFields = processObjField(branchField, jsonNode) - - for objField in objFields: - let exprColonExpr = newNimNode(nnkExprColonExpr) - result.add(exprColonExpr) - # Add the name of the field. - exprColonExpr.add(toIdentNode(objField[0])) - - # Add the value of the field. - let cond = createOfBranchCond(ofBranch, getEnumCall) - exprColonExpr.add(newIfStmt( - (cond, objField[1]) - )) - -proc processElseBranch(recCaseNode, elseBranch, jsonNode, kindType, - kindJsonNode: NimNode): seq[NimNode] {.compileTime.} = - ## Processes each field inside of a variant object's ``else`` branch. - ## - ## ..code-block::plain - ## Else - ## RecList - ## Sym "other" - result = @[] - let getEnumCall = createGetEnumCall(kindJsonNode, kindType) - - # We need to build up a list of conditions from each ``of`` branch so that - # we can then negate it to get ``else``. - var cond = newIdentNode("false") - for i in 1 ..< len(recCaseNode): - if recCaseNode[i].kind == nnkElse: - break - - cond = infix(cond, "or", createOfBranchCond(recCaseNode[i], getEnumCall)) - - # Negate the condition. - cond = prefix(cond, "not") - - for branchField in elseBranch[^1]: - let objFields = processObjField(branchField, jsonNode) - - for objField in objFields: - let exprColonExpr = newNimNode(nnkExprColonExpr) - result.add(exprColonExpr) - # Add the name of the field. - exprColonExpr.add(toIdentNode(objField[0])) - - # Add the value of the field. - let ifStmt = newIfStmt((cond, objField[1])) - exprColonExpr.add(ifStmt) - -proc createConstructor(typeSym, jsonNode: NimNode): NimNode {.compileTime.} - -proc detectDistinctType(typeSym: NimNode): NimNode = - let - typeImpl = getTypeImpl(typeSym) - typeInst = getTypeInst(typeSym) - result = if typeImpl.typeKind == ntyDistinct: typeImpl else: typeInst - -proc processObjField(field, jsonNode: NimNode): seq[NimNode] = - ## Process a field from a ``RecList``. - ## - ## The field will typically be a simple ``Sym`` node, but for object variants - ## it may also be a ``RecCase`` in which case things become complicated. - result = @[] - case field.kind - of nnkSym: - # Ordinary field. For example, `name: string`. - let exprColonExpr = newNimNode(nnkExprColonExpr) - result.add(exprColonExpr) - - # Add the field name. - exprColonExpr.add(toIdentNode(field)) - - # Add the field value. - # -> jsonNode["`field`"] - let indexedJsonNode = createJsonIndexer(jsonNode, $field) - let typeNode = detectDistinctType(field) - exprColonExpr.add(createConstructor(typeNode, indexedJsonNode)) - of nnkRecCase: - # A "case" field that introduces a variant. - let exprEqExpr = newNimNode(nnkExprEqExpr) - result.add(exprEqExpr) - - # Add the "case" field name (usually "kind"). - exprEqExpr.add(toIdentNode(field[0])) - - # -> jsonNode["`field[0]`"] - let kindJsonNode = createJsonIndexer(jsonNode, $field[0]) - - # Add the "case" field's value. - let kindType = toIdentNode(getTypeInst(field[0])) - let getEnumSym = bindSym("getEnum") - let astStrLit = toStrLit(kindJsonNode) - let getEnumCall = newCall(getEnumSym, kindJsonNode, astStrLit, kindType) - exprEqExpr.add(getEnumCall) - - # Iterate through each `of` branch. - for i in 1 ..< field.len: - case field[i].kind - of nnkOfBranch: - result.add processOfBranch(field[i], jsonNode, kindType, kindJsonNode) - of nnkElse: - result.add processElseBranch(field, field[i], jsonNode, kindType, kindJsonNode) - else: - doAssert false, "Expected OfBranch or Else node kinds, got: " & $field[i].kind - else: - doAssert false, "Unable to process object field: " & $field.kind - - doAssert result.len > 0 - -proc processFields(obj: NimNode, - jsonNode: NimNode): seq[NimNode] {.compileTime.} = - ## Process all the fields of an ``ObjectTy`` and any of its - ## parent type's fields (via inheritance). - result = @[] - case obj.kind - of nnkObjectTy: - expectKind(obj[2], nnkRecList) - for field in obj[2]: - let nodes = processObjField(field, jsonNode) - result.add(nodes) - - # process parent type fields - case obj[1].kind - of nnkBracketExpr: - assert $obj[1][0] == "ref" - result.add(processFields(getType(obj[1][1]), jsonNode)) - of nnkSym: - result.add(processFields(getType(obj[1]), jsonNode)) + proc initFromJson(dst: var string; jsonNode: JsonNode; jsonPath: string) = + verifyJsonKind(jsonNode, {JString, JNull}, jsonPath) + # since strings don't have a nil state anymore, this mapping of + # JNull to the default string is questionable. `none(string)` and + # `some("")` have the same potentional json value `JNull`. + if jsonNode.kind == JNull: + dst = "" else: + dst = jsonNode.str + + proc initFromJson(dst: var bool; jsonNode: JsonNode; jsonPath: string) = + verifyJsonKind(jsonNode, {JBool}, jsonPath) + dst = jsonNode.bval + + proc initFromJson(dst: var JsonNode; jsonNode: JsonNode; jsonPath: string) = + dst = jsonNode.copy + + proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: string) = + verifyJsonKind(jsonNode, {JInt}, jsonPath) + dst = T(jsonNode.num) + + proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: string) = + verifyJsonKind(jsonNode, {JInt, JFloat}, jsonPath) + if jsonNode.kind == JFloat: + dst = T(jsonNode.fnum) + else: + dst = T(jsonNode.num) + + proc initFromJson[T: enum](dst: var T; jsonNode: JsonNode; jsonPath: string) = + verifyJsonKind(jsonNode, {JString}, jsonPath) + dst = parseEnum[T](jsonNode.getStr) + + proc initFromJson[T](dst: var seq[T]; jsonNode: JsonNode; jsonPath: string) = + verifyJsonKind(jsonNode, {JArray}, jsonPath) + dst.setLen jsonNode.len + for i in 0 ..< jsonNode.len: + initFromJson(dst[i], jsonNode[i], jsonPath & "[" & $i & "]") + + proc initFromJson[S,T](dst: var array[S,T]; jsonNode: JsonNode; jsonPath: string) = + verifyJsonKind(jsonNode, {JArray}, jsonPath) + for i in 0 ..< jsonNode.len: + initFromJson(dst[i], jsonNode[i], jsonPath & "[" & $i & "]") + + proc initFromJson[T](dst: var Table[string,T];jsonNode: JsonNode; jsonPath: string) = + dst = initTable[string, T]() + verifyJsonKind(jsonNode, {JObject}, jsonPath) + for key in keys(jsonNode.fields): + initFromJson(mgetOrPut(dst, key, default(T)), jsonNode[key], jsonPath & "." & key) + + proc initFromJson[T](dst: var OrderedTable[string,T];jsonNode: JsonNode; jsonPath: string) = + dst = initOrderedTable[string,T]() + verifyJsonKind(jsonNode, {JObject}, jsonPath) + for key in keys(jsonNode.fields): + initFromJson(mgetOrPut(dst, key, default(T)), jsonNode[key], jsonPath & "." & key) + + proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: string) = + if jsonNode.kind == JNull: + dst = nil + else: + dst = new(ref T) + initFromJson(dst[], jsonNode, jsonPath) + + proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: string) = + if jsonNode != nil and jsonNode.kind != JNull: + dst = some(default(T)) + initFromJson(dst.get, jsonNode, jsonPath) + + macro assignDistinctImpl[T : distinct](dst: var T;jsonNode: JsonNode; jsonPath: string) = + let typInst = getTypeInst(dst) + let typImpl = getTypeImpl(dst) + let baseTyp = typImpl[0] + result = quote do: + initFromJson( `baseTyp`(`dst`), `jsonNode`, `jsonPath`) + + proc initFromJson[T : distinct](dst: var T; jsonNode: JsonNode; jsonPath: string) = + assignDistinctImpl(dst, jsonNode, jsonPath) + + proc detectIncompatibleType(typeExpr, lineinfoNode: NimNode): void = + if typeExpr.kind == nnkTupleConstr: + error("Use a named tuple instead of: " & typeExpr.repr, lineinfoNode) + + proc foldObjectBody(dst, typeNode, tmpSym, jsonNode, jsonPath: NimNode, depth: int): void {.compileTime.} = + if depth > 150: + error("recursion limit reached", typeNode) + case typeNode.kind + of nnkEmpty: discard - of nnkTupleTy: - for identDefs in obj: - expectKind(identDefs, nnkIdentDefs) - let nodes = processObjField(identDefs[0], jsonNode) - result.add(nodes) - else: - doAssert false, "Unable to process field type: " & $obj.kind + of nnkRecList, nnkTupleTy: + for it in typeNode: + foldObjectBody(dst, it, tmpSym, jsonNode, jsonPath, depth + 1) -proc processType(typeName: NimNode, obj: NimNode, - jsonNode: NimNode, isRef: bool): NimNode {.compileTime.} = - ## Process a type such as ``Sym "float"`` or ``ObjectTy ...``. - ## - ## Sample ``ObjectTy``: - ## - ## .. code-block::plain - ## ObjectTy - ## Empty - ## InheritanceInformation - ## RecList - ## Sym "events" - case obj.kind - of nnkObjectTy, nnkTupleTy: - # Create object constructor. - result = - if obj.kind == nnkObjectTy: newNimNode(nnkObjConstr) - else: newNimNode(nnkPar) + of nnkIdentDefs: + typeNode.expectLen 3 + let fieldSym = typeNode[0] + let fieldNameLit = newLit(fieldSym.strVal) + let fieldType = typeNode[1] - if obj.kind == nnkObjectTy: - result.add(typeName) # Name of the type to construct. + # Detecting incompatiple tuple types in `assignObjectImpl` only + # would be much cleaner, but the ast for tuple types does not + # contain usable type information. + detectIncompatibleType(fieldType, fieldSym) - # Process each object/tuple field and add it as an exprColonExpr - result.add(processFields(obj, jsonNode)) + dst.add quote do: + initFromJson(`tmpSym`.`fieldSym`, getOrDefault(`jsonNode`,`fieldNameLit`), `jsonPath` & "." & `fieldNameLit`) - # Object might be null. So we need to check for that. - if isRef: - result = quote do: - verifyJsonKind(`jsonNode`, {JObject, JNull}, astToStr(`jsonNode`)) - if `jsonNode`.kind == JNull: - nil + of nnkRecCase: + let kindSym = typeNode[0][0] + let kindNameLit = newLit(kindSym.strVal) + let kindType = typeNode[0][1] + let kindOffsetLit = newLit(uint(getOffset(kindSym))) + dst.add quote do: + var kindTmp: `kindType` + initFromJson(kindTmp, `jsonNode`[`kindNameLit`], `jsonPath` & "." & `kindNameLit`) + when defined js: + `tmpSym`.`kindSym` = kindTmp else: - `result` + when nimVm: + `tmpSym`.`kindSym` = kindTmp + else: + # fuck it, assign kind field anyway + ((cast[ptr `kindType`](cast[uint](`tmpSym`.addr) + `kindOffsetLit`))[]) = kindTmp + dst.add nnkCaseStmt.newTree(nnkDotExpr.newTree(tmpSym, kindSym)) + for i in 1 ..< typeNode.len: + foldObjectBody(dst, typeNode[i], tmpSym, jsonNode, jsonPath, depth + 1) + + of nnkOfBranch, nnkElse: + let ofBranch = newNimNode(typeNode.kind) + for i in 0 ..< typeNode.len-1: + ofBranch.add copyNimTree(typeNode[i]) + let dstInner = newNimNode(nnkStmtListExpr) + foldObjectBody(dstInner, typeNode[^1], tmpSym, jsonNode, jsonPath, depth + 1) + # resOuter now contains the inner stmtList + ofBranch.add dstInner + dst[^1].expectKind nnkCaseStmt + dst[^1].add ofBranch + + of nnkObjectTy: + typeNode[0].expectKind nnkEmpty + typeNode[1].expectKind {nnkEmpty, nnkOfInherit} + if typeNode[1].kind == nnkOfInherit: + let base = typeNode[1][0] + var impl = getTypeImpl(base) + while impl.kind in {nnkRefTy, nnkPtrTy}: + impl = getTypeImpl(impl[0]) + foldObjectBody(dst, impl, tmpSym, jsonNode, jsonPath, depth + 1) + let body = typeNode[2] + foldObjectBody(dst, body, tmpSym, jsonNode, jsonPath, depth + 1) + else: - result = quote do: - verifyJsonKind(`jsonNode`, {JObject}, astToStr(`jsonNode`)); - `result` + error("unhandled kind: " & $typeNode.kind, typeNode) - of nnkEnumTy: - let instType = toIdentNode(getTypeInst(typeName)) - let getEnumCall = createGetEnumCall(jsonNode, instType) - result = quote do: - ( - `getEnumCall` - ) - of nnkSym: - let name = normalize($typeName.getTypeImpl()) - case name - of "string": - result = quote do: - ( - verifyJsonKind(`jsonNode`, {JString, JNull}, astToStr(`jsonNode`)); - if `jsonNode`.kind == JNull: "" else: `jsonNode`.str - ) - of "biggestint": - result = quote do: - ( - verifyJsonKind(`jsonNode`, {JInt}, astToStr(`jsonNode`)); - `jsonNode`.num - ) - of "bool": - result = quote do: - ( - verifyJsonKind(`jsonNode`, {JBool}, astToStr(`jsonNode`)); - `jsonNode`.bval - ) + + macro assignObjectImpl[T](dst: var T; jsonNode: JsonNode; jsonPath: string) = + let typeSym = getTypeInst(dst) + result = newStmtList() + if typeSym.kind in {nnkTupleTy, nnkTupleConstr}: + # both, `dst` and `typeSym` don't have good lineinfo. But nothing + # else is available here. + detectIncompatibleType(typeSym, dst) + foldObjectBody(result, typeSym, dst, jsonNode, jsonPath, 0) else: - if name.startsWith("int") or name.startsWith("uint"): - result = quote do: - ( - verifyJsonKind(`jsonNode`, {JInt}, astToStr(`jsonNode`)); - `jsonNode`.num.`obj` - ) - elif name.startsWith("float"): - result = quote do: - ( - verifyJsonKind(`jsonNode`, {JInt, JFloat}, astToStr(`jsonNode`)); - if `jsonNode`.kind == JFloat: `jsonNode`.fnum.`obj` else: `jsonNode`.num.`obj` - ) - else: - doAssert false, "Unable to process nnkSym " & $typeName - else: - doAssert false, "Unable to process type: " & $obj.kind + foldObjectBody(result, typeSym.getTypeImpl, dst, jsonNode, jsonPath, 0) - doAssert(not result.isNil(), "processType not initialised.") + proc initFromJson[T : object|tuple](dst: var T; jsonNode: JsonNode; jsonPath: string) = + assignObjectImpl(dst, jsonNode, jsonPath) -import options -proc workaroundMacroNone[T](): Option[T] = - none(T) + proc to*[T](node: JsonNode, t: typedesc[T]): T = + ## `Unmarshals`:idx: the specified node into the object type specified. + ## + ## Known limitations: + ## + ## * Heterogeneous arrays are not supported. + ## * Sets in object variants are not supported. + ## * Not nil annotations are not supported. + ## + ## Example: + ## + ## .. code-block:: Nim + ## let jsonNode = parseJson(""" + ## { + ## "person": { + ## "name": "Nimmer", + ## "age": 21 + ## }, + ## "list": [1, 2, 3, 4] + ## } + ## """) + ## + ## type + ## Person = object + ## name: string + ## age: int + ## + ## Data = object + ## person: Person + ## list: seq[int] + ## + ## var data = to(jsonNode, Data) + ## doAssert data.person.name == "Nimmer" + ## doAssert data.person.age == 21 + ## doAssert data.list == @[1, 2, 3, 4] -proc depth(n: NimNode, current = 0): int = - result = 1 - for child in n: - let d = 1 + child.depth(current + 1) - if d > result: - result = d - -proc createConstructor(typeSym, jsonNode: NimNode): NimNode = - ## Accepts a type description, i.e. "ref Type", "seq[Type]", "Type" etc. - ## - ## The ``jsonNode`` refers to the node variable that we are deserialising. - ## - ## Returns an object constructor node. - # echo("--createConsuctor-- \n", treeRepr(typeSym)) - # echo() - - if depth(jsonNode) > 150: - error("The `to` macro does not support ref objects with cycles.", jsonNode) - - case typeSym.kind - of nnkBracketExpr: - var bracketName = ($typeSym[0]).normalize - case bracketName - of "option": - # TODO: Would be good to verify that this is Option[T] from - # options module I suppose. - let lenientJsonNode = transformJsonIndexer(jsonNode) - - let optionGeneric = typeSym[1] - let value = createConstructor(typeSym[1], jsonNode) - let workaround = bindSym("workaroundMacroNone") # TODO: Nim Bug: This shouldn't be necessary. - - result = quote do: - ( - if `lenientJsonNode`.isNil or `jsonNode`.kind == JNull: `workaround`[`optionGeneric`]() else: some[`optionGeneric`](`value`) - ) - of "table", "orderedtable": - let tableKeyType = typeSym[1] - if ($tableKeyType).cmpIgnoreStyle("string") != 0: - error("JSON doesn't support keys of type " & $tableKeyType) - let tableValueType = typeSym[2] - - let forLoopKey = genSym(nskForVar, "key") - let indexerNode = createJsonIndexer(jsonNode, forLoopKey) - let constructorNode = createConstructor(tableValueType, indexerNode) - - let tableInit = - if bracketName == "table": - bindSym("initTable") - else: - bindSym("initOrderedTable") - - # Create a statement expression containing a for loop. - result = quote do: - ( - var map = `tableInit`[`tableKeyType`, `tableValueType`](); - verifyJsonKind(`jsonNode`, {JObject}, astToStr(`jsonNode`)); - for `forLoopKey` in keys(`jsonNode`.fields): map[ - `forLoopKey`] = `constructorNode`; - map - ) - of "ref": - # Ref type. - var typeName = $typeSym[1] - # Remove the `:ObjectType` suffix. - if typeName.endsWith(":ObjectType"): - typeName = typeName[0 .. ^12] - - let obj = getType(typeSym[1]) - result = processType(newIdentNode(typeName), obj, jsonNode, true) - of "range": - let typeNode = typeSym - # Deduce the base type from one of the endpoints - let baseType = getType(typeNode[1]) - - result = createConstructor(baseType, jsonNode) - of "seq": - let seqT = typeSym[1] - let forLoopI = genSym(nskForVar, "i") - let indexerNode = createJsonIndexer(jsonNode, forLoopI) - let constructorNode = createConstructor(detectDistinctType(seqT), indexerNode) - - # Create a statement expression containing a for loop. - result = quote do: - ( - var list: `typeSym` = @[]; - verifyJsonKind(`jsonNode`, {JArray}, astToStr(`jsonNode`)); - for `forLoopI` in 0 ..< `jsonNode`.len: list.add(`constructorNode`); - list - ) - of "array": - let arrayT = typeSym[2] - let forLoopI = genSym(nskForVar, "i") - let indexerNode = createJsonIndexer(jsonNode, forLoopI) - let constructorNode = createConstructor(arrayT, indexerNode) - - # Create a statement expression containing a for loop. - result = quote do: - ( - var list: `typeSym`; - verifyJsonKind(`jsonNode`, {JArray}, astToStr(`jsonNode`)); - for `forLoopI` in 0 ..< `jsonNode`.len: list[ - `forLoopI`] = `constructorNode`; - list - ) - of "tuple": - let typeNode = getTypeImpl(typeSym) - result = createConstructor(typeNode, jsonNode) - else: - # Generic type or some `seq[T]` alias - let obj = getType(typeSym) - case obj.kind - of nnkBracketExpr: - # probably a `seq[T]` alias - let typeNode = getTypeImpl(typeSym) - result = createConstructor(typeNode, jsonNode) - else: - # generic type - result = processType(typeSym, obj, jsonNode, false) - of nnkSym: - # Handle JsonNode. - if ($typeSym).cmpIgnoreStyle("jsonnode") == 0: - return jsonNode - - # Handle all other types. - let obj = getType(typeSym) - let typeNode = getTypeImpl(typeSym) - if typeNode.typeKind == ntyDistinct: - result = createConstructor(typeNode, jsonNode) - elif obj.kind == nnkBracketExpr: - # When `Sym "Foo"` turns out to be a `ref object` or `tuple` - result = createConstructor(obj, jsonNode) - else: - result = processType(typeSym, obj, jsonNode, false) - of nnkTupleTy: - result = processType(typeSym, typeSym, jsonNode, false) - of nnkPar, nnkTupleConstr: - # TODO: The fact that `jsonNode` here works to give a good line number - # is weird. Specifying typeSym should work but doesn't. - error("Use a named tuple instead of: " & $toStrLit(typeSym), jsonNode) - of nnkDistinctTy: - var baseType = typeSym - # solve nested distinct types - while baseType.typeKind == ntyDistinct: - let impl = getTypeImpl(baseType[0]) - if impl.typeKind != ntyDistinct: - baseType = baseType[0] - break - baseType = impl - let ret = createConstructor(baseType, jsonNode) - let typeInst = getTypeInst(typeSym) - result = quote do: - ( - `typeInst`(`ret`) - ) - else: - doAssert false, "Unable to create constructor for: " & $typeSym.kind - - doAssert(not result.isNil(), "Constructor not initialised.") - -proc postProcess(node: NimNode): NimNode -proc postProcessValue(value: NimNode): NimNode = - ## Looks for object constructors and calls the ``postProcess`` procedure - ## on them. Otherwise it just returns the node as-is. - case value.kind - of nnkObjConstr: - result = postProcess(value) - else: - result = value - for i in 0 ..< len(result): - result[i] = postProcessValue(result[i]) - -proc postProcessExprColonExpr(exprColonExpr, resIdent: NimNode): NimNode = - ## Transform each field mapping in the ExprColonExpr into a simple - ## field assignment. Special processing is performed if the field mapping - ## has an if statement. - ## - ## ..code-block::plain - ## field: (if true: 12) -> if true: `resIdent`.field = 12 - expectKind(exprColonExpr, nnkExprColonExpr) - let fieldName = exprColonExpr[0] - let fieldValue = exprColonExpr[1] - case fieldValue.kind - of nnkIfStmt: - doAssert fieldValue.len == 1, "Cannot postProcess two ElifBranches." - expectKind(fieldValue[0], nnkElifBranch) - - let cond = fieldValue[0][0] - let bodyValue = postProcessValue(fieldValue[0][1]) - doAssert(bodyValue.kind != nnkNilLit) - result = - quote do: - if `cond`: - `resIdent`.`fieldName` = `bodyValue` - else: - let fieldValue = postProcessValue(fieldValue) - doAssert(fieldValue.kind != nnkNilLit) - result = - quote do: - `resIdent`.`fieldName` = `fieldValue` - - -proc postProcess(node: NimNode): NimNode = - ## The ``createConstructor`` proc creates a ObjConstr node which contains - ## if statements for fields that may not be assignable (due to an object - ## variant). Nim doesn't handle this, but may do in the future. - ## - ## For simplicity, we post process the object constructor into multiple - ## assignments. - ## - ## For example: - ## - ## ..code-block::plain - ## Object( (var res = Object(); - ## field: if true: 12 -> if true: res.field = 12; - ## ) res) - result = newNimNode(nnkStmtListExpr) - - expectKind(node, nnkObjConstr) - - # Create the type. - # -> var res = Object() - var resIdent = genSym(nskVar, "res") - var resType = node[0] - - var objConstr = newTree(nnkObjConstr, resType) - result.add newVarStmt(resIdent, objConstr) - - # Process each ExprColonExpr. - for i in 1.. Date: Thu, 17 Oct 2019 06:37:08 -0300 Subject: [PATCH 37/56] Improve jsconsole adding the rest of the stable api as documented on the standard at https://developer.mozilla.org/docs/Web/API/Console (#12440) --- lib/js/jsconsole.nim | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/js/jsconsole.nim b/lib/js/jsconsole.nim index d9ced95f09..617cbebf1b 100644 --- a/lib/js/jsconsole.nim +++ b/lib/js/jsconsole.nim @@ -24,6 +24,7 @@ proc logImpl(console: Console) {.importcpp: "log", varargs.} proc debugImpl(console: Console) {.importcpp: "debug", varargs.} proc infoImpl(console: Console) {.importcpp: "info", varargs.} proc errorImpl(console: Console) {.importcpp: "error", varargs.} +proc warnImpl(console: Console) {.importcpp: "warn", varargs.} proc makeConsoleCall(console: NimNode, procName: NimNode, args: NimNode): NimNode = result = newCall(procName, console) @@ -41,4 +42,28 @@ macro info*(console: Console, args: varargs[RootRef, convertToConsoleLoggable]): macro error*(console: Console, args: varargs[RootRef, convertToConsoleLoggable]): untyped = makeConsoleCall(console, bindSym "errorImpl", args) -var console* {.importc, nodecl.}: Console \ No newline at end of file + +macro warn*(console: Console, args: varargs[RootRef, convertToConsoleLoggable]): untyped = + ## https://developer.mozilla.org/en-US/docs/Web/API/Console/warn + makeConsoleCall(console, bindSym "warnImpl", args) + +proc clear*(console: Console) {.importcpp: "clear".} ## https://developer.mozilla.org/en-US/docs/Web/API/Console/clear + +proc count*(console: Console, label = "".cstring) {.importcpp: "count".} ## https://developer.mozilla.org/en-US/docs/Web/API/Console/count + +proc countReset*(console: Console, label = "".cstring) {.importcpp: "countReset".} ## https://developer.mozilla.org/en-US/docs/Web/API/Console/countReset + +proc group*(console: Console, label = "".cstring) {.importcpp: "group".} ## https://developer.mozilla.org/en-US/docs/Web/API/Console/group + +proc groupCollapsed*(console: Console, label = "".cstring) {.importcpp: "groupCollapsed".} ## https://developer.mozilla.org/en-US/docs/Web/API/Console/groupCollapsed + +proc groupEnd*(console: Console) {.importcpp: "groupEnd".} ## https://developer.mozilla.org/en-US/docs/Web/API/Console/groupEnd + +proc time*(console: Console, label = "".cstring) {.importcpp: "time".} ## https://developer.mozilla.org/en-US/docs/Web/API/Console/time + +proc timeEnd*(console: Console, label = "".cstring) {.importcpp: "timeEnd".} ## https://developer.mozilla.org/en-US/docs/Web/API/Console/timeEnd + +proc timeLog*(console: Console, label = "".cstring) {.importcpp: "timeLog".} ## https://developer.mozilla.org/en-US/docs/Web/API/Console/timeLog + + +var console* {.importc, nodecl.}: Console From 2cfd58de48668d4827c86d70f1ee6d5872f7c654 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Thu, 17 Oct 2019 06:37:55 -0300 Subject: [PATCH 38/56] Fix #10804 (#12438) --- doc/manual.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 5f45970b10..b8c976edbe 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -3511,7 +3511,7 @@ for details on how to change this behavior. Anonymous Procs --------------- -Unnamed procedures can be used as lambda expressions to pass into other +Unnamed procedures can be used as lambda expressions to pass into other procedures: .. code-block:: nim @@ -3522,8 +3522,8 @@ procedures: Procs as expressions can appear both as nested procs and inside top level -executable code. The `sugar `_ module contains the `=>` macro -which enables a more succinct syntax for anonymous procedures resembling +executable code. The `sugar `_ module contains the `=>` macro +which enables a more succinct syntax for anonymous procedures resembling lambdas as they are in languages like JavaScript, C#, etc. @@ -3696,7 +3696,7 @@ type. method eval(e: Expression): int {.base.} = # override this base method - quit "to override!" + raise newException(CatchableError, "Method without implementation override") method eval(e: Literal): int = return e.x From 4d1f69c7d253ad9dbe9681062eb650acc9ff5d22 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Thu, 17 Oct 2019 06:39:01 -0300 Subject: [PATCH 39/56] Fixes #10824 (#12437) --- doc/manual.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/doc/manual.rst b/doc/manual.rst index b8c976edbe..e1c650a93d 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -6224,6 +6224,25 @@ but are used to override the settings temporarily. Example: # ... some code ... {.pop.} # restore old settings +`push/pop`:idx: can switch on/off some standard library pragmas, example: + +.. code-block:: nim + {.push inline.} + proc thisIsInlined(): int = 42 + func willBeInlined(): float = 42.0 + {.pop.} + proc notInlined(): int = 9 + + {.push discardable, boundChecks: off, compileTime, noSideEffect, experimental.} + template example(): string = "https://nim-lang.org" + {.pop.} + + {.push deprecated, hint[LineTooLong]: off, used, stackTrace: off.} + proc sample(): bool = true + {.pop.} + +For third party pragmas it depends on its implementation, but uses the same syntax. + register pragma --------------- From 81125e2029fdd0d3a9c2931b066bfb72406a21ae Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 17 Oct 2019 20:02:59 +0200 Subject: [PATCH 40/56] [backport] add back a check that got accidentically removed; fixes #12379 (#12444) --- compiler/semtypes.nim | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 896db5c3c6..186161169c 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -635,6 +635,12 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int, errorUndeclaredIdentifier(c, n.sons[0].info, typ.sym.name.s) elif not isOrdinalType(typ): localError(c.config, n.sons[0].info, "selector must be of an ordinal type, float or string") + elif firstOrd(c.config, typ) != 0: + localError(c.config, n.info, "low(" & $a.sons[0].sym.name.s & + ") must be 0 for discriminant") + elif lengthOrd(c.config, typ) > 0x00007FFF: + localError(c.config, n.info, "len($1) must be less than 32768" % a.sons[0].sym.name.s) + for i in 1 ..< len(n): var b = copyTree(n.sons[i]) addSon(a, b) From a5ab502f08d11be807c663a9d586b4a4768772dc Mon Sep 17 00:00:00 2001 From: Miran Date: Thu, 17 Oct 2019 22:13:00 +0200 Subject: [PATCH 41/56] [backport] fix type's case in random.nim (#12445) --- lib/pure/random.nim | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/pure/random.nim b/lib/pure/random.nim index b10bc43c82..72e9f91f07 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -84,11 +84,11 @@ include "system/inclrtl" {.push debugger: off.} when defined(JS): - type ui = uint32 + type Ui = uint32 const randMax = 4_294_967_295u32 else: - type ui = uint64 + type Ui = uint64 const randMax = 18_446_744_073_709_551_615u64 @@ -106,7 +106,7 @@ type ## Many procs have two variations: one that takes in a Rand parameter and ## another that uses the default generator. The procs that use the default ## generator are **not** thread-safe! - a0, a1: ui + a0, a1: Ui when defined(JS): var state = Rand( @@ -118,8 +118,8 @@ else: a0: 0x69B4C98CB8530805u64, a1: 0xFED1DD3004688D67CAu64) # global for backwards compatibility -proc rotl(x, k: ui): ui = - result = (x shl k) or (x shr (ui(64) - k)) +proc rotl(x, k: Ui): Ui = + result = (x shl k) or (x shr (Ui(64) - k)) proc next*(r: var Rand): uint64 = ## Computes a random ``uint64`` number using the given state. @@ -195,11 +195,11 @@ proc skipRandomNumbers*(s: var Rand) = else: const helper = [0xbeac0467eba5facbu64, 0xd86b048b86aa9922u64] var - s0 = ui 0 - s1 = ui 0 + s0 = Ui 0 + s1 = Ui 0 for i in 0..high(helper): for b in 0 ..< 64: - if (helper[i] and (ui(1) shl ui(b))) != 0: + if (helper[i] and (Ui(1) shl Ui(b))) != 0: s0 = s0 xor s.a0 s1 = s1 xor s.a1 discard next(s) @@ -210,7 +210,7 @@ proc random*(max: int): int {.benign, deprecated: "Deprecated since v0.18.0; use 'rand' instead".} = while true: let x = next(state) - if x < randMax - (randMax mod ui(max)): + if x < randMax - (randMax mod Ui(max)): return int(x mod uint64(max)) proc random*(max: float): float {.benign, deprecated: @@ -247,7 +247,7 @@ proc rand*(r: var Rand; max: Natural): int {.benign.} = if max == 0: return while true: let x = next(r) - if x <= randMax - (randMax mod ui(max)): + if x <= randMax - (randMax mod Ui(max)): return int(x mod (uint64(max)+1u64)) proc rand*(max: int): int {.benign.} = @@ -570,8 +570,8 @@ proc initRand*(seed: int64): Rand = let now = getTime() var r2 = initRand(now.toUnix * 1_000_000_000 + now.nanosecond) doAssert seed != 0 # 0 causes `rand(int)` to always return 0 for example. - result.a0 = ui(seed shr 16) - result.a1 = ui(seed and 0xffff) + result.a0 = Ui(seed shr 16) + result.a1 = Ui(seed and 0xffff) discard next(result) proc randomize*(seed: int64) {.benign.} = From 0a6e0a3f388985f455e88604576ffe4f36e93579 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Fri, 18 Oct 2019 07:16:01 -0300 Subject: [PATCH 42/56] Improve htmlgen (#12452) --- changelog.md | 2 +- lib/pure/htmlgen.nim | 194 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 22b0b130d6..657354fe6f 100644 --- a/changelog.md +++ b/changelog.md @@ -24,7 +24,7 @@ ## Library changes - `base64.encode` and `base64.decode` was made faster by about 50%. - +- `htmlgen` adds [MathML](https://wikipedia.org/wiki/MathML) support (ISO 40314). ## Language additions diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim index 3a1ed23065..ebd46df532 100644 --- a/lib/pure/htmlgen.nim +++ b/lib/pure/htmlgen.nim @@ -19,6 +19,14 @@ ## generator. Each commonly used HTML tag has a corresponding macro ## that generates a string with its HTML representation. ## +## MathML +## ====== +## +## `MathML `_ is supported, MathML is part of HTML5. +## `MathML `_ is an Standard ISO/IEC 40314 from year 2015. +## MathML allows you to `draw advanced math on the web `_, +## `visually similar to Latex math. `_ +## ## Examples ## ======== ## @@ -608,9 +616,195 @@ macro wbr*(e: varargs[untyped]): untyped = ## generates the HTML ``wbr`` element. result = xmlCheckedTag(e, "wbr", commonAttr, "", true) + +macro math*(e: varargs[untyped]): untyped = + ## Generates the HTML ``math`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/math#Examples + result = xmlCheckedTag(e, "math", "mathbackground mathcolor href overflow" & commonAttr) + +macro maction*(e: varargs[untyped]): untyped = + ## Generates the HTML ``maction`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/maction + result = xmlCheckedTag(e, "maction", "mathbackground mathcolor href" & commonAttr) + +macro menclose*(e: varargs[untyped]): untyped = + ## Generates the HTML ``menclose`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/menclose + result = xmlCheckedTag(e, "menclose", "mathbackground mathcolor href notation" & commonAttr) + +macro merror*(e: varargs[untyped]): untyped = + ## Generates the HTML ``merror`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/merror + result = xmlCheckedTag(e, "merror", "mathbackground mathcolor href" & commonAttr) + +macro mfenced*(e: varargs[untyped]): untyped = + ## Generates the HTML ``mfenced`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mfenced + result = xmlCheckedTag(e, "mfenced", "mathbackground mathcolor href open separators" & commonAttr) + +macro mfrac*(e: varargs[untyped]): untyped = + ## Generates the HTML ``mfrac`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mfrac + result = xmlCheckedTag(e, "mfrac", "mathbackground mathcolor href linethickness numalign" & commonAttr) + +macro mglyph*(e: varargs[untyped]): untyped = + ## Generates the HTML ``mglyph`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mglyph + result = xmlCheckedTag(e, "mglyph", "mathbackground mathcolor href src valign" & commonAttr) + +macro mi*(e: varargs[untyped]): untyped = + ## Generates the HTML ``mi`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mi + result = xmlCheckedTag(e, "mi", "mathbackground mathcolor href mathsize mathvariant" & commonAttr) + +macro mlabeledtr*(e: varargs[untyped]): untyped = + ## Generates the HTML ``mlabeledtr`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mlabeledtr + result = xmlCheckedTag(e, "mlabeledtr", "mathbackground mathcolor href columnalign groupalign rowalign" & commonAttr) + +macro mmultiscripts*(e: varargs[untyped]): untyped = + ## Generates the HTML ``mmultiscripts`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mmultiscripts + result = xmlCheckedTag(e, "mmultiscripts", "mathbackground mathcolor href subscriptshift superscriptshift" & commonAttr) + +macro mn*(e: varargs[untyped]): untyped = + ## Generates the HTML ``mn`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mn + result = xmlCheckedTag(e, "mn", "mathbackground mathcolor href mathsize mathvariant" & commonAttr) + +macro mo*(e: varargs[untyped]): untyped = + ## Generates the HTML ``mo`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mo + result = xmlCheckedTag(e, "mo", + "mathbackground mathcolor fence form largeop lspace mathsize mathvariant movablelimits rspace separator stretchy symmetric" & commonAttr) + +macro mover*(e: varargs[untyped]): untyped = + ## Generates the HTML ``mover`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mover + result = xmlCheckedTag(e, "mover", "mathbackground mathcolor accent href" & commonAttr) + +macro mpadded*(e: varargs[untyped]): untyped = + ## Generates the HTML ``mpadded`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mpadded + result = xmlCheckedTag(e, "mpadded", "mathbackground mathcolor depth href lspace voffset" & commonAttr) + +macro mphantom*(e: varargs[untyped]): untyped = + ## Generates the HTML ``mphantom`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mphantom + result = xmlCheckedTag(e, "mphantom", "mathbackground" & commonAttr) + +macro mroot*(e: varargs[untyped]): untyped = + ## Generates the HTML ``mroot`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mroot + result = xmlCheckedTag(e, "mroot", "mathbackground mathcolor href" & commonAttr) + +macro mrow*(e: varargs[untyped]): untyped = + ## Generates the HTML ``mrow`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mrow + result = xmlCheckedTag(e, "mrow", "mathbackground mathcolor href" & commonAttr) + +macro ms*(e: varargs[untyped]): untyped = + ## Generates the HTML ``ms`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/ms + result = xmlCheckedTag(e, "ms", "mathbackground mathcolor href lquote mathsize mathvariant rquote" & commonAttr) + +macro mspace*(e: varargs[untyped]): untyped = + ## Generates the HTML ``mspace`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mspace + result = xmlCheckedTag(e, "mspace", "mathbackground mathcolor href linebreak" & commonAttr) + +macro msqrt*(e: varargs[untyped]): untyped = + ## Generates the HTML ``msqrt`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/msqrt + result = xmlCheckedTag(e, "msqrt", "mathbackground mathcolor href" & commonAttr) + +macro mstyle*(e: varargs[untyped]): untyped = + ## Generates the HTML ``mstyle`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mstyle + result = xmlCheckedTag(e, "mstyle", ("mathbackground mathcolor href decimalpoint displaystyle " & + "infixlinebreakstyle scriptlevel scriptminsize scriptsizemultiplier" & commonAttr)) + +macro msub*(e: varargs[untyped]): untyped = + ## Generates the HTML ``msub`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/msub + result = xmlCheckedTag(e, "msub", "mathbackground mathcolor href subscriptshift" & commonAttr) + +macro msubsup*(e: varargs[untyped]): untyped = + ## Generates the HTML ``msubsup`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/msubsup + result = xmlCheckedTag(e, "msubsup", "mathbackground mathcolor href subscriptshift superscriptshift" & commonAttr) + +macro msup*(e: varargs[untyped]): untyped = + ## Generates the HTML ``msup`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/msup + result = xmlCheckedTag(e, "msup", "mathbackground mathcolor href superscriptshift" & commonAttr) + +macro mtable*(e: varargs[untyped]): untyped = + ## Generates the HTML ``mtable`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mtable + result = xmlCheckedTag(e, "mtable", ("mathbackground mathcolor href align " & + "alignmentscope columnalign columnlines columnspacing columnwidth " & + "displaystyle equalcolumns equalrows frame framespacing groupalign " & + "rowalign rowlines rowspacing side width" & commonAttr)) + +macro mtd*(e: varargs[untyped]): untyped = + ## Generates the HTML ``mtd`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mtd + result = xmlCheckedTag(e, "mtd", + "mathbackground mathcolor href columnalign columnspan groupalign rowalign rowspan" & commonAttr) + +macro mtext*(e: varargs[untyped]): untyped = + ## Generates the HTML ``mtext`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mtext + result = xmlCheckedTag(e, "mtext", "mathbackground mathcolor href mathsize mathvariant" & commonAttr) + +macro munder*(e: varargs[untyped]): untyped = + ## Generates the HTML ``munder`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/munder + result = xmlCheckedTag(e, "munder", "mathbackground mathcolor href accentunder align" & commonAttr) + +macro munderover*(e: varargs[untyped]): untyped = + ## Generates the HTML ``munderover`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/munderover + result = xmlCheckedTag(e, "munderover", "mathbackground mathcolor href accentunder accent align" & commonAttr) + +macro semantics*(e: varargs[untyped]): untyped = + ## Generates the HTML ``semantics`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/semantics + result = xmlCheckedTag(e, "semantics", "mathbackground mathcolor href definitionURL encoding cd src" & commonAttr) + +macro annotation*(e: varargs[untyped]): untyped = + ## Generates the HTML ``annotation`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/semantics + result = xmlCheckedTag(e, "annotation", "mathbackground mathcolor href definitionURL encoding cd src" & commonAttr) + +macro `annotation-xml`*(e: varargs[untyped]): untyped = + ## Generates the HTML ``annotation-xml`` element. MathML https://wikipedia.org/wiki/MathML + ## https://developer.mozilla.org/en-US/docs/Web/MathML/Element/semantics + result = xmlCheckedTag(e, "annotation", "mathbackground mathcolor href definitionURL encoding cd src" & commonAttr) + + runnableExamples: let nim = "Nim" assert h1(a(href = "https://nim-lang.org", nim)) == """

      Nim

      """ assert form(action = "test", `accept-charset` = "Content-Type") == """
      """ + + + assert math( + semantics( + mrow( + msup( + mi("x"), + mn("42") + ) + ) + ) + ) == "x42" + + assert math( + semantics( + annotation(encoding = "application/x-tex", title = "Latex on Web", r"x^{2} + y") + ) + ) == """x^{2} + y""" From 4a0debfe8712d075d69284429dba7475a608488d Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Fri, 18 Oct 2019 09:13:55 -0300 Subject: [PATCH 43/56] Add no-ident for GCC when -d:release (#12454) --- compiler/extccomp.nim | 6 +++--- config/nim.cfg | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index c06ade3a54..6aa14f4a4d 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -63,8 +63,8 @@ compiler gcc: result = ( name: "gcc", objExt: "o", - optSpeed: " -O3 ", - optSize: " -Os ", + optSpeed: " -O3 -fno-ident", + optSize: " -Os -fno-ident", compilerExe: "gcc", cppCompiler: "g++", compileTmpl: "-c $options $include -o $objfile $file", @@ -664,7 +664,7 @@ proc addExternalFileToCompile*(conf: ConfigRef; c: var Cfile) = c.flags.incl CfileFlag.Cached else: # make sure Nim keeps recompiling the external file on reruns - # if compilation is not successful + # if compilation is not successful discard tryRemoveFile(c.obj.string) conf.toCompile.add(c) diff --git a/config/nim.cfg b/config/nim.cfg index 5caf578d64..c64a78a9b7 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -207,15 +207,15 @@ clang.objc.options.linker = "-lobjc -lgnustep-base" gcc.options.linker %= "-L $WIND_BASE/target/lib/usr/lib/ppc/PPC32/common -mrtp -fno-strict-aliasing -D_C99 -D_HAS_C9X -std=c99 -fasm -Wall -Wno-write-strings" @end -gcc.options.speed = "-O3 -fno-strict-aliasing" -gcc.options.size = "-Os" +gcc.options.speed = "-O3 -fno-strict-aliasing -fno-ident" +gcc.options.size = "-Os -fno-ident" @if windows: gcc.options.debug = "-g3 -Og -gdwarf-3" @else: gcc.options.debug = "-g3 -Og" @end -gcc.cpp.options.speed = "-O3 -fno-strict-aliasing" -gcc.cpp.options.size = "-Os" +gcc.cpp.options.speed = "-O3 -fno-strict-aliasing -fno-ident" +gcc.cpp.options.size = "-Os -fno-ident" gcc.cpp.options.debug = "-g3 -Og" #passl = "-pg" From f5b4d9a2e52285f48eb75100495f150d347cb161 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Fri, 18 Oct 2019 09:27:23 -0300 Subject: [PATCH 44/56] Fixes #8802 (#12439) * Fix #8802 * Peer review feedbacks https://github.com/nim-lang/Nim/pull/12439#discussion_r335905397 --- doc/gc.rst | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/doc/gc.rst b/doc/gc.rst index 7ec4e6d364..693f4c3a07 100644 --- a/doc/gc.rst +++ b/doc/gc.rst @@ -119,9 +119,12 @@ procs ``GC_ref`` and ``GC_unref`` to mark objects as referenced to avoid them being freed by the GC. Other useful procs from `system `_ you can use to keep track of memory are: -* getTotalMem(): returns the amount of total memory managed by the GC. -* getOccupiedMem(): bytes reserved by the GC and used by objects. -* getFreeMem(): bytes reserved by the GC and not in use. +* ``getTotalMem()`` Returns the amount of total memory managed by the GC. +* ``getOccupiedMem()`` Bytes reserved by the GC and used by objects. +* ``getFreeMem()`` Bytes reserved by the GC and not in use. + +These numbers are usually only for the running thread, not for the whole heap, +with the exception of ``--gc:boehm`` and ``--gc:go``. In addition to ``GC_ref`` and ``GC_unref`` you can avoid the GC by manually allocating memory with procs like ``alloc``, ``allocShared``, or @@ -144,3 +147,24 @@ The numbers count the number of objects in all GC heaps, they refer to all running threads, not only to the current thread. (The current thread would be the thread that calls ``dumpNumberOfInstances``.) This might change in later versions. + + +Garbage collector options +------------------------- + +You can choose which garbage collector to use when compiling source code, +you can pass ``--gc:`` on the compile command with the choosed garbage collector. + +- ``--gc:refc`` Deferred `reference counting `_ with cycle detection, `thread local heap `_, default. +- ``--gc:markAndSweep`` `Mark-And-Sweep `_ based garbage collector, `thread local heap `_. +- ``--gc:boehm`` `Boehm `_ based garbage collector, `stop-the-world `_, `shared heap `_. +- ``--gc:go`` Go lang like garbage collector, `stop-the-world `_, `shared heap `_. +- ``--gc:regions`` `Stack `_ based garbage collector. +- ``--gc:none`` No garbage collector. + +The same Nim code can compile to use any of the garbage collectors, +the Nim syntax mostly wont change from one garbage collector to another. +No garbage collector is used for `JavaScript and NodeJS `_ compilation targets. +`NimScript `_ target uses Nim VM garbage collector. + +If you are new to Nim and just starting, the default garbage collector is balanced to fit most common use cases. From 889b745b2b57927e2953d6e8bacaa68fde13513e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 18 Oct 2019 15:59:22 +0200 Subject: [PATCH 45/56] Revert "Fixes #12187 (#12321)" (#12447) This reverts commit 00c31e87660d9db813871f5aa23661bf6b9bbdcb. --- lib/pure/concurrency/cpuinfo.nim | 2 +- lib/pure/memfiles.nim | 2 +- lib/pure/strutils.nim | 2 +- lib/system.nim | 4 ++-- lib/system/ansi_c.nim | 18 +----------------- lib/system/io.nim | 14 +++----------- lib/system/memory.nim | 6 +++--- lib/system/osalloc.nim | 8 ++++---- lib/wrappers/openssl.nim | 4 ++-- testament/important_packages.nim | 3 ++- tests/manyloc/keineschweine/lib/estreams.nim | 2 +- 11 files changed, 21 insertions(+), 44 deletions(-) diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim index 5a72459a30..415b9a7872 100644 --- a/lib/pure/concurrency/cpuinfo.nim +++ b/lib/pure/concurrency/cpuinfo.nim @@ -79,7 +79,7 @@ proc countProcessors*(): int {.rtl, extern: "ncpi$1".} = len: csize mib[0] = CTL_HW mib[1] = HW_AVAILCPU - len = csize sizeof(numCPU) + len = sizeof(numCPU) discard sysctl(addr(mib), 2, addr(numCPU), len, nil, 0) if numCPU < 1: mib[1] = HW_NCPU diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim index 7e0478877f..411df14564 100644 --- a/lib/pure/memfiles.nim +++ b/lib/pure/memfiles.nim @@ -416,7 +416,7 @@ iterator memSlices*(mfile: MemFile, delim = '\l', eat = '\r'): MemSlice {.inline ms.data = mfile.mem var remaining = mfile.size while remaining > 0: - ending = c_memchr(ms.data, delim, csize remaining) + ending = c_memchr(ms.data, delim, remaining) if ending == nil: # unterminated final slice ms.size = remaining # Weird case..check eat? yield ms diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index fd5dcf14cc..69cb1efd58 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1872,7 +1872,7 @@ proc find*(s: string, sub: char, start: Natural = 0, last = 0): int {.noSideEffe when hasCStringBuiltin: let L = last-start+1 if L > 0: - let found = c_memchr(s[start].unsafeAddr, sub, csize L) + let found = c_memchr(s[start].unsafeAddr, sub, L) if not found.isNil: return cast[ByteAddress](found) -% cast[ByteAddress](s.cstring) else: diff --git a/lib/system.nim b/lib/system.nim index fdbd91c2f1..a7d8e8f05d 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2270,7 +2270,7 @@ type # these work for most platforms: ## This is the same as the type ``short`` in *C*. cint* {.importc: "int", nodecl.} = int32 ## This is the same as the type ``int`` in *C*. - csize* {.importc: "size_t", nodecl.} = uint + csize* {.importc: "size_t", nodecl.} = int ## This is the same as the type ``size_t`` in *C*. clonglong* {.importc: "long long", nodecl.} = int64 ## This is the same as the type ``long long`` in *C*. @@ -3634,7 +3634,7 @@ when not defined(JS): #and not defined(nimscript): when declared(memTrackerOp): memTrackerOp("copyMem", dest, size) proc moveMem(dest, source: pointer, size: Natural) = - c_memmove(dest, source, csize size) + c_memmove(dest, source, size) when declared(memTrackerOp): memTrackerOp("moveMem", dest, size) proc equalMem(a, b: pointer, size: Natural): bool = diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index 89058ce4f2..16e7a14d60 100644 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -17,24 +17,14 @@ when not defined(nimHasHotCodeReloading): proc c_memchr*(s: pointer, c: cint, n: csize): pointer {. importc: "memchr", header: "".} -proc c_memchr*(s: pointer, c: cint, n: int): pointer {. - importc: "memchr", header: "", deprecated: "csize is now uint".} proc c_memcmp*(a, b: pointer, size: csize): cint {. importc: "memcmp", header: "", noSideEffect.} -proc c_memcmp*(a, b: pointer, size: int): cint {. - importc: "memcmp", header: "", noSideEffect, deprecated: "csize is now uint".} proc c_memcpy*(a, b: pointer, size: csize): pointer {. importc: "memcpy", header: "", discardable.} -proc c_memcpy*(a, b: pointer, size: int): pointer {. - importc: "memcpy", header: "", discardable, deprecated: "csize is now uint".} proc c_memmove*(a, b: pointer, size: csize): pointer {. importc: "memmove", header: "",discardable.} -proc c_memmove*(a, b: pointer, size: int): pointer {. - importc: "memmove", header: "",discardable, deprecated: "csize is now uint".} proc c_memset*(p: pointer, value: cint, size: csize): pointer {. importc: "memset", header: "", discardable.} -proc c_memset*(p: pointer, value: cint, size: int): pointer {. - importc: "memset", header: "", discardable, deprecated: "csize is now uint".} proc c_strcmp*(a, b: cstring): cint {. importc: "strcmp", header: "", noSideEffect.} proc c_strlen*(a: cstring): csize {. @@ -144,22 +134,16 @@ proc c_sprintf*(buf, frmt: cstring): cint {. proc c_malloc*(size: csize): pointer {. importc: "malloc", header: "".} -proc c_malloc*(size: int): pointer {. - importc: "malloc", header: "", deprecated: "csize is now uint".} proc c_free*(p: pointer) {. importc: "free", header: "".} proc c_realloc*(p: pointer, newsize: csize): pointer {. importc: "realloc", header: "".} -proc c_realloc*(p: pointer, newsize: int): pointer {. - importc: "realloc", header: "", deprecated: "csize is now uint".} proc c_fwrite*(buf: pointer, size, n: csize, f: CFilePtr): cint {. importc: "fwrite", header: "".} -proc c_fwrite*(buf: pointer, size, n: int, f: CFilePtr): cint {. - importc: "fwrite", header: "", deprecated: "csize is now uint".} proc rawWrite*(f: CFilePtr, s: cstring) {.compilerproc, nonReloadable, inline.} = # we cannot throw an exception here! - discard c_fwrite(s, 1, csize s.len, f) + discard c_fwrite(s, 1, s.len, f) {.pop.} diff --git a/lib/system/io.nim b/lib/system/io.nim index 89ceb4ea20..b0ada528e3 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -85,14 +85,10 @@ proc c_feof(f: File): cint {. when not declared(c_fwrite): proc c_fwrite(buf: pointer, size, n: csize, f: File): cint {. importc: "fwrite", header: "".} - proc c_fwrite(buf: pointer, size, n: int, f: File): cint {. - importc: "fwrite", header: "", deprecated: "csize is now uint".} # C routine that is used here: proc c_fread(buf: pointer, size, n: csize, f: File): csize {. importc: "fread", header: "", tags: [ReadIOEffect].} -proc c_fread(buf: pointer, size, n: int, f: File): int {. - importc: "fread", header: "", tags: [ReadIOEffect], deprecated: "csize is now uint".} when defined(windows): when not defined(amd64): proc c_fseek(f: File, offset: int64, whence: cint): cint {. @@ -113,8 +109,6 @@ proc c_ferror(f: File): cint {. importc: "ferror", header: "", tags: [].} proc c_setvbuf(f: File, buf: pointer, mode: cint, size: csize): cint {. importc: "setvbuf", header: "", tags: [].} -proc c_setvbuf(f: File, buf: pointer, mode: cint, size: int): cint {. - importc: "setvbuf", header: "", tags: [], deprecated: "csize is now uint".} proc c_fprintf(f: File, frmt: cstring): cint {. importc: "fprintf", header: "", varargs, discardable.} @@ -159,7 +153,7 @@ proc readBuffer*(f: File, buffer: pointer, len: Natural): int {. ## reads `len` bytes into the buffer pointed to by `buffer`. Returns ## the actual number of bytes that have been read which may be less than ## `len` (if not as many bytes are remaining), but not greater. - result = int c_fread(buffer, 1, csize len, f) + result = c_fread(buffer, 1, len, f) if result != len: checkErr(f) proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: Natural): int {. @@ -191,7 +185,7 @@ proc writeBuffer*(f: File, buffer: pointer, len: Natural): int {. ## writes the bytes of buffer pointed to by the parameter `buffer` to the ## file `f`. Returns the number of actual written bytes, which may be less ## than `len` in case of an error. - result = c_fwrite(buffer, 1, csize len, f) + result = c_fwrite(buffer, 1, len, f) checkErr(f) proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: Natural): int {. @@ -304,8 +298,6 @@ proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], ## ``false`` is returned `line` contains no new data. proc c_memchr(s: pointer, c: cint, n: csize): pointer {. importc: "memchr", header: "".} - proc c_memchr(s: pointer, c: cint, n: int): pointer {. - importc: "memchr", header: "", deprecated: "csize is now uint".} var pos = 0 @@ -320,7 +312,7 @@ proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], var fgetsSuccess = c_fgets(addr line.string[pos], sp.cint, f) != nil if not fgetsSuccess: checkErr(f) - let m = c_memchr(addr line.string[pos], '\L'.ord, csize sp) + let m = c_memchr(addr line.string[pos], '\L'.ord, sp) if m != nil: # \l found: Could be our own or the one by fgets, in any case, we're done var last = cast[ByteAddress](m) - cast[ByteAddress](addr line.string[0]) diff --git a/lib/system/memory.nim b/lib/system/memory.nim index 53c9b1c3bd..13bddf211e 100644 --- a/lib/system/memory.nim +++ b/lib/system/memory.nim @@ -10,7 +10,7 @@ when useLibC: proc nimCopyMem*(dest, source: pointer, size: Natural) {.nonReloadable, compilerproc, inline.} = when useLibC: - c_memcpy(dest, source, csize size) + c_memcpy(dest, source, size) else: let d = cast[ptr UncheckedArray[byte]](dest) let s = cast[ptr UncheckedArray[byte]](source) @@ -21,7 +21,7 @@ proc nimCopyMem*(dest, source: pointer, size: Natural) {.nonReloadable, compiler proc nimSetMem*(a: pointer, v: cint, size: Natural) {.nonReloadable, inline.} = when useLibC: - c_memset(a, v, csize size) + c_memset(a, v, size) else: let a = cast[ptr UncheckedArray[byte]](a) var i = 0 @@ -35,7 +35,7 @@ proc nimZeroMem*(p: pointer, size: Natural) {.compilerproc, nonReloadable, inlin proc nimCmpMem*(a, b: pointer, size: Natural): cint {.compilerproc, nonReloadable, inline.} = when useLibC: - c_memcmp(a, b, csize size) + c_memcmp(a, b, size) else: let a = cast[ptr UncheckedArray[byte]](a) let b = cast[ptr UncheckedArray[byte]](b) diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim index e29f997d23..06e89f1305 100644 --- a/lib/system/osalloc.nim +++ b/lib/system/osalloc.nim @@ -153,7 +153,7 @@ elif defined(nintendoswitch): # size, as well as space to store our structure let realSize = alignSize(size + sizeof(NSwitchBlock)) - let heap = memalign(PageSize, realSize.csize) + let heap = memalign(PageSize, realSize) if heap.isNil: outOfMemoryStmt @@ -221,18 +221,18 @@ elif defined(posix): proc munmap(adr: pointer, len: csize): cint {.header: "".} proc osAllocPages(size: int): pointer {.inline.} = - result = mmap(nil, csize size, PROT_READ or PROT_WRITE, + result = mmap(nil, size, PROT_READ or PROT_WRITE, MAP_PRIVATE or MAP_ANONYMOUS, -1, 0) if result == nil or result == cast[pointer](-1): raiseOutOfMem() proc osTryAllocPages(size: int): pointer {.inline.} = - result = mmap(nil, csize size, PROT_READ or PROT_WRITE, + result = mmap(nil, size, PROT_READ or PROT_WRITE, MAP_PRIVATE or MAP_ANONYMOUS, -1, 0) if result == cast[pointer](-1): result = nil proc osDeallocPages(p: pointer, size: int) {.inline.} = - when reallyOsDealloc: discard munmap(p, csize size) + when reallyOsDealloc: discard munmap(p, size) elif defined(windows): const diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 46c9d7bd8d..482062617b 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -712,7 +712,7 @@ proc md5_File*(file: string): string {.raises: [IOError,Exception].} = discard md5_Init(ctx) while(let bytes = f.readChars(buf, 0, sz); bytes > 0): - discard md5_Update(ctx, buf[0].addr, csize bytes) + discard md5_Update(ctx, buf[0].addr, bytes) discard md5_Final(buf[0].addr, ctx) f.close @@ -731,7 +731,7 @@ proc md5_Str*(str: string): string = var i = 0 while i < str.len: let L = min(str.len - i, 512) - discard md5_Update(ctx, input[i].addr, csize L) + discard md5_Update(ctx, input[i].addr, L) i += L discard md5_Final(addr res, ctx) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index a6e712009e..2ecdbd7636 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -20,8 +20,9 @@ pkg "chroma" pkg "chronicles", "nim c -o:chr -r chronicles.nim", true pkg "chronos" pkg "cligen", "nim c -o:cligenn -r cligen.nim" +pkg "coco", "", true pkg "combparser" -pkg "compactdict", "", false, "https://github.com/Clyybber/compactdict" +pkg "compactdict" pkg "comprehension", "", false, "https://github.com/alehander42/comprehension" pkg "criterion" pkg "dashing", "nim c tests/functional.nim" diff --git a/tests/manyloc/keineschweine/lib/estreams.nim b/tests/manyloc/keineschweine/lib/estreams.nim index e8a036f03c..99cbb63d18 100644 --- a/tests/manyloc/keineschweine/lib/estreams.nim +++ b/tests/manyloc/keineschweine/lib/estreams.nim @@ -26,7 +26,7 @@ proc newBuffer*(pkt: PPacket): PBuffer = copyMem(addr result.data[0], pkt.data, pkt.dataLength) proc toPacket*(buffer: PBuffer; flags: TPacketFlag): PPacket = buffer.data.setLen buffer.pos - result = createPacket(cstring(buffer.data), csize buffer.pos, flags) + result = createPacket(cstring(buffer.data), buffer.pos, flags) proc isDirty*(buffer: PBuffer): bool {.inline.} = result = (buffer.pos != 0) From 6b157e5f73ad7df0e397f7890df5c263cf518dba Mon Sep 17 00:00:00 2001 From: Tomohiro Date: Fri, 18 Oct 2019 23:20:18 +0900 Subject: [PATCH 46/56] Fix vcc linker option name (#12422) --- config/nim.cfg | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/nim.cfg b/config/nim.cfg index c64a78a9b7..af8a97a199 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -257,7 +257,8 @@ vcc.linkerexe = "vccexe.exe" vcc.cpp.linkerexe = "vccexe.exe" vcc.cpp.options.always = "/EHsc" -vcc.options.linker.always = "/F33554432" # set the stack size to 32 MiB +vcc.options.linker = "/F33554432" # set the stack size to 32 MiB +vcc.cpp.options.linker = "/F33554432" vcc.options.debug = "/Zi /FS /Od" vcc.cpp.options.debug = "/Zi /FS /Od" vcc.options.speed = "/O2" From 832b0a0232e610c1935aaf6ce0b45f69199f8a19 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 18 Oct 2019 22:13:24 +0200 Subject: [PATCH 47/56] fixes #12420 [backport] (#12456) --- compiler/packagehandling.nim | 13 +++++-------- tests/modules/a/utils.nim | 2 ++ tests/modules/b/utils.nim | 2 ++ tests/modules/tutils_ab.nim | 5 +++++ 4 files changed, 14 insertions(+), 8 deletions(-) create mode 100644 tests/modules/a/utils.nim create mode 100644 tests/modules/b/utils.nim create mode 100644 tests/modules/tutils_ab.nim diff --git a/compiler/packagehandling.nim b/compiler/packagehandling.nim index 7fb560433b..ee6af06159 100644 --- a/compiler/packagehandling.nim +++ b/compiler/packagehandling.nim @@ -47,12 +47,9 @@ proc demanglePackageName*(path: string): string = proc withPackageName*(conf: ConfigRef; path: AbsoluteFile): AbsoluteFile = let x = getPackageName(conf, path.string) - if x.len == 0: - result = path + let (p, file, ext) = path.splitFile + if x == "stdlib": + # Hot code reloading now relies on 'stdlib_system' names etc. + result = p / RelativeFile((x & '_' & file) & ext) else: - let (p, file, ext) = path.splitFile - if x == "stdlib": - # Hot code reloading now relies on 'stdlib_system' names etc. - result = p / RelativeFile((x & '_' & file) & ext) - else: - result = p / RelativeFile(fakePackageName(conf, path)) + result = p / RelativeFile(fakePackageName(conf, path)) diff --git a/tests/modules/a/utils.nim b/tests/modules/a/utils.nim new file mode 100644 index 0000000000..f37abfb93f --- /dev/null +++ b/tests/modules/a/utils.nim @@ -0,0 +1,2 @@ +proc burnMem*(a: int) = + discard diff --git a/tests/modules/b/utils.nim b/tests/modules/b/utils.nim new file mode 100644 index 0000000000..e343385f53 --- /dev/null +++ b/tests/modules/b/utils.nim @@ -0,0 +1,2 @@ +# module b/utils.nim +let x* = 10 diff --git a/tests/modules/tutils_ab.nim b/tests/modules/tutils_ab.nim new file mode 100644 index 0000000000..25bd08f3c3 --- /dev/null +++ b/tests/modules/tutils_ab.nim @@ -0,0 +1,5 @@ +import a/utils as autils, b/utils + +# bug #12420 + +burnMem(x) From 61ea85687c2950bb40c23a1a7cd2c13473bd9662 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 19 Oct 2019 16:21:01 +0200 Subject: [PATCH 48/56] refactoring: --newruntime consists of 3 different switches --- compiler/ccgexprs.nim | 10 +++++----- compiler/ccgstmts.nim | 8 ++++---- compiler/ccgtrav.nim | 5 +++-- compiler/ccgtypes.nim | 2 +- compiler/cgen.nim | 2 +- compiler/commands.nim | 4 +++- compiler/injectdestructors.nim | 2 +- compiler/lambdalifting.nim | 20 ++++++++++---------- compiler/liftdestructors.nim | 6 +++--- compiler/options.nim | 6 +++++- compiler/scriptconfig.nim | 6 +++--- compiler/semexprs.nim | 2 +- compiler/semobjconstr.nim | 2 +- compiler/semstmts.nim | 6 +++--- compiler/semtypes.nim | 4 ++-- compiler/spawn.nim | 2 +- compiler/transf.nim | 2 +- 17 files changed, 48 insertions(+), 41 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 7a84fb1a29..13656acadf 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1206,7 +1206,7 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) = if sizeExpr.isNil: sizeExpr = "sizeof($1)" % [getTypeDesc(p.module, bt)] - if optNimV2 in p.config.globalOptions: + if optOwnedRefs in p.config.globalOptions: b.r = ropecg(p.module, "($1) #nimNewObj($2)", [getTypeDesc(p.module, typ), sizeExpr]) genAssignment(p, a, b, {}) @@ -1484,7 +1484,7 @@ proc genNewFinalize(p: BProc, e: PNode) = gcUsage(p.config, e) proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope = - if optNimV2 in p.config.globalOptions: + if optTinyRtti in p.config.globalOptions: result = ropecg(p.module, "#isObj($1.m_type, $2)", [a, genTypeInfo2Name(p.module, dest)]) else: @@ -1535,7 +1535,7 @@ proc genOf(p: BProc, n: PNode, d: var TLoc) = genOf(p, n.sons[1], n.sons[2].typ, d) proc genRepr(p: BProc, e: PNode, d: var TLoc) = - if optNimV2 in p.config.globalOptions: + if optTinyRtti in p.config.globalOptions: localError(p.config, e.info, "'repr' is not available for --newruntime") var a: TLoc initLocExpr(p, e.sons[1], a) @@ -2148,7 +2148,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)") of mStrToStr, mUnown: expr(p, e.sons[1], d) of mEnumToStr: - if optNimV2 in p.config.globalOptions: + if optTinyRtti in p.config.globalOptions: genEnumToStr(p, e, d) else: genRepr(p, e, d) @@ -2423,7 +2423,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) = while t.kind == tyObject and t.sons[0] != nil: add(r, ".Sup") t = skipTypes(t.sons[0], skipPtrs) - let checkFor = if optNimV2 in p.config.globalOptions: + let checkFor = if optTinyRtti in p.config.globalOptions: genTypeInfo2Name(p.module, dest) else: genTypeInfo(p.module, dest, n.info) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 6ff7cf91c5..fcef4a0ffe 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -17,7 +17,7 @@ const proc getTraverseProc(p: BProc, v: PSym): Rope = if p.config.selectedGC in {gcMarkAndSweep, gcDestructors, gcV2, gcRefc} and - optNimV2 notin p.config.globalOptions and + optOwnedRefs notin p.config.globalOptions and containsGarbageCollectedRef(v.loc.t): # we register a specialized marked proc here; this has the advantage # that it works out of the box for thread local storage then :-) @@ -692,7 +692,7 @@ proc genRaiseStmt(p: BProc, t: PNode) = [e, makeCString(typ.sym.name.s), makeCString(if p.prc != nil: p.prc.name.s else: p.module.module.name.s), quotedFilename(p.config, t.info), toLinenumber(t.info)]) - if optNimV2 in p.config.globalOptions: + if optOwnedRefs in p.config.globalOptions: lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [e]) else: genLineDir(p, t) @@ -1057,7 +1057,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) = for j in 0 .. blen - 2: assert(t.sons[i].sons[j].kind == nkType) if orExpr != nil: add(orExpr, "||") - let checkFor = if optNimV2 in p.config.globalOptions: + let checkFor = if optTinyRtti in p.config.globalOptions: genTypeInfo2Name(p.module, t[i][j].typ) else: genTypeInfo(p.module, t[i][j].typ, t[i][j].info) @@ -1220,7 +1220,7 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) = getTemp(p, a.t, tmp) expr(p, e.sons[1], tmp) let field = dotExpr.sons[1].sym - if optNimV2 in p.config.globalOptions: + if optTinyRtti in p.config.globalOptions: let t = dotExpr[0].typ.skipTypes(abstractInst) var oldVal, newVal: TLoc genCaseObjDiscMapping(p, e[0], t, field, oldVal) diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index 9374648c4e..e494b3e480 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -17,7 +17,7 @@ type visitorFrmt: string const - visitorFrmt = "#nimGCvisit((void*)$1, $2);$n" + visitorFrmt = "#nimGCvisit((void*)$1, $2);$n" proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) proc genCaseRange(p: BProc, branch: PNode) @@ -104,7 +104,8 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) = elif containsGarbageCollectedRef(typ.lastSon): # destructor based seqs are themselves not traced but their data is, if # they contain a GC'ed type: - genTraverseProcSeq(c, accessor, typ) + lineCg(p, cpsStmts, "#nimGCvisitSeq((void*)$1, $2);$n", [accessor, c.visitorFrmt]) + #genTraverseProcSeq(c, accessor, typ) of tyString: if tfHasAsgn notin typ.flags: lineCg(p, cpsStmts, visitorFrmt, [accessor, c.visitorFrmt]) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index fa90bc3f58..3e06da1462 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1365,7 +1365,7 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope = of tySet: genSetInfo(m, t, result, info) of tyEnum: genEnumInfo(m, t, result, info) of tyObject: - if optNimV2 in m.config.globalOptions: + if optTinyRtti in m.config.globalOptions: genObjectInfoV2(m, t, origType, result, info) else: genObjectInfo(m, t, origType, result, info) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index d1ac70d034..0c03c71717 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -347,7 +347,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc, s = skipTypes(s.sons[0], skipPtrs) linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfo(p.module, t, a.lode.info)]) of frEmbedded: - if optNimV2 in p.config.globalOptions: + if optTinyRtti in p.config.globalOptions: localError(p.config, p.prc.info, "complex object initialization is not supported with --newruntime") # worst case for performance: diff --git a/compiler/commands.nim b/compiler/commands.nim index aaa5f6623f..0ca99e2ce2 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -758,7 +758,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; if pass in {passCmd2, passPP}: doAssert(conf != nil) incl(conf.features, destructor) - incl(conf.globalOptions, optNimV2) + incl(conf.globalOptions, optTinyRtti) + incl(conf.globalOptions, optOwnedRefs) + incl(conf.globalOptions, optSeqDestructors) defineSymbol(conf.symbols, "nimV2") conf.selectedGC = gcDestructors defineSymbol(conf.symbols, "gcdestructors") diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 5765721d7e..40a4b74213 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -486,7 +486,7 @@ proc p(n: PNode; c: var Con): PNode = result.add n[0] result.add p(n[1], c) of nkRaiseStmt: - if optNimV2 in c.graph.config.globalOptions and n[0].kind != nkEmpty: + if optOwnedRefs in c.graph.config.globalOptions and n[0].kind != nkEmpty: if n[0].kind in nkCallKinds: let call = p(n[0], c) result = copyNode(n) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 33eacefbd6..612cc3b176 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -257,7 +257,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode = result.add(v) # add 'new' statement: result.add newCall(getSysSym(g, n.info, "internalNew"), env) - if optNimV2 in g.config.globalOptions: + if optOwnedRefs in g.config.globalOptions: createTypeBoundOps(g, nil, env.typ, n.info) result.add makeClosure(g, iter, env, n.info) @@ -323,7 +323,7 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym; c.ownerToType[owner.id] = result proc asOwnedRef(c: DetectionPass; t: PType): PType = - if optNimV2 in c.graph.config.globalOptions: + if optOwnedRefs in c.graph.config.globalOptions: assert t.kind == tyRef result = newType(tyOwned, t.owner) result.flags.incl tfHasOwned @@ -542,7 +542,7 @@ proc setupEnvVar(owner: PSym; d: DetectionPass; localError d.graph.config, owner.info, "internal error: could not determine closure type" result = newEnvVar(d.graph.cache, owner, asOwnedRef(d, envVarType), info) c.envVars[owner.id] = result - if optNimV2 in d.graph.config.globalOptions: + if optOwnedRefs in d.graph.config.globalOptions: var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), owner, info) v.flags = {sfShadowed, sfGeneratedOp} v.typ = envVarType @@ -572,14 +572,14 @@ proc rawClosureCreation(owner: PSym; var v = newNodeI(nkVarSection, env.info) addVar(v, env) result.add(v) - if optNimV2 in d.graph.config.globalOptions: + if optOwnedRefs in d.graph.config.globalOptions: let unowned = c.unownedEnvVars[owner.id] assert unowned != nil addVar(v, unowned) # add 'new' statement: result.add(newCall(getSysSym(d.graph, env.info, "internalNew"), env)) - if optNimV2 in d.graph.config.globalOptions: + if optOwnedRefs in d.graph.config.globalOptions: let unowned = c.unownedEnvVars[owner.id] assert unowned != nil let env2 = copyTree(env) @@ -608,12 +608,12 @@ proc rawClosureCreation(owner: PSym; localError(d.graph.config, env.info, "internal error: cannot create up reference") # we are not in the sem'check phase anymore! so pass 'nil' for the PContext # and hope for the best: - if optNimV2 in d.graph.config.globalOptions: + if optOwnedRefs in d.graph.config.globalOptions: createTypeBoundOps(d.graph, nil, env.typ, owner.info) proc finishClosureCreation(owner: PSym; d: DetectionPass; c: LiftingPass; info: TLineInfo; res: PNode) = - if optNimV2 in d.graph.config.globalOptions: + if optOwnedRefs in d.graph.config.globalOptions: let unowned = c.unownedEnvVars[owner.id] assert unowned != nil let nilLit = newNodeIT(nkNilLit, info, unowned.typ) @@ -637,7 +637,7 @@ proc closureCreationForIter(iter: PNode; addVar(vs, vnode) result.add(vs) result.add(newCall(getSysSym(d.graph, iter.info, "internalNew"), vnode)) - if optNimV2 in d.graph.config.globalOptions: + if optOwnedRefs in d.graph.config.globalOptions: createTypeBoundOps(d.graph, nil, vnode.typ, iter.info) let upField = lookupInRecord(v.typ.skipTypes({tyOwned, tyRef}).n, getIdent(d.graph.cache, upName)) @@ -653,7 +653,7 @@ proc closureCreationForIter(iter: PNode; proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass; c: var LiftingPass): PNode = var access = setupEnvVar(owner, d, c, n.info) - if optNimV2 in d.graph.config.globalOptions: + if optOwnedRefs in d.graph.config.globalOptions: access = c.unownedEnvVars[owner.id] let obj = access.typ.skipTypes({tyOwned, tyRef}) let field = getFieldFromObj(obj, n.sym) @@ -923,7 +923,7 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode = result.add(v) # add 'new' statement: result.add(newCall(getSysSym(g, env.info, "internalNew"), env.newSymNode)) - if optNimV2 in g.config.globalOptions: + if optOwnedRefs in g.config.globalOptions: createTypeBoundOps(g, nil, env.typ, body.info) elif op.kind == nkStmtListExpr: diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index cf9743ea47..69a4a55ee9 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -411,7 +411,7 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = call.sons[0] = newSymNode(createMagic(c.g, "deepCopy", mDeepCopy)) call.sons[1] = y body.add newAsgnStmt(x, call) - elif optNimV2 in c.g.config.globalOptions and + elif optOwnedRefs in c.g.config.globalOptions and optRefCheck in c.g.config.options: let xx = genBuiltin(c.g, mAccessEnv, "accessEnv", x) xx.typ = getSysType(c.g, c.info, tyPointer) @@ -457,7 +457,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = tyPtr, tyOpt, tyUncheckedArray: defaultOp(c, t, body, x, y) of tyRef: - if optNimV2 in c.g.config.globalOptions and + if optOwnedRefs in c.g.config.globalOptions and optRefCheck in c.g.config.options: weakrefOp(c, t, body, x, y) else: @@ -469,7 +469,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = defaultOp(c, t, body, x, y) of tyOwned: let base = t.skipTypes(abstractInstOwned) - if optNimV2 in c.g.config.globalOptions: + if optOwnedRefs in c.g.config.globalOptions: case base.kind of tyRef: ownedRefOp(c, base, body, x, y) diff --git a/compiler/options.nim b/compiler/options.nim index d115a20bd6..286ca8fcfe 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -81,7 +81,11 @@ type # please make sure we have under 32 options optNoNimblePath optHotCodeReloading optDynlibOverrideAll - optNimV2 + optSeqDestructors # active if the implementation uses the new + # string/seq implementation based on destructors + optTinyRtti # active if we use the new "tiny RTTI" + # implementation + optOwnedRefs # active if the Nim compiler knows about 'owned'. optMultiMethods optNimV019 optBenchmarkVM # Enables cpuTime() in the VM diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index 2dcac5666e..e9e720b1b7 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -217,7 +217,7 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile; let oldGlobalOptions = conf.globalOptions let oldSelectedGC = conf.selectedGC undefSymbol(conf.symbols, "nimv2") - conf.globalOptions.excl optNimV2 + conf.globalOptions.excl {optTinyRtti, optOwnedRefs, optSeqDestructors} conf.selectedGC = gcUnselected var m = graph.makeModule(scriptName) @@ -229,8 +229,8 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile; # watch out, "newruntime" can be set within NimScript itself and then we need # to remember this: - if optNimV2 in oldGlobalOptions: - conf.globalOptions.incl optNimV2 + if optOwnedRefs in oldGlobalOptions: + conf.globalOptions.incl {optTinyRtti, optOwnedRefs, optSeqDestructors} defineSymbol(conf.symbols, "nimv2") if conf.selectedGC == gcUnselected: conf.selectedGC = oldSelectedGC diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 019c302262..ed38f66e11 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2563,7 +2563,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # if isGenericRoutine(result.sym): # localError(c.config, n.info, errInstantiateXExplicitly, s.name.s) # "procs literals" are 'owned' - if optNimV2 in c.config.globalOptions: + if optOwnedRefs in c.config.globalOptions: result.typ = makeVarType(c, result.typ, tyOwned) else: result = semSym(c, n, s, flags) diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index b71198fd8d..eff7bd8252 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -380,7 +380,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = t = skipTypes(t, {tyGenericInst, tyAlias, tySink, tyOwned}) if t.kind == tyRef: t = skipTypes(t.sons[0], {tyGenericInst, tyAlias, tySink, tyOwned}) - if optNimV2 in c.config.globalOptions: + if optOwnedRefs in c.config.globalOptions: result.typ = makeVarType(c, result.typ, tyOwned) # we have to watch out, there are also 'owned proc' types that can be used # multiple times as long as they don't have closures. diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f5a82b910a..518b5e5e8b 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1519,7 +1519,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = closeScope(c) # close scope for parameters popOwner(c) result.typ = s.typ - if optNimV2 in c.config.globalOptions: + if optOwnedRefs in c.config.globalOptions: result.typ = makeVarType(c, result.typ, tyOwned) proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode = @@ -1556,7 +1556,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode = popProcCon(c) popOwner(c) closeScope(c) - if optNimV2 in c.config.globalOptions and result.typ != nil: + if optOwnedRefs in c.config.globalOptions and result.typ != nil: result.typ = makeVarType(c, result.typ, tyOwned) # alternative variant (not quite working): # var prc = arg[0].sym @@ -1948,7 +1948,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if isAnon: n.kind = nkLambda result.typ = s.typ - if optNimV2 in c.config.globalOptions: + if optOwnedRefs in c.config.globalOptions: result.typ = makeVarType(c, result.typ, tyOwned) if isTopLevel(c) and s.kind != skIterator and s.typ.callConv == ccClosure: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 186161169c..7e42a120c7 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -877,7 +877,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType = if tfPartial in result.flags: if result.lastSon.kind == tyObject: incl(result.lastSon.flags, tfPartial) #if not isNilable: result.flags.incl tfNotNil - if isOwned and optNimV2 in c.config.globalOptions: + if isOwned and optOwnedRefs in c.config.globalOptions: let t = newTypeS(tyOwned, c) t.flags.incl tfHasOwned t.rawAddSonNoPropagationOfTypeFlags result @@ -1644,7 +1644,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = semTypeof(c, n[1], prev) elif op.s == "typeof" and n[0].kind == nkSym and n[0].sym.magic == mTypeOf: result = semTypeof2(c, n, prev) - elif op.s == "owned" and optNimV2 notin c.config.globalOptions and n.len == 2: + elif op.s == "owned" and optOwnedRefs notin c.config.globalOptions and n.len == 2: result = semTypeExpr(c, n[1], prev) else: if c.inGenericContext > 0 and n.kind == nkCall: diff --git a/compiler/spawn.nim b/compiler/spawn.nim index 7980ac4344..b48c67fd3b 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -65,7 +65,7 @@ proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; owner: PSym; typ: P vpart.sons[2] = if varInit.isNil: v else: vpart[1] varSection.add vpart if varInit != nil: - if useShallowCopy and typeNeedsNoDeepCopy(typ) or optNimV2 in g.config.globalOptions: + if useShallowCopy and typeNeedsNoDeepCopy(typ) or optTinyRtti in g.config.globalOptions: varInit.add newFastAsgnStmt(newSymNode(result), v) else: let deepCopyCall = newNodeI(nkCall, varInit.info, 3) diff --git a/compiler/transf.nim b/compiler/transf.nim index afbe419507..b95733a37e 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -914,7 +914,7 @@ proc transform(c: PTransf, n: PNode): PTransNode = oldDeferAnchor = c.deferAnchor c.deferAnchor = n if (n.typ != nil and tfHasAsgn in n.typ.flags) or - optNimV2 in c.graph.config.globalOptions: + optSeqDestructors in c.graph.config.globalOptions: c.needsDestroyPass = true case n.kind of nkSym: From ed2fb36bc61bd5272734899783ede5e6f285da0e Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 19 Oct 2019 18:03:50 +0200 Subject: [PATCH 49/56] refactoring: use the new strings and seqs when optSeqDestructors is active --- compiler/ccgexprs.nim | 40 ++++++++++++++++---------------- compiler/ccgtypes.nim | 12 +++++----- compiler/cgen.nim | 10 ++++---- compiler/commands.nim | 1 + compiler/lambdalifting.nim | 6 ++--- compiler/liftdestructors.nim | 6 ++--- compiler/semtypes.nim | 27 ++++----------------- compiler/sigmatch.nim | 5 ---- compiler/sizealignoffsetimpl.nim | 4 ++-- 9 files changed, 45 insertions(+), 66 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 13656acadf..cc4e8de42d 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -79,7 +79,7 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope = # with the new semantics for 'nil' strings, we can map "" to nil and # save tons of allocations: if n.strVal.len == 0 and optNilSeqs notin p.options and - p.config.selectedGC != gcDestructors: + optSeqDestructors notin p.config.globalOptions: result = genNilStringLiteral(p.module, n.info) else: result = genStringLiteral(p.module, n) @@ -250,7 +250,7 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = # tfShallow flag for the built-in string type too! So we check only # here for this flag, where it is reasonably safe to do so # (for objects, etc.): - if p.config.selectedGC == gcDestructors: + if optSeqDestructors in p.config.globalOptions: linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) @@ -279,7 +279,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = of tyRef: genRefAssign(p, dest, src) of tySequence: - if p.config.selectedGC == gcDestructors: + if optSeqDestructors in p.config.globalOptions: genGenericAsgn(p, dest, src, flags) elif (needToCopy notin flags and src.storage != OnStatic) or canMove(p, src.lode, dest): genRefAssign(p, dest, src) @@ -288,7 +288,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = [addrLoc(p.config, dest), rdLoc(src), genTypeInfo(p.module, dest.t, dest.lode.info)]) of tyString: - if p.config.selectedGC == gcDestructors: + if optSeqDestructors in p.config.globalOptions: genGenericAsgn(p, dest, src, flags) elif (needToCopy notin flags and src.storage != OnStatic) or canMove(p, src.lode, dest): genRefAssign(p, dest, src) @@ -934,7 +934,7 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = a.r = ropecg(p.module, "(*$1)", [a.r]) if lfPrepareForMutation in d.flags and ty.kind == tyString and - p.config.selectedGC == gcDestructors: + optSeqDestructors in p.config.globalOptions: linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) putIntoDest(p, d, n, ropecg(p.module, "$1$3[$2]", [rdLoc(a), rdCharLoc(b), dataField(p)]), a.storage) @@ -1060,7 +1060,7 @@ proc gcUsage(conf: ConfigRef; n: PNode) = if conf.selectedGC == gcNone: message(conf, n.info, warnGcMem, n.renderTree) proc strLoc(p: BProc; d: TLoc): Rope = - if p.config.selectedGC == gcDestructors: + if optSeqDestructors in p.config.globalOptions: result = byRefLoc(p, d) else: result = rdLoc(d) @@ -1141,7 +1141,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) = add(lens, " + ") add(appends, ropecg(p.module, "#appendString($1, $2);$n", [strLoc(p, dest), rdLoc(a)])) - if p.config.selectedGC == gcDestructors: + if optSeqDestructors in p.config.globalOptions: linefmt(p, cpsStmts, "#prepareAdd($1, $2$3);$n", [byRefLoc(p, dest), lens, L]) else: @@ -1288,7 +1288,7 @@ proc genNewSeq(p: BProc, e: PNode) = var a, b: TLoc initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[2], b) - if p.config.selectedGC == gcDestructors: + if optSeqDestructors in p.config.globalOptions: let seqtype = skipTypes(e.sons[1].typ, abstractVarRange) linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n", [a.rdLoc, b.rdLoc, getTypeDesc(p.module, seqtype.lastSon), @@ -1303,7 +1303,7 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) = let seqtype = skipTypes(e.typ, abstractVarRange) var a: TLoc initLocExpr(p, e.sons[1], a) - if p.config.selectedGC == gcDestructors: + if optSeqDestructors in p.config.globalOptions: if d.k == locNone: getTemp(p, e.typ, d, needsInit=false) linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n", [d.rdLoc, a.rdLoc, getTypeDesc(p.module, seqtype.lastSon), @@ -1403,7 +1403,7 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) = getTemp(p, n.typ, d) let l = intLiteral(len(n)) - if p.config.selectedGC == gcDestructors: + if optSeqDestructors in p.config.globalOptions: let seqtype = n.typ linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n", [rdLoc dest[], l, getTypeDesc(p.module, seqtype.lastSon), @@ -1434,7 +1434,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) = getTemp(p, n.typ, d) # generate call to newSeq before adding the elements per hand: let L = toInt(lengthOrd(p.config, n.sons[1].typ)) - if p.config.selectedGC == gcDestructors: + if optSeqDestructors in p.config.globalOptions: let seqtype = n.typ linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n", [rdLoc d, L, getTypeDesc(p.module, seqtype.lastSon), @@ -1654,7 +1654,7 @@ proc makeAddr(n: PNode): PNode = result.typ = makePtrType(n.typ) proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = - if p.config.selectedGC == gcDestructors: + if optSeqDestructors in p.config.globalOptions: e.sons[1] = makeAddr(e[1]) genCall(p, e, d) return @@ -1683,7 +1683,7 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = gcUsage(p.config, e) proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) = - if p.config.selectedGC == gcDestructors: + if optSeqDestructors in p.config.globalOptions: binaryStmtAddr(p, e, d, "setLengthStrV2") else: var a, b, call: TLoc @@ -1897,7 +1897,7 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) = if srcTyp.kind in {tyPtr, tyPointer} and etyp.kind in IntegralTypes: putIntoDest(p, d, e, "(($1) (ptrdiff_t) ($2))" % [getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.storage) - elif p.config.selectedGC == gcDestructors and etyp.kind in {tySequence, tyString}: + elif optSeqDestructors in p.config.globalOptions and etyp.kind in {tySequence, tyString}: putIntoDest(p, d, e, "(*($1*) (&$2))" % [getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.storage) else: @@ -2025,7 +2025,7 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) = resetLoc(p, a) proc genDestroy(p: BProc; n: PNode) = - if p.config.selectedGC == gcDestructors: + if optSeqDestructors in p.config.globalOptions: let arg = n[1].skipAddr let t = arg.typ.skipTypes(abstractInst) case t.kind @@ -2120,7 +2120,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mConStrStr: genStrConcat(p, e, d) of mAppendStrCh: - if p.config.selectedGC == gcDestructors: + if optSeqDestructors in p.config.globalOptions: binaryStmtAddr(p, e, d, "nimAddCharV1") else: var dest, b, call: TLoc @@ -2131,7 +2131,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = genAssignment(p, dest, call, {}) of mAppendStrStr: genStrAppend(p, e, d) of mAppendSeqElem: - if p.config.selectedGC == gcDestructors: + if optSeqDestructors in p.config.globalOptions: e.sons[1] = makeAddr(e[1]) genCall(p, e, d) else: @@ -2713,7 +2713,7 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope = tyTyped, tyTypeDesc, tyStatic, tyRef, tyNil: result = rope"NIM_NIL" of tyString, tySequence: - if p.config.selectedGC == gcDestructors: + if optSeqDestructors in p.config.globalOptions: result = rope"{0, NIM_NIL}" else: result = rope"NIM_NIL" @@ -2855,7 +2855,7 @@ proc genConstExpr(p: BProc, n: PNode): Rope = of nkBracket, nkPar, nkTupleConstr, nkClosure: var t = skipTypes(n.typ, abstractInstOwned) if t.kind == tySequence: - if p.config.selectedGC == gcDestructors: + if optSeqDestructors in p.config.globalOptions: result = genConstSeqV2(p, n, n.typ) else: result = genConstSeq(p, n, n.typ) @@ -2879,7 +2879,7 @@ proc genConstExpr(p: BProc, n: PNode): Rope = of nkObjConstr: result = genConstObjConstr(p, n) of nkStrLit..nkTripleStrLit: - if p.config.selectedGC == gcDestructors: + if optSeqDestructors in p.config.globalOptions: result = genStringLiteralV2Const(p.module, n) else: var d: TLoc diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 3e06da1462..de1f0e4974 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -356,7 +356,7 @@ proc addForwardStructFormat(m: BModule, structOrUnion: Rope, typename: Rope) = m.s[cfsForwardTypes].addf "typedef $1 $2 $2;$n", [structOrUnion, typename] proc seqStar(m: BModule): string = - if m.config.selectedGC == gcDestructors: result = "" + if optSeqDestructors in m.config.globalOptions: result = "" else: result = "*" proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope = @@ -390,7 +390,7 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope = pushType(m, t) of tySequence: let sig = hashType(t) - if m.config.selectedGC == gcDestructors: + if optSeqDestructors in m.config.globalOptions: if skipTypes(etB.sons[0], typedescInst).kind == tyEmpty: internalError(m.config, "cannot map the empty seq type to a C type") @@ -710,7 +710,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = result = name & star m.typeCache[sig] = result of tySequence: - if m.config.selectedGC == gcDestructors: + if optSeqDestructors in m.config.globalOptions: result = getTypeDescWeak(m, et, check) & star m.typeCache[sig] = result else: @@ -770,7 +770,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = "void* ClE_0;$n} $1;$n", [result, rettype, desc]) of tySequence: - if m.config.selectedGC == gcDestructors: + if optSeqDestructors in m.config.globalOptions: result = getTypeDescWeak(m, t, check) else: # we cannot use getTypeForward here because then t would be associated @@ -926,7 +926,7 @@ proc finishTypeDescriptions(m: BModule) = var check = initIntSet() while i < len(m.typeStack): let t = m.typeStack[i] - if m.config.selectedGC == gcDestructors and t.skipTypes(abstractInst).kind == tySequence: + if optSeqDestructors in m.config.globalOptions and t.skipTypes(abstractInst).kind == tySequence: seqV2ContentType(m, t, check) else: discard getTypeDescAux(m, t, check) @@ -1351,7 +1351,7 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope = genTupleInfo(m, x, x, result, info) of tySequence: genTypeInfoAux(m, t, t, result, info) - if m.config.selectedGC != gcDestructors: + if optSeqDestructors notin m.config.globalOptions: if m.config.selectedGC >= gcMarkAndSweep: let markerProc = genTraverseProc(m, origType, sig) addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc]) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 0c03c71717..5809a40491 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -293,13 +293,13 @@ proc lenField(p: BProc): Rope = result = rope(if p.module.compileToCpp: "len" else: "Sup.len") proc lenExpr(p: BProc; a: TLoc): Rope = - if p.config.selectedGC == gcDestructors: + if optSeqDestructors in p.config.globalOptions: result = rdLoc(a) & ".len" else: result = "($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p)] proc dataField(p: BProc): Rope = - if p.config.selectedGC == gcDestructors: + if optSeqDestructors in p.config.globalOptions: result = rope".p->data" else: result = rope"->data" @@ -377,10 +377,10 @@ proc isComplexValueType(t: PType): bool {.inline.} = (t.kind == tyProc and t.callConv == ccClosure) proc resetLoc(p: BProc, loc: var TLoc) = - let containsGcRef = p.config.selectedGC != gcDestructors and containsGarbageCollectedRef(loc.t) + let containsGcRef = optSeqDestructors notin p.config.globalOptions and containsGarbageCollectedRef(loc.t) let typ = skipTypes(loc.t, abstractVarRange) if isImportedCppType(typ): return - if p.config.selectedGC == gcDestructors and typ.kind in {tyString, tySequence}: + if optSeqDestructors in p.config.globalOptions and typ.kind in {tyString, tySequence}: assert rdLoc(loc) != nil linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)]) elif not isComplexValueType(typ): @@ -411,7 +411,7 @@ proc resetLoc(p: BProc, loc: var TLoc) = proc constructLoc(p: BProc, loc: TLoc, isTemp = false) = let typ = loc.t - if p.config.selectedGC == gcDestructors and skipTypes(typ, abstractInst).kind in {tyString, tySequence}: + if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst).kind in {tyString, tySequence}: linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)]) elif not isComplexValueType(typ): linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc), diff --git a/compiler/commands.nim b/compiler/commands.nim index 0ca99e2ce2..05626a9c3f 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -452,6 +452,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "destructors": conf.selectedGC = gcDestructors defineSymbol(conf.symbols, "gcdestructors") + incl conf.globalOptions, optSeqDestructors of "go": conf.selectedGC = gcGo defineSymbol(conf.symbols, "gogc") diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 612cc3b176..2ea5f5263a 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -342,9 +342,9 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) = let obj = refObj.skipTypes({tyOwned, tyRef}) # The assumption here is that gcDestructors means we cannot deal # with cycles properly, so it's better to produce a weak ref (=ptr) here. - # This seems to be generally correct but since it's a bit risky it's only - # enabled for gcDestructors. - let fieldType = if false: # c.graph.config.selectedGC == gcDestructors: + # This seems to be generally correct but since it's a bit risky it's disabled + # for now. + let fieldType = if false: # optSeqDestructors in c.graph.config.globalOptions: c.getEnvTypeForOwnerUp(dep, info) #getHiddenParam(dep).typ else: c.getEnvTypeForOwner(dep, info) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 69a4a55ee9..ffdf3e16e4 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -129,7 +129,7 @@ proc newDeepCopyCall(op: PSym; x, y: PNode): PNode = result = newAsgnStmt(x, newOpCall(op, y)) proc useNoGc(c: TLiftCtx; t: PType): bool {.inline.} = - result = c.g.config.selectedGC == gcDestructors and + result = optSeqDestructors in c.g.config.globalOptions and ({tfHasGCedMem, tfHasOwned} * t.flags != {} or t.isGCedMem) proc instantiateGeneric(c: var TLiftCtx; op: PSym; t, typeInst: PType): PSym = @@ -142,7 +142,7 @@ proc instantiateGeneric(c: var TLiftCtx; op: PSym; t, typeInst: PType): PSym = proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode; field: var PSym): bool = - if c.g.config.selectedGC == gcDestructors: + if optSeqDestructors in c.g.config.globalOptions: let op = field if field != nil and sfOverriden in field.flags: if sfError in op.flags: @@ -488,7 +488,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = of tySequence: if useNoGc(c, t): useSeqOrStrOp(c, t, body, x, y) - elif c.g.config.selectedGC == gcDestructors: + elif optSeqDestructors in c.g.config.globalOptions: # note that tfHasAsgn is propagated so we need the check on # 'selectedGC' here to determine if we have the new runtime. discard considerUserDefinedOp(c, t, body, x, y) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 7e42a120c7..3fdeb144d7 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1668,26 +1668,9 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of mSet: result = semSet(c, n, prev) of mOrdinal: result = semOrdinal(c, n, prev) of mSeq: - if false: # c.config.selectedGC == gcDestructors and optNimV2 notin c.config.globalOptions: - let s = c.graph.sysTypes[tySequence] - assert s != nil - assert prev == nil - result = copyType(s, s.owner, keepId=false) - # Remove the 'T' parameter from tySequence: - result.sons.setLen 0 - result.n = nil - result.flags = {tfHasAsgn} - semContainerArg(c, n, "seq", result) - if result.len > 0: - var base = result[0] - if base.kind in {tyGenericInst, tyAlias, tySink}: base = lastSon(base) - if not containsGenericType(base): - # base.kind != tyGenericParam: - c.typesWithOps.add((result, result)) - else: - result = semContainer(c, n, tySequence, "seq", prev) - if c.config.selectedGC == gcDestructors: - incl result.flags, tfHasAsgn + result = semContainer(c, n, tySequence, "seq", prev) + if optSeqDestructors in c.config.globalOptions: + incl result.flags, tfHasAsgn of mOpt: result = semContainer(c, n, tyOpt, "opt", prev) of mVarargs: result = semVarargs(c, n, prev) of mTypeDesc, mType, mTypeOf: @@ -1862,7 +1845,7 @@ proc processMagicType(c: PContext, m: PSym) = of mString: setMagicType(c.config, m, tyString, szUncomputedSize) rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar)) - if c.config.selectedGC == gcDestructors: + if optSeqDestructors in c.config.globalOptions: incl m.typ.flags, tfHasAsgn of mCstring: setMagicIntegral(c.config, m, tyCString, c.config.target.ptrSize) @@ -1903,7 +1886,7 @@ proc processMagicType(c: PContext, m: PSym) = setMagicIntegral(c.config, m, tyUncheckedArray, szUncomputedSize) of mSeq: setMagicType(c.config, m, tySequence, szUncomputedSize) - if c.config.selectedGC == gcDestructors: + if optSeqDestructors in c.config.globalOptions: incl m.typ.flags, tfHasAsgn assert c.graph.sysTypes[tySequence] == nil c.graph.sysTypes[tySequence] = m.typ diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 10141e645a..a5e588bab6 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2590,11 +2590,6 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo; if f.kind in {tyRef, tyPtr}: f = f.lastSon else: if f.kind == tyVar: f = f.lastSon - #if c.config.selectedGC == gcDestructors and f.kind == tySequence: - # use the canonical type to access the =sink and =destroy etc. - # f = c.graph.sysTypes[tySequence] - #echo "YUP_---------Formal ", typeToString(f, preferDesc), " real ", typeToString(t, preferDesc), " ", f.id, " ", t.id - if typeRel(m, f, t) == isNone: localError(c.config, info, "cannot instantiate: '" & dc.name.s & "'") else: diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index 1692aaf64c..f579697125 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -231,7 +231,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = typ.size = conf.target.ptrSize typ.align = int16(conf.target.ptrSize) of tyString: - if conf.selectedGC == gcDestructors: + if optSeqDestructors in conf.globalOptions: typ.size = conf.target.ptrSize * 2 else: typ.size = conf.target.ptrSize @@ -245,7 +245,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = typ.paddingAtEnd = szIllegalRecursion return typ.align = int16(conf.target.ptrSize) - if typ.kind == tySequence and conf.selectedGC == gcDestructors: + if typ.kind == tySequence and optSeqDestructors in conf.globalOptions: typ.size = conf.target.ptrSize * 2 else: typ.size = conf.target.ptrSize From 0eae2217b69541ea8ce1cf6509732928fb0869ee Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 19 Oct 2019 19:30:48 +0200 Subject: [PATCH 50/56] first implementation of the new --seqsv2 switch --- compiler/commands.nim | 5 +++++ doc/advopt.txt | 2 ++ lib/system.nim | 20 ++++++++++---------- lib/system/excpt.nim | 2 +- lib/system/gc_ms.nim | 4 ++-- lib/system/mmdisp.nim | 2 +- lib/system/repr.nim | 2 +- 7 files changed, 22 insertions(+), 15 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 05626a9c3f..a3ab6e522d 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -765,6 +765,11 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; defineSymbol(conf.symbols, "nimV2") conf.selectedGC = gcDestructors defineSymbol(conf.symbols, "gcdestructors") + defineSymbol(conf.symbols, "nimSeqsV2") + of "seqsv2": + processOnOffSwitchG(conf, {optSeqDestructors}, arg, pass, info) + if pass in {passCmd2, passPP}: + defineSymbol(conf.symbols, "nimSeqsV2") of "stylecheck": case arg.normalize of "off": conf.globalOptions = conf.globalOptions - {optStyleHint, optStyleError} diff --git a/doc/advopt.txt b/doc/advopt.txt index 96db6a9c28..351815ade7 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -89,6 +89,8 @@ Advanced options: strings is allowed; only for backwards compatibility --nilseqs:on|off allow 'nil' for strings/seqs for backwards compatibility + --seqsv2:on|off use the new string/seq implementation based on + destructors --oldast:on|off use old AST for backwards compatibility --skipCfg:on|off do not read the nim installation's configuration file --skipUserCfg:on|off do not read the user's configuration file diff --git a/lib/system.nim b/lib/system.nim index a7d8e8f05d..5e1bcd309a 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -671,7 +671,7 @@ include "system/inclrtl" const NoFakeVars* = defined(nimscript) ## `true` if the backend doesn't support \ ## "fake variables" like `var EBADF {.importc.}: cint`. -when not defined(JS) and not defined(gcDestructors): +when not defined(JS) and not defined(nimSeqsV2): type TGenericSeq {.compilerproc, pure, inheritable.} = object len, reserved: int @@ -684,7 +684,7 @@ when not defined(JS) and not defined(gcDestructors): NimString = ptr NimStringDesc when not defined(JS) and not defined(nimscript): - when not defined(gcDestructors): + when not defined(nimSeqsV2): template space(s: PGenericSeq): int {.dirty.} = s.reserved and not (seqShallowFlag or strlitFlag) when not defined(nimV2): @@ -1020,7 +1020,7 @@ when not defined(JS): ## assert len(x) == 3 ## x[0] = 10 result = newSeqOfCap[T](len) - when defined(gcDestructors): + when defined(nimSeqsV2): cast[ptr int](addr result)[] = len else: var s = cast[PGenericSeq](result) @@ -2111,10 +2111,10 @@ const hasAlloc = (hostOS != "standalone" or not defined(nogc)) and not defined(n when not defined(JS) and not defined(nimscript) and hostOS != "standalone": include "system/cgprocs" -when not defined(JS) and not defined(nimscript) and hasAlloc and not defined(gcDestructors): +when not defined(JS) and not defined(nimscript) and hasAlloc and not defined(nimSeqsV2): proc addChar(s: NimString, c: char): NimString {.compilerproc, benign.} -when not defined(gcDestructors) or defined(nimscript): +when not defined(nimSeqsV2) or defined(nimscript): proc add*[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.} ## Generic proc for adding a data item `y` to a container `x`. ## @@ -2141,7 +2141,7 @@ proc add*[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} = setLen(x, xl + y.len) for i in 0..high(y): x[xl+i] = y[i] -when defined(gcDestructors): +when defined(nimSeqsV2): template movingCopy(a, b) = a = move(b) else: @@ -3039,7 +3039,7 @@ proc `==`*[T](x, y: seq[T]): bool {.noSideEffect.} = else: when not defined(JS): proc seqToPtr[T](x: seq[T]): pointer {.inline, noSideEffect.} = - when defined(gcDestructors): + when defined(nimSeqsV2): result = cast[NimSeqV2[T]](x).p else: result = cast[pointer](x) @@ -3135,7 +3135,7 @@ when not defined(js): name: cstring PNimType = ptr TNimType - when defined(gcDestructors) and not defined(nimscript): + when defined(nimSeqsV2) and not defined(nimscript): include "core/strs" include "core/seqs" @@ -3784,7 +3784,7 @@ when not defined(JS): #and not defined(nimscript): {.pop.} {.push stack_trace: off, profiler:off.} when hasAlloc: - when not defined(gcDestructors): + when not defined(nimSeqsV2): include "system/sysstr" {.pop.} when hasAlloc: include "system/strmantle" @@ -4199,7 +4199,7 @@ proc shallow*(s: var string) {.noSideEffect, inline.} = ## perform deep copies of `s`. ## ## This is only useful for optimization purposes. - when not defined(JS) and not defined(nimscript) and not defined(gcDestructors): + when not defined(JS) and not defined(nimscript) and not defined(nimSeqsV2): var s = cast[PGenericSeq](s) if s == nil: s = cast[PGenericSeq](newString(0)) diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 1eb4cedc8e..e3448ff4c8 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -439,7 +439,7 @@ proc getStackTrace(e: ref Exception): string = proc getStackTraceEntries*(e: ref Exception): seq[StackTraceEntry] = ## Returns the attached stack trace to the exception ``e`` as ## a ``seq``. This is not yet available for the JS backend. - when not defined(gcDestructors): + when not defined(nimSeqsV2): shallowCopy(result, e.trace) else: result = move(e.trace) diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim index 3ce4289303..271543445f 100644 --- a/lib/system/gc_ms.nim +++ b/lib/system/gc_ms.nim @@ -254,7 +254,7 @@ proc forAllChildren(cell: PCell, op: WalkOp) = of tyRef: # common case forAllChildrenAux(cellToUsr(cell), cell.typ.base, op) of tySequence: - when not defined(gcDestructors): + when not defined(nimSeqsV2): var d = cast[ByteAddress](cellToUsr(cell)) var s = cast[PGenericSeq](d) if s != nil: @@ -304,7 +304,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} = zeroMem(result, size) when defined(memProfiler): nimProfile(size) -when not defined(gcDestructors): +when not defined(nimSeqsV2): proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} = # `newObj` already uses locks, so no need for them here. let size = addInt(mulInt(len, typ.base.size), GenericSeqSize) diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index cba88104d4..de89acd331 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -518,7 +518,7 @@ else: else: include "system/gc" -when not declared(nimNewSeqOfCap) and not defined(gcDestructors): +when not declared(nimNewSeqOfCap) and not defined(nimSeqsV2): proc nimNewSeqOfCap(typ: PNimType, cap: int): pointer {.compilerproc.} = when defined(gcRegions): let s = mulInt(cap, typ.base.size) # newStr already adds GenericSeqSize diff --git a/lib/system/repr.nim b/lib/system/repr.nim index 97975277bf..0c7848c753 100644 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -160,7 +160,7 @@ when not defined(useNimRtl): reprAux(result, cast[pointer](cast[ByteAddress](p) + i*bs), typ.base, cl) add result, "]" - when defined(gcDestructors): + when defined(nimSeqsV2): type GenericSeq = object len: int From df4c339cfce15ccc5406bc7763eac4daf9b8c76f Mon Sep 17 00:00:00 2001 From: ducdetronquito Date: Sun, 20 Oct 2019 08:12:02 +0200 Subject: [PATCH 51/56] Namespace unittest enums to avoid name conflicts (#12468) [backport] * [backport] Fixes: #12465 - Unittest - Namespace the usage of TestStatus enum to avoid name conflicts. --- lib/pure/unittest.nim | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 0cfb5756ec..c3e3a8876b 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -186,7 +186,7 @@ proc delOutputFormatter*(formatter: OutputFormatter) = keepIf(formatters, proc (x: OutputFormatter): bool = x != formatter) -proc newConsoleOutputFormatter*(outputLevel: OutputLevel = PRINT_ALL, +proc newConsoleOutputFormatter*(outputLevel: OutputLevel = OutputLevel.PRINT_ALL, colorOutput = true): ConsoleOutputFormatter = ConsoleOutputFormatter( outputLevel: outputLevel, @@ -207,7 +207,7 @@ proc defaultConsoleFormatter*(): ConsoleOutputFormatter = colorOutput = true elif existsEnv("NIMTEST_NO_COLOR"): colorOutput = false - var outputLevel = PRINT_ALL + var outputLevel = OutputLevel.PRINT_ALL if envOutLvl.len > 0: for opt in countup(low(OutputLevel), high(OutputLevel)): if $opt == envOutLvl: @@ -240,17 +240,17 @@ method failureOccurred*(formatter: ConsoleOutputFormatter, method testEnded*(formatter: ConsoleOutputFormatter, testResult: TestResult) = formatter.isInTest = false - if formatter.outputLevel != PRINT_NONE and - (formatter.outputLevel == PRINT_ALL or testResult.status == FAILED): + if formatter.outputLevel != OutputLevel.PRINT_NONE and + (formatter.outputLevel == OutputLevel.PRINT_ALL or testResult.status == TestStatus.FAILED): let prefix = if testResult.suiteName.len > 0: " " else: "" template rawPrint() = echo(prefix, "[", $testResult.status, "] ", testResult.testName) when not defined(ECMAScript): if formatter.colorOutput and not defined(ECMAScript): var color = case testResult.status - of OK: fgGreen - of FAILED: fgRed - of SKIPPED: fgYellow + of TestStatus.OK: fgGreen + of TestStatus.FAILED: fgRed + of TestStatus.SKIPPED: fgYellow styledEcho styleBright, color, prefix, "[", $testResult.status, "] ", resetStyle, testResult.testName else: @@ -318,11 +318,11 @@ method testEnded*(formatter: JUnitOutputFormatter, testResult: TestResult) = formatter.stream.writeLine("\t\t" % [ xmlEscape(testResult.testName), timeStr]) case testResult.status - of OK: + of TestStatus.OK: discard - of SKIPPED: + of TestStatus.SKIPPED: formatter.stream.writeLine("") - of FAILED: + of TestStatus.FAILED: let failureMsg = if formatter.testStackTrace.len > 0 and formatter.testErrors.len > 0: xmlEscape(formatter.testErrors[^1]) @@ -498,7 +498,7 @@ template test*(name, body) {.dirty.} = if shouldRun(when declared(testSuiteName): testSuiteName else: "", name): checkpoints = @[] - var testStatusIMPL {.inject.} = OK + var testStatusIMPL {.inject.} = TestStatus.OK for formatter in formatters: formatter.testStarted(name) @@ -518,7 +518,7 @@ template test*(name, body) {.dirty.} = fail() finally: - if testStatusIMPL == FAILED: + if testStatusIMPL == TestStatus.FAILED: programResult = 1 let testResult = TestResult( suiteName: when declared(testSuiteName): testSuiteName else: "", @@ -558,7 +558,7 @@ template fail* = bind ensureInitialized when declared(testStatusIMPL): - testStatusIMPL = FAILED + testStatusIMPL = TestStatus.FAILED else: programResult = 1 @@ -589,7 +589,7 @@ template skip* = ## skip() bind checkpoints - testStatusIMPL = SKIPPED + testStatusIMPL = TestStatus.SKIPPED checkpoints = @[] macro check*(conditions: untyped): untyped = From ec20fd35447fea2a5da8538260397cea24051db5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20D=C3=B6ring?= Date: Sun, 20 Oct 2019 11:52:50 +0200 Subject: [PATCH 52/56] fix #12426 (#12462) --- compiler/cgen.nim | 5 +++-- tests/untestable/gdb/gdb_pretty_printer_test.py | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 5809a40491..71d7198140 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -997,13 +997,14 @@ proc genProcAux(m: BModule, prc: PSym) = closureSetup(p, prc) genStmts(p, procBody) # modifies p.locals, p.init, etc. var generatedProc: Rope + generatedProc.genCLineDir prc.info, m.config if sfNoReturn in prc.flags: if hasDeclspec in extccomp.CC[p.config.cCompiler].props: header = "__declspec(noreturn) " & header if sfPure in prc.flags: if hasDeclspec in extccomp.CC[p.config.cCompiler].props: header = "__declspec(naked) " & header - generatedProc = ropecg(p.module, "$N$1 {$n$2$3$4}$N$N", + generatedProc.add ropecg(p.module, "$1 {$n$2$3$4}$N$N", [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]) else: if m.hcrOn and isReloadable(m, prc): @@ -1011,7 +1012,7 @@ proc genProcAux(m: BModule, prc: PSym) = # This fixes the use of methods and also the case when 2 functions within the same module # call each other using directly the "_actual" versions (an optimization) - see issue #11608 addf(m.s[cfsProcHeaders], "$1;\n", [header]) - generatedProc = ropecg(p.module, "$N$1 {$N", [header]) + generatedProc.add ropecg(p.module, "$1 {", [header]) add(generatedProc, initGCFrame(p)) if optStackTrace in prc.options: add(generatedProc, p.s(cpsLocals)) diff --git a/tests/untestable/gdb/gdb_pretty_printer_test.py b/tests/untestable/gdb/gdb_pretty_printer_test.py index 54af65d9a4..f002941ec8 100644 --- a/tests/untestable/gdb/gdb_pretty_printer_test.py +++ b/tests/untestable/gdb/gdb_pretty_printer_test.py @@ -22,6 +22,9 @@ outputs = [ ] for i, expected in enumerate(outputs): + functionSymbol = gdb.selected_frame().block().function + assert functionSymbol.line == 21 + if i == 5: # myArray is passed as pointer to int to myDebug. I look up myArray up in the stack gdb.execute("up") From 38b3590e40b7267195c65168e6ff064775de4339 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 20 Oct 2019 22:37:31 +0200 Subject: [PATCH 53/56] fixes #12310 [backport] (#12470) --- compiler/vmgen.nim | 8 ++++++-- tests/vm/tmisc_vm.nim | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 09e02f8182..b528ff7bea 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -948,9 +948,13 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = c.genAddSubInt(n, dest, opcAddInt) of mInc, mDec: unused(c, n, dest) - let opc = if m == mInc: opcAddInt else: opcSubInt + let isUnsigned = n.sons[1].typ.skipTypes(abstractVarRange).kind in {tyUInt..tyUInt64} + let opc = if not isUnsigned: + if m == mInc: opcAddInt else: opcSubInt + else: + if m == mInc: opcAddu else: opcSubu let d = c.genx(n.sons[1]) - if n.sons[2].isInt8Lit: + if n.sons[2].isInt8Lit and not isUnsigned: c.gABI(n, succ(opc), d, d, n.sons[2].intVal) else: let tmp = c.genx(n.sons[2]) diff --git a/tests/vm/tmisc_vm.nim b/tests/vm/tmisc_vm.nim index 7d7275426c..57dc526c55 100644 --- a/tests/vm/tmisc_vm.nim +++ b/tests/vm/tmisc_vm.nim @@ -200,3 +200,17 @@ const vmCrash = oh_no() debugEcho vmCrash + + +# bug #12310 + +proc someTransform(s: var array[8, uint64]) = + var s1 = 5982491417506315008'u64 + s[1] += s1 + +static: + var state: array[8, uint64] + state[1] = 7105036623409894663'u64 + someTransform(state) + + doAssert state[1] == 13087528040916209671'u64 From 2ccd1c34284f08ba8e4c7b5b4986de8899f60354 Mon Sep 17 00:00:00 2001 From: Andy Davidoff Date: Tue, 22 Oct 2019 07:54:48 -0400 Subject: [PATCH 54/56] tweaked for clarity after editing to fix a typo (#12473) --- doc/gc.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/gc.rst b/doc/gc.rst index 693f4c3a07..af849e7134 100644 --- a/doc/gc.rst +++ b/doc/gc.rst @@ -162,8 +162,8 @@ you can pass ``--gc:`` on the compile command with the choosed garbage collector - ``--gc:regions`` `Stack `_ based garbage collector. - ``--gc:none`` No garbage collector. -The same Nim code can compile to use any of the garbage collectors, -the Nim syntax mostly wont change from one garbage collector to another. +The same Nim code can be compiled to use any of the garbage collectors; +the Nim syntax generally will not change from one garbage collector to another. No garbage collector is used for `JavaScript and NodeJS `_ compilation targets. `NimScript `_ target uses Nim VM garbage collector. From ad3c10022afa3047a9bee73967c0d319541745b4 Mon Sep 17 00:00:00 2001 From: Paul Tan Date: Wed, 23 Oct 2019 00:18:33 +0800 Subject: [PATCH 55/56] guards.nim:sameTree(): handle uint literals correctly (#12483) [backport] --- compiler/guards.nim | 2 +- tests/array/tarray.nim | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/compiler/guards.nim b/compiler/guards.nim index 52e0a1bdd9..8b7dc1d890 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -436,7 +436,7 @@ proc sameTree*(a, b: PNode): bool = if not result and a.sym.magic != mNone: result = a.sym.magic == b.sym.magic or sameOpr(a.sym, b.sym) of nkIdent: result = a.ident.id == b.ident.id - of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal + of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal of nkType: result = a.typ == b.typ diff --git a/tests/array/tarray.nim b/tests/array/tarray.nim index 30244173a7..27288bab30 100644 --- a/tests/array/tarray.nim +++ b/tests/array/tarray.nim @@ -582,3 +582,11 @@ template append2*(args: varargs[string, myAppend]): string = let foo = append2("1", "2", "3") echo foo + +block t12466: + # https://github.com/nim-lang/Nim/issues/12466 + var a: array[288, uint16] + for i in 0'u16 ..< 144'u16: + a[0'u16 + i] = i + for i in 0'u16 ..< 8'u16: + a[0'u16 + i] = i From 049032432c47f9036e2e4cc4830320947939c706 Mon Sep 17 00:00:00 2001 From: Artem V L Date: Tue, 22 Oct 2019 18:20:25 +0200 Subject: [PATCH 56/56] Docstring refined for the getSectionValue() (#12478) [backport] --- lib/pure/parsecfg.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index 4fd5647f67..49684a5e93 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -561,7 +561,7 @@ proc writeConfig*(dict: Config, filename: string) = dict.writeConfig(fileStream) proc getSectionValue*(dict: Config, section, key: string): string = - ## Gets the Key value of the specified Section. + ## Gets the Key value of the specified Section, returns an empty string if the key does not exist. if dict.hasKey(section): if dict[section].hasKey(key): result = dict[section][key]