From 66f37971e92ee9a573d1dd2fb82d5120e6ccb0ed Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 9 Jul 2016 00:28:14 +0200 Subject: [PATCH 01/25] undocumented feature: JS backend: unit and group separators generate hash and at symbols --- compiler/jsgen.nim | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 09eafe1285..744e190cd8 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1234,10 +1234,18 @@ proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType; genOtherArg(p, n, j, typ, generated, r) inc j inc i + of '\31': + # unit separator + add(r.res, "#") + inc i + of '\29': + # group separator + add(r.res, "@") + inc i else: let start = i while i < pat.len: - if pat[i] notin {'@', '#'}: inc(i) + if pat[i] notin {'@', '#', '\31', '\29'}: inc(i) else: break if i - 1 >= start: add(r.res, substr(pat, start, i - 1)) From 5e82ffc8d560dd3b2b7bbda034e5436fb036c20d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 9 Jul 2016 14:26:00 +0200 Subject: [PATCH 02/25] Nimscript: added support for 'patchFile' --- compiler/options.nim | 10 ++++++++++ compiler/scriptconfig.nim | 8 +++++++- lib/system/nimscript.nim | 15 +++++++++++++++ tests/newconfig/mymath.nim | 4 ++++ tests/newconfig/tfoo.nim | 6 ++++-- tests/newconfig/tfoo.nims | 2 ++ web/news/version_0_15_released.rst | 10 ++++++++++ 7 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 tests/newconfig/mymath.nim diff --git a/compiler/options.nim b/compiler/options.nim index 7797a4c824..fca945393f 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -151,6 +151,7 @@ const var gConfigVars* = newStringTable(modeStyleInsensitive) gDllOverrides = newStringTable(modeCaseInsensitive) + gModuleOverrides* = newStringTable(modeStyleInsensitive) gPrefixDir* = "" # Overrides the default prefix dir in getPrefixDir proc. libpath* = "" gProjectName* = "" # holds a name like 'nim' @@ -374,6 +375,13 @@ proc rawFindFile2(f: string): string = it = PStrEntry(it.next) result = "" +template patchModule() {.dirty.} = + if result.len > 0 and gModuleOverrides.len > 0: + let key = getPackageName(result) & "_" & splitFile(result).name + if gModuleOverrides.hasKey(key): + let ov = gModuleOverrides[key] + if ov.len > 0: result = ov + proc findFile*(f: string): string {.procvar.} = if f.isAbsolute: result = if f.existsFile: f else: "" @@ -385,6 +393,7 @@ proc findFile*(f: string): string {.procvar.} = result = f.rawFindFile2 if result.len == 0: result = f.toLower.rawFindFile2 + patchModule() proc findModule*(modulename, currentModule: string): string = # returns path to module @@ -403,6 +412,7 @@ proc findModule*(modulename, currentModule: string): string = result = currentPath / m if not existsFile(result): result = findFile(m) + patchModule() proc libCandidates*(s: string, dest: var seq[string]) = var le = strutils.find(s, '(') diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index ca42cc8fa7..dcb92227d1 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -13,7 +13,7 @@ import ast, modules, passes, passaux, condsyms, options, nimconf, lists, sem, semdata, llstream, vm, vmdef, commands, msgs, - os, times, osproc, wordrecg + os, times, osproc, wordrecg, strtabs # we support 'cmpIgnoreStyle' natively for efficiency: from strutils import cmpIgnoreStyle @@ -122,6 +122,12 @@ proc setupVM*(module: PSym; scriptName: string): PEvalContext = cbconf warningImpl: processSpecificNote(a.getString 0, wWarning, passPP, unknownLineInfo(), a.getString 1) + cbconf patchFile: + let key = a.getString(0) & "_" & a.getString(1) + var val = a.getString(2).addFileExt(NimExt) + if not isAbsolute(val): + val = vthisDir / val + gModuleOverrides[key] = val proc runNimScript*(scriptName: string; freshDefines=true) = passes.gIncludeFile = includeModule diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim index db6d72d7bb..cc96bcba88 100644 --- a/lib/system/nimscript.nim +++ b/lib/system/nimscript.nim @@ -65,6 +65,21 @@ proc hint*(name: string; val: bool) = let v = if val: "on" else: "off" hintImpl(name & "]:" & v, "hint[" & name & "]:" & v) +proc patchFile*(package, filename, replacement: string) = + ## Overrides the location of a given file belonging to the + ## passed package. + ## If the ``replacement`` is not an absolute path, the path + ## is interpreted to be local to the Nimscript file that contains + ## the call to ``patchFile``, Nim's ``--path`` is not used at all + ## to resolve the filename! + ## + ## Example: + ## + ## .. code-block:: nim + ## + ## patchFile("stdlib", "asyncdispatch", "patches/replacement") + discard + proc getCommand*(): string = ## Gets the Nim command that the compiler has been invoked with, for example ## "c", "js", "build", "help". diff --git a/tests/newconfig/mymath.nim b/tests/newconfig/mymath.nim new file mode 100644 index 0000000000..5668b448be --- /dev/null +++ b/tests/newconfig/mymath.nim @@ -0,0 +1,4 @@ + + +proc ln*(x: float): float = + return 0.5 diff --git a/tests/newconfig/tfoo.nim b/tests/newconfig/tfoo.nim index d593d4a756..2e10167b12 100644 --- a/tests/newconfig/tfoo.nim +++ b/tests/newconfig/tfoo.nim @@ -1,10 +1,12 @@ discard """ cmd: "nim default $file" - output: '''hello world!''' + output: '''hello world! 0.5''' msg: '''[NimScript] exec: gcc -v''' """ when not defined(definedefine): {.fatal: "wrong nim script configuration".} -echo "hello world!" +import math + +echo "hello world! ", ln 2.0 diff --git a/tests/newconfig/tfoo.nims b/tests/newconfig/tfoo.nims index 8d1461c78e..f87aba619e 100644 --- a/tests/newconfig/tfoo.nims +++ b/tests/newconfig/tfoo.nims @@ -11,6 +11,8 @@ import ospaths warning("uninit", off) hint("processing", off) +patchFile("stdlib", "math", "mymath") + task listDirs, "lists every subdirectory": for x in listDirs("."): echo "DIR ", x diff --git a/web/news/version_0_15_released.rst b/web/news/version_0_15_released.rst index e940a2da8e..0dfde1ce29 100644 --- a/web/news/version_0_15_released.rst +++ b/web/news/version_0_15_released.rst @@ -49,6 +49,16 @@ Compiler Additions - The ``-d/--define`` flag can now optionally take a value to be used by code at compile time. +Nimscript Additions +------------------- + +- Finally it's possible to dis/enable specific hints and warnings in + Nimscript via the procs ``warning`` and ``hint``. +- Nimscript exports a proc named ``patchFile`` which can be used to + patch modules or include files for different Nimble packages, including + the ``stdlib`` package. + + Language Additions ------------------ From a505fa631d8447c226f95b450e06d8fbd5be788f Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Sat, 9 Jul 2016 17:25:57 +0100 Subject: [PATCH 03/25] Fix "string literal as key expected" error Fix "Error: string literal as key expected expected" --- lib/pure/json.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 5198f5e008..b8e4a65630 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1127,7 +1127,7 @@ proc parseJson(p: var JsonParser): JsonNode = discard getTok(p) while p.tok != tkCurlyRi: if p.tok != tkString: - raiseParseErr(p, "string literal as key expected") + raiseParseErr(p, "string literal as key") var key = p.a discard getTok(p) eat(p, tkColon) From 2247ddd12df9f8bf550d614d60d1072070f31ccb Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 9 Jul 2016 22:45:55 +0200 Subject: [PATCH 04/25] make hint/warning work properly after Nimscript execution --- compiler/scriptconfig.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index dcb92227d1..1d34cd2bef 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -155,3 +155,4 @@ proc runNimScript*(scriptName: string; freshDefines=true) = #initDefines() undefSymbol("nimscript") undefSymbol("nimconfig") + gMainPackageNotes = {} From d7e172a6bc351ed926f93b77a14fc5cddbce3293 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 10 Jul 2016 01:16:40 +0200 Subject: [PATCH 05/25] make tests green again --- compiler/ast.nim | 1 - compiler/commands.nim | 3 +++ compiler/msgs.nim | 1 + compiler/scriptconfig.nim | 1 - config/nim.cfg | 9 --------- tests/newconfig/tfoo.nims | 2 +- 6 files changed, 5 insertions(+), 12 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 2b4de75cc9..5d587f35a8 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -965,7 +965,6 @@ const var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things var gMainPackageId*: int - gMainPackageNotes*: TNoteKinds proc isCallExpr*(n: PNode): bool = result = n.kind in nkCallKinds diff --git a/compiler/commands.nim b/compiler/commands.nim index 22512c563e..b468dd6b86 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -181,9 +181,11 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, case whichKeyword(substr(arg, i)) of wOn: incl(gNotes, n) + incl(gMainPackageNotes, n) incl(enableNotes, n) of wOff: excl(gNotes, n) + excl(gMainPackageNotes, n) incl(disableNotes, n) excl(ForeignPackageNotes, n) else: localError(info, errOnOrOffExpectedButXFound, arg) @@ -548,6 +550,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = gNotes = NotesVerbosity[gVerbosity] incl(gNotes, enableNotes) excl(gNotes, disableNotes) + gMainPackageNotes = gNotes of "parallelbuild": expectArg(switch, arg, pass, info) gNumberOfProcessors = parseInt(arg) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 098370e41f..03a63483da 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -621,6 +621,7 @@ var gHintCounter*: int = 0 gWarnCounter*: int = 0 gErrorMax*: int = 1 # stop after gErrorMax errors + gMainPackageNotes*: TNoteKinds = NotesVerbosity[1] proc unknownLineInfo*(): TLineInfo = result.line = int16(-1) diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index 1d34cd2bef..dcb92227d1 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -155,4 +155,3 @@ proc runNimScript*(scriptName: string; freshDefines=true) = #initDefines() undefSymbol("nimscript") undefSymbol("nimconfig") - gMainPackageNotes = {} diff --git a/config/nim.cfg b/config/nim.cfg index 93b8477840..0cc014a937 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -23,10 +23,6 @@ arm.linux.gcc.linkerexe = "arm-linux-gcc" mips.linux.gcc.exe = "mips-openwrt-linux-gcc" mips.linux.gcc.linkerexe = "mips-openwrt-linux-gcc" -@if not nimfix: - cs:partial -@end - path="$lib/deprecated/core" path="$lib/deprecated/pure" path="$lib/pure/collections" @@ -168,10 +164,5 @@ vcc.options.always = "/nologo" vcc.options.speed = "/O2 /arch:SSE2" vcc.options.size = "/O1" -# Configuration for the Digital Mars C/C++ compiler: -@if windows: - dmc.path = r"$nimrod\dist\dm\bin" -@end - # Configuration for the Tiny C Compiler: tcc.options.always = "-w" diff --git a/tests/newconfig/tfoo.nims b/tests/newconfig/tfoo.nims index f87aba619e..057c0ed923 100644 --- a/tests/newconfig/tfoo.nims +++ b/tests/newconfig/tfoo.nims @@ -10,7 +10,7 @@ import ospaths warning("uninit", off) hint("processing", off) - +#--verbosity:2 patchFile("stdlib", "math", "mymath") task listDirs, "lists every subdirectory": From 90a5edfa6dc6ac781ddacbba07c8e10bd9aee871 Mon Sep 17 00:00:00 2001 From: Matthew Baulch Date: Mon, 11 Jul 2016 15:10:54 +1000 Subject: [PATCH 06/25] Fix #4422: Reset queue element on pop. Prevent NimVM confusion. Help GC. --- lib/pure/collections/queues.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pure/collections/queues.nim b/lib/pure/collections/queues.nim index 9118165186..399e4d4136 100644 --- a/lib/pure/collections/queues.nim +++ b/lib/pure/collections/queues.nim @@ -152,11 +152,13 @@ proc add*[T](q: var Queue[T], item: T) = q.data[q.wr] = item q.wr = (q.wr + 1) and q.mask +proc default[T](t: typedesc[T]): T {.inline.} = discard proc pop*[T](q: var Queue[T]): T {.inline, discardable.} = ## Remove and returns the first (oldest) element of the queue `q`. emptyCheck(q) dec q.count result = q.data[q.rd] + q.data[q.rd] = default(type(result)) q.rd = (q.rd + 1) and q.mask proc enqueue*[T](q: var Queue[T], item: T) = From d05e146b30aef398164d11e04175c375c74d9463 Mon Sep 17 00:00:00 2001 From: Matthew Baulch Date: Mon, 11 Jul 2016 19:12:05 +1000 Subject: [PATCH 07/25] Recursively check literals for tyEmpty. --- compiler/semstmts.nim | 10 ++++++++-- tests/types/tassignemptytuple.nim | 11 +++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 tests/types/tassignemptytuple.nim diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 0fb7708756..40462a1da3 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -411,6 +411,13 @@ proc semUsing(c: PContext; n: PNode): PNode = if a.sons[length-1].kind != nkEmpty: localError(a.info, "'using' sections cannot contain assignments") +proc hasEmpty(typ: PType): bool = + if typ.kind in {tySequence, tyArray, tySet}: + result = typ.lastSon.kind == tyEmpty + elif typ.kind == tyTuple: + for s in typ.sons: + result = result or hasEmpty(s) + proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = var b: PNode result = copyNode(n) @@ -445,8 +452,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = #changeType(def.skipConv, typ, check=true) else: typ = skipIntLit(def.typ) - if typ.kind in {tySequence, tyArray, tySet} and - typ.lastSon.kind == tyEmpty: + if hasEmpty(typ): localError(def.info, errCannotInferTypeOfTheLiteral, ($typ.kind).substr(2).toLower) else: diff --git a/tests/types/tassignemptytuple.nim b/tests/types/tassignemptytuple.nim new file mode 100644 index 0000000000..bdfc653a5e --- /dev/null +++ b/tests/types/tassignemptytuple.nim @@ -0,0 +1,11 @@ +discard """ + file: "tassignemptytuple.nim" + line: 11 + errormsg: "cannot infer the type of the tuple" +""" + +var + foo: seq[int] + bar: tuple[a: seq[int], b: set[char]] + +(foo, bar) = (@[], (@[], {})) From 59d17cb341d4348b16a80c36ecc6e6e3c9f9c6a2 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Mon, 11 Jul 2016 16:23:15 +0300 Subject: [PATCH 08/25] Fixed crash with leakDetector and threads enabled. --- lib/system/gc.nim | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 3e71b4fe09..a36dbf02b9 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -452,10 +452,13 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer = gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2") # now it is buffered in the ZCT res.typ = typ - when leakDetector and not hasThreadSupport: - if framePtr != nil and framePtr.prev != nil: - res.filename = framePtr.prev.filename - res.line = framePtr.prev.line + when leakDetector: + res.filename = nil + res.line = 0 + when not hasThreadSupport: + if framePtr != nil and framePtr.prev != nil: + res.filename = framePtr.prev.filename + res.line = framePtr.prev.line # refcount is zero, color is black, but mark it to be in the ZCT res.refcount = ZctFlag sysAssert(isAllocatedPtr(gch.region, res), "newObj: 3") @@ -503,10 +506,13 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} = sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2") # now it is buffered in the ZCT res.typ = typ - when leakDetector and not hasThreadSupport: - if framePtr != nil and framePtr.prev != nil: - res.filename = framePtr.prev.filename - res.line = framePtr.prev.line + when leakDetector: + res.filename = nil + res.line = 0 + when not hasThreadSupport: + if framePtr != nil and framePtr.prev != nil: + res.filename = framePtr.prev.filename + res.line = framePtr.prev.line res.refcount = rcIncrement # refcount is 1 sysAssert(isAllocatedPtr(gch.region, res), "newObj: 3") when logGC: writeCell("new cell", res) From 56015e52b9028097446e06bc3f09581992e6d692 Mon Sep 17 00:00:00 2001 From: Kier Davis Date: Mon, 11 Jul 2016 14:53:37 +0100 Subject: [PATCH 09/25] Fix #4475 Existing implementation would append the default value for a varargs parameter (the empty array) to the end of the sons of the nnkCall node, rather than storing it into the correct index. This left the location where it should have been stored set to its default value of nil, causing later code that uses this node to segfault. --- compiler/sigmatch.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 511a44954f..8c8c83d0fb 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1746,8 +1746,8 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) = if formal.ast == nil: if formal.typ.kind == tyVarargs: var container = newNodeIT(nkBracket, n.info, arrayConstr(c, n.info)) - addSon(m.call, implicitConv(nkHiddenStdConv, formal.typ, - container, m, c)) + setSon(m.call, formal.position + 1, + implicitConv(nkHiddenStdConv, formal.typ, container, m, c)) else: # no default value m.state = csNoMatch From 023f1da40a1343dab0e3d8d2f1ef3bf08b55f91a Mon Sep 17 00:00:00 2001 From: Kier Davis Date: Mon, 11 Jul 2016 15:16:23 +0100 Subject: [PATCH 10/25] Add regression test for fix for #4475 --- tests/overload/tissue4475.nim | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/overload/tissue4475.nim diff --git a/tests/overload/tissue4475.nim b/tests/overload/tissue4475.nim new file mode 100644 index 0000000000..34618cac57 --- /dev/null +++ b/tests/overload/tissue4475.nim @@ -0,0 +1,6 @@ +# Bug: https://github.com/nim-lang/Nim/issues/4475 +# Fix: https://github.com/nim-lang/Nim/pull/4477 + +proc test(x: varargs[string], y: int) = discard + +test(y = 1) From c9ce38e56dba0f0c37a4193311e1120ba2d12c0e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 11 Jul 2016 11:11:21 +0200 Subject: [PATCH 11/25] fixes a strange JS codegen bug --- compiler/jsgen.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 744e190cd8..0ac779822b 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1049,6 +1049,8 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) = else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')') of nkObjDownConv: gen(p, n.sons[0], r) + of nkHiddenDeref: + gen(p, n.sons[0].sons[0], r) else: internalError(n.sons[0].info, "genAddr: " & $n.sons[0].kind) proc thisParam(p: PProc; typ: PType): PType = From bcb2365decb4fce8bd0be9e8e7a855a86fbcc202 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 11 Jul 2016 23:15:37 +0200 Subject: [PATCH 12/25] fixes a critical JS codegen bug which caused 'importcpp' statements not to be emitted --- compiler/jsgen.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 0ac779822b..be529072c1 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1223,6 +1223,7 @@ proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType; r: var TCompRes) = var i = 0 var j = 1 + r.kind = resExpr while i < pat.len: case pat[i] of '@': From 7a018007a442c74602fc6819ff5eb30697cbbf49 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 12 Jul 2016 00:50:25 +0200 Subject: [PATCH 13/25] fixes #4471 --- compiler/jsgen.nim | 18 +++++++++++++++--- tests/js/tstring_assignment.nim | 11 +++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 tests/js/tstring_assignment.nim diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index be529072c1..24e01db608 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -48,6 +48,7 @@ type etyNull, # null type etyProc, # proc type etyBool, # bool type + etySeq, # Nim seq or string type etyInt, # JavaScript's int etyFloat, # JavaScript's float etyString, # JavaScript's string @@ -156,7 +157,7 @@ proc mapType(typ: PType): TJSTypeKind = of tyBool: result = etyBool of tyFloat..tyFloat128: result = etyFloat of tySet: result = etyObject # map a set to a table - of tyString, tySequence: result = etyInt # little hack to get right semantics + of tyString, tySequence: result = etySeq of tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, tyBigNum, tyVarargs: result = etyObject @@ -817,7 +818,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = addf(p.body, "$#[$#] = chr($#);$n", [a.rdLoc, b.rdLoc, c.rdLoc]) return - let xtyp = mapType(p, x.typ) + var xtyp = mapType(p, x.typ) if x.kind == nkHiddenDeref and x.sons[0].kind == nkCall and xtyp != etyObject: gen(p, x.sons[0], a) @@ -829,7 +830,18 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = gen(p, y, b) + # we don't care if it's an etyBaseIndex (global) of a string, it's + # still a string that needs to be copied properly: + if x.typ.skipTypes(abstractInst).kind in {tySequence, tyString}: + xtyp = etySeq case xtyp + of etySeq: + if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: + addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) + else: + useMagic(p, "nimCopy") + addf(p.body, "$1 = nimCopy(null, $2, $3);$n", + [a.rdLoc, b.res, genTypeInfo(p, y.typ)]) of etyObject: if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) @@ -1430,7 +1442,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) = discard mangleName(v, p.target) gen(p, n, a) case mapType(p, v.typ) - of etyObject: + of etyObject, etySeq: if needsNoCopy(p, n): s = a.res else: diff --git a/tests/js/tstring_assignment.nim b/tests/js/tstring_assignment.nim new file mode 100644 index 0000000000..bdd93e6b55 --- /dev/null +++ b/tests/js/tstring_assignment.nim @@ -0,0 +1,11 @@ +discard """ + output: '''true''' +""" + +# bug #4471 +when true: + let s1 = "123" + var s2 = s1 + s2.setLen(0) + # fails - s1.len == 0 + echo s1.len == 3 From 56f99f56ac20647017199c0e947a67ae9a806e81 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 12 Jul 2016 01:05:52 +0200 Subject: [PATCH 14/25] fixes edge cases in the lexer --- compiler/lexer.nim | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 8b201431e7..c6b11443d0 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -735,7 +735,8 @@ proc getSymbol(L: var TLexer, tok: var TToken) = if c == '\226' and buf[pos+1] == '\128' and buf[pos+2] == '\147': # It's a 'magic separator' en-dash Unicode - if buf[pos + magicIdentSeparatorRuneByteWidth] notin SymChars: + if buf[pos + magicIdentSeparatorRuneByteWidth] notin SymChars or + isMagicIdentSeparatorRune(buf, pos+magicIdentSeparatorRuneByteWidth) or pos == L.bufpos: lexMessage(L, errInvalidToken, "–") break inc(pos, magicIdentSeparatorRuneByteWidth) @@ -747,7 +748,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) = h = h !& ord(c) inc(pos) of '_': - if buf[pos+1] notin SymChars: + if buf[pos+1] notin SymChars or isMagicIdentSeparatorRune(buf, pos+1): lexMessage(L, errInvalidToken, "_") break inc(pos) @@ -1056,7 +1057,8 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = inc(L.bufpos) of '_': inc(L.bufpos) - if L.buf[L.bufpos] notin SymChars: + if L.buf[L.bufpos] notin SymChars+{'_'} and not + isMagicIdentSeparatorRune(L.buf, L.bufpos): tok.tokType = tkSymbol tok.ident = getIdent("_") else: From 84c3830c6bb7b73a526dff81946ba53ebd4f0edb Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 12 Jul 2016 02:14:26 +0200 Subject: [PATCH 15/25] fixes #4301 --- compiler/lexer.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index c6b11443d0..0a96ed0ba1 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -1079,6 +1079,9 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) = tok.tokType = tkCharLit of '0'..'9': getNumber(L, tok) + let c = L.buf[L.bufpos] + if c in SymChars+{'_'}: + lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')') else: if c in OpChars: getOperator(L, tok) From 8d4614b5ab4fbf8ccb34875c2c2f1e7dcddcc2ee Mon Sep 17 00:00:00 2001 From: Axel Pahl Date: Tue, 12 Jul 2016 09:43:31 +0200 Subject: [PATCH 16/25] explain difference between Table and TableRef in tables.nim --- lib/pure/collections/tables.nim | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index e454a43cbe..9feea37468 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -16,6 +16,39 @@ ## semantics, this means that ``=`` performs a copy of the hash table. ## For **reference** semantics use the ``Ref`` variant: ``TableRef``, ## ``OrderedTableRef``, ``CountTableRef``. +## To give an example, when `a` is a Table, then `var b = a` gives `b` +## as a new independent table. b is initialised with the contents of `a`. +## Changing `b` does not affect `a` and vice versa: +## +## .. code-block:: +## import tables +## +## var +## a = toTable([(1, "one"), (2, "two")]) # creates a Table +## b = a +## +## echo a, b # output: {1: one, 2: two}{1: one, 2: two} +## +## b[3] = "three" +## echo a, b # output: {1: one, 2: two}{1: one, 2: two, 3: three} +## echo a == b # output: false +## +## On the other hand, when `a` is a TableRef instead, then changes to `b` also affect `a`. +## Both `a` and `b` reference the same data structure: +## +## .. code-block:: +## import tables +## +## var +## a = newTable([(1, "one"), (2, "two")]) # creates a TableRef +## b = a +## +## echo a, b # output: {1: one, 2: two}{1: one, 2: two} +## +## b[3] = "three" +## echo a, b # output: {1: one, 2: two, 3: three}{1: one, 2: two, 3: three} +## echo a == b # output: true +## ## ## If you are using simple standard types like ``int`` or ``string`` for the ## keys of the table you won't have any problems, but as soon as you try to use From 4f7a2e9def798b708ec48585c6553d258b6e4890 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 12 Jul 2016 10:26:43 +0200 Subject: [PATCH 17/25] fixes #4358 --- compiler/semexprs.nim | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index f8723bf64c..17feab85d7 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1065,8 +1065,11 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = result = newSymNode(s, n.info) result.typ = makeTypeDesc(c, s.typ) of skField: - if c.p != nil and c.p.selfSym != nil: - var ty = skipTypes(c.p.selfSym.typ, {tyGenericInst, tyVar, tyPtr, tyRef}) + var p = c.p + while p != nil and p.selfSym == nil: + p = p.next + if p != nil and p.selfSym != nil: + var ty = skipTypes(p.selfSym.typ, {tyGenericInst, tyVar, tyPtr, tyRef}) while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct}) var check: PNode = nil if ty.kind == tyObject: @@ -1079,7 +1082,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = markUsed(n.info, f) styleCheckUse(n.info, f) result = newNodeIT(nkDotExpr, n.info, f.typ) - result.add makeDeref(newSymNode(c.p.selfSym)) + result.add makeDeref(newSymNode(p.selfSym)) result.add newSymNode(f) # we now have the correct field if check != nil: check.sons[0] = result From 928222cc679639b694ef4a8635762be7e00c7ade Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 12 Jul 2016 10:31:36 +0200 Subject: [PATCH 18/25] fixes #4429 --- compiler/types.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/types.nim b/compiler/types.nim index 4d6bf05023..063eb0757a 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -541,7 +541,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = else: result.add typeToString(t.sons[0]) of tyRange: - result = "range " & rangeToStr(t.n) + result = "range " + if t.n != nil and t.n.kind == nkRange: + result.add rangeToStr(t.n) if prefer != preferExported: result.add("(" & typeToString(t.sons[0]) & ")") of tyProc: From 6de1333a26844a1749d2795f111ceccc2debc886 Mon Sep 17 00:00:00 2001 From: Axel Pahl Date: Tue, 12 Jul 2016 10:45:54 +0200 Subject: [PATCH 19/25] use table literal syntax --- lib/pure/collections/tables.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 9feea37468..941516956a 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -24,7 +24,7 @@ ## import tables ## ## var -## a = toTable([(1, "one"), (2, "two")]) # creates a Table +## a = {1: "one", 2: "two"}.toTable # creates a Table ## b = a ## ## echo a, b # output: {1: one, 2: two}{1: one, 2: two} @@ -40,7 +40,7 @@ ## import tables ## ## var -## a = newTable([(1, "one"), (2, "two")]) # creates a TableRef +## a = {1: "one", 2: "two"}.newTable # creates a TableRef ## b = a ## ## echo a, b # output: {1: one, 2: two}{1: one, 2: two} From 8dd27a66997b870fd325f4cd7b0b2003a8f285e9 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 12 Jul 2016 20:23:10 +0200 Subject: [PATCH 20/25] fixes #2730 --- compiler/vmgen.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index abb88b7b93..f0434617bb 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1686,10 +1686,10 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = of skType: genTypeLit(c, s.typ, dest) of skGenericParam: - if c.prc.sym.kind == skMacro: + if c.prc.sym != nil and c.prc.sym.kind == skMacro: genRdVar(c, n, dest, flags) else: - internalError(n.info, "cannot generate code for: " & s.name.s) + globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s) else: globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s) of nkCallKinds: From f47165af11f71acf872ab9fd5ab56e3465b19dad Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 12 Jul 2016 20:38:31 +0200 Subject: [PATCH 21/25] fixes #3706 --- compiler/ccgtypes.nim | 11 +++++++++++ compiler/jsgen.nim | 11 ++++++++++- compiler/jstypes.nim | 3 +++ compiler/types.nim | 3 +++ tests/metatype/tmodulo.nim | 20 ++++++++++++++++++++ 5 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 tests/metatype/tmodulo.nim diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index a10f3b8383..34a16c8599 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -150,6 +150,9 @@ proc mapType(typ: PType): TCTypeKind = of tyCString: result = ctCString of tyInt..tyUInt64: result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt)) + of tyStatic: + if typ.n != nil: result = mapType(lastSon typ) + else: internalError("mapType") else: internalError("mapType") proc mapReturnType(typ: PType): TCTypeKind = @@ -256,6 +259,11 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope = of tyInt..tyUInt64: result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind]) of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0]) + of tyStatic: + if typ.n != nil: result = getSimpleTypeDesc(m, lastSon typ) + else: internalError("tyStatic for getSimpleTypeDesc") + of tyGenericInst: + result = getSimpleTypeDesc(m, lastSon typ) else: result = nil proc pushType(m: BModule, typ: PType) = @@ -1025,6 +1033,9 @@ proc genTypeInfo(m: BModule, t: PType): Rope = of tyEmpty, tyVoid: result = rope"0" of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar: genTypeInfoAuxBase(m, t, t, result, rope"0") + of tyStatic: + if t.n != nil: result = genTypeInfo(m, lastSon t) + else: internalError("genTypeInfo(" & $t.kind & ')') of tyProc: if t.callConv != ccClosure: genTypeInfoAuxBase(m, t, t, result, rope"0") diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 24e01db608..fe0f6df532 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -164,8 +164,11 @@ proc mapType(typ: PType): TJSTypeKind = of tyNil: result = etyNull of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvocation, tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor, - tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses, tyVoid: + tyExpr, tyStmt, tyTypeDesc, tyTypeClasses, tyVoid: result = etyNone + of tyStatic: + if t.n != nil: result = mapType(lastSon t) + else: result = etyNone of tyProc: result = etyProc of tyCString: result = etyString @@ -1427,6 +1430,12 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = result = putToSeq("null", indirect) of tySequence, tyString, tyCString, tyPointer, tyProc: result = putToSeq("null", indirect) + of tyStatic: + if t.n != nil: + result = createVar(p, lastSon t, indirect) + else: + internalError("createVar: " & $t.kind) + result = nil else: internalError("createVar: " & $t.kind) result = nil diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim index 8d109e48a3..cf1679ee4a 100644 --- a/compiler/jstypes.nim +++ b/compiler/jstypes.nim @@ -165,4 +165,7 @@ proc genTypeInfo(p: PProc, typ: PType): Rope = of tyEnum: genEnumInfo(p, t, result) of tyObject: genObjectInfo(p, t, result) of tyTuple: genTupleInfo(p, t, result) + of tyStatic: + if t.n != nil: result = genTypeInfo(p, lastSon t) + else: internalError("genTypeInfo(" & $t.kind & ')') else: internalError("genTypeInfo(" & $t.kind & ')') diff --git a/compiler/types.nim b/compiler/types.nim index 063eb0757a..a87f9470fa 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1317,6 +1317,9 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt = of tyTypeDesc: result = computeSizeAux(typ.base, a) of tyForward: return szIllegalRecursion + of tyStatic: + if typ.n != nil: result = computeSizeAux(lastSon(typ), a) + else: result = szUnknownSize else: #internalError("computeSizeAux()") result = szUnknownSize diff --git a/tests/metatype/tmodulo.nim b/tests/metatype/tmodulo.nim new file mode 100644 index 0000000000..08bcc7935e --- /dev/null +++ b/tests/metatype/tmodulo.nim @@ -0,0 +1,20 @@ +discard """ + output: '''1 mod 7''' +""" + +# bug #3706 + +type Modulo[M: static[int]] = distinct int + +proc modulo(a: int, M: static[int]): Modulo[M] = Modulo[M](a %% M) + +proc `+`[M: static[int]](a, b: Modulo[M]): Modulo[M] = (a.int + b.int).modulo(M) + +proc `$`*[M: static[int]](a: Modulo[M]): string = $(a.int) & " mod " & $(M) + +when isMainModule: + let + a = 3.modulo(7) + b = 5.modulo(7) + echo a + b + From 813828f6907ce05756145c57bc6dd4758ffb2a7e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 12 Jul 2016 22:35:55 +0200 Subject: [PATCH 22/25] the Nim compiler supports the jsondoc2 command --- compiler/docgen.nim | 56 +++++++++++++++++++++++++++----------------- compiler/docgen2.nim | 17 ++++++++++++++ compiler/main.nim | 15 ++++++++---- doc/advopt.txt | 1 + 4 files changed, 64 insertions(+), 25 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index fab7598485..4bd10437d4 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -25,6 +25,7 @@ type indexValFilename: string analytics: string # Google Analytics javascript, "" if doesn't exist seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML. + jArray: JsonNode PDoc* = ref TDocumentor ## Alias to type less. @@ -81,6 +82,7 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc = result.seenSymbols = newStringTable(modeCaseInsensitive) result.id = 100 + result.jArray = newJArray() proc dispA(dest: var Rope, xml, tex: string, args: openArray[Rope]) = if gCmd != cmdRst2tex: addf(dest, xml, args) @@ -439,7 +441,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = setIndexTerm(d[], symbolOrId, name, linkTitle, xmltree.escape(plainDocstring.docstringSummary)) -proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode = +proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode = if not isVisible(nameNode): return var name = getName(d, nameNode) @@ -499,46 +501,44 @@ proc generateDoc*(d: PDoc, n: PNode) = of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0]) else: discard -proc generateJson(d: PDoc, n: PNode, jArray: JsonNode = nil): JsonNode = +proc add(d: PDoc; j: JsonNode) = + if j != nil: d.jArray.add j + +proc generateJson*(d: PDoc, n: PNode) = case n.kind of nkCommentStmt: if n.comment != nil and startsWith(n.comment, "##"): let stripped = n.comment.substr(2).strip - result = %{ "comment": %stripped } + d.add %{ "comment": %stripped } of nkProcDef: when useEffectSystem: documentRaises(n) - result = genJSONItem(d, n, n.sons[namePos], skProc) + d.add genJsonItem(d, n, n.sons[namePos], skProc) of nkMethodDef: when useEffectSystem: documentRaises(n) - result = genJSONItem(d, n, n.sons[namePos], skMethod) + d.add genJsonItem(d, n, n.sons[namePos], skMethod) of nkIteratorDef: when useEffectSystem: documentRaises(n) - result = genJSONItem(d, n, n.sons[namePos], skIterator) + d.add genJsonItem(d, n, n.sons[namePos], skIterator) of nkMacroDef: - result = genJSONItem(d, n, n.sons[namePos], skMacro) + d.add genJsonItem(d, n, n.sons[namePos], skMacro) of nkTemplateDef: - result = genJSONItem(d, n, n.sons[namePos], skTemplate) + d.add genJsonItem(d, n, n.sons[namePos], skTemplate) of nkConverterDef: when useEffectSystem: documentRaises(n) - result = genJSONItem(d, n, n.sons[namePos], skConverter) + d.add genJsonItem(d, n, n.sons[namePos], skConverter) of nkTypeSection, nkVarSection, nkLetSection, nkConstSection: for i in countup(0, sonsLen(n) - 1): if n.sons[i].kind != nkCommentStmt: # order is always 'type var let const': - result = genJSONItem(d, n.sons[i], n.sons[i].sons[0], + d.add genJsonItem(d, n.sons[i], n.sons[i].sons[0], succ(skType, ord(n.kind)-ord(nkTypeSection))) of nkStmtList: - result = if jArray != nil: jArray else: newJArray() - for i in countup(0, sonsLen(n) - 1): - var r = generateJson(d, n.sons[i], result) - if r != nil: - result.add(r) - + generateJson(d, n.sons[i]) of nkWhenStmt: # generate documentation for the first branch only: - if not checkForFalse(n.sons[0].sons[0]) and jArray != nil: - discard generateJson(d, lastSon(n.sons[0]), jArray) + if not checkForFalse(n.sons[0].sons[0]): + generateJson(d, lastSon(n.sons[0])) else: discard proc genSection(d: PDoc, kind: TSymKind) = @@ -607,6 +607,19 @@ proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) = else: writeRope(content, getOutFile(filename, outExt), useWarning) +proc writeOutputJson*(d: PDoc, filename, outExt: string, + useWarning = false) = + let content = $d.jArray + if optStdout in gGlobalOptions: + write(stdout, content) + else: + var f: File + if open(f, getOutFile(filename, outExt), fmWrite): + write(f, content) + close(f) + else: + discard "fixme: error report" + proc commandDoc*() = var ast = parseFile(gProjectMainIdx) if ast == nil: return @@ -636,13 +649,14 @@ proc commandRst2TeX*() = splitter = "\\-" commandRstAux(gProjectFull, TexExt) -proc commandJSON*() = +proc commandJson*() = var ast = parseFile(gProjectMainIdx) if ast == nil: return var d = newDocumentor(gProjectFull, options.gConfigVars) d.hasToc = true - var json = generateJson(d, ast) - var content = rope(pretty(json)) + generateJson(d, ast) + let json = d.jArray + let content = rope(pretty(json)) if optStdout in gGlobalOptions: writeRope(stdout, content) diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim index 27de068116..f83166f2b3 100644 --- a/compiler/docgen2.nim +++ b/compiler/docgen2.nim @@ -29,11 +29,26 @@ proc close(p: PPassContext, n: PNode): PNode = except IOError: discard +proc closeJson(p: PPassContext, n: PNode): PNode = + var g = PGen(p) + let useWarning = sfMainModule notin g.module.flags + if gWholeProject or sfMainModule in g.module.flags: + writeOutputJson(g.doc, g.module.filename, ".json", useWarning) + try: + generateIndex(g.doc) + except IOError: + discard + proc processNode(c: PPassContext, n: PNode): PNode = result = n var g = PGen(c) generateDoc(g.doc, n) +proc processNodeJson(c: PPassContext, n: PNode): PNode = + result = n + var g = PGen(c) + generateJson(g.doc, n) + proc myOpen(module: PSym): PPassContext = var g: PGen new(g) @@ -44,6 +59,8 @@ proc myOpen(module: PSym): PPassContext = result = g const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close) +const docgen2JsonPass* = makePass(open = myOpen, process = processNodeJson, + close = closeJson) proc finishDoc2Pass*(project: string) = discard diff --git a/compiler/main.nim b/compiler/main.nim index b1b9006bd9..0db66b53ea 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -46,10 +46,11 @@ proc commandCheck = rodPass() compileProject() -proc commandDoc2 = +proc commandDoc2(json: bool) = msgs.gErrorMax = high(int) # do not stop after first error semanticPasses() - registerPass(docgen2Pass) + if json: registerPass(docgen2JsonPass) + else: registerPass(docgen2Pass) #registerPass(cleanupPass()) compileProject() finishDoc2Pass(gProjectName) @@ -281,7 +282,7 @@ proc mainCommand* = gCmd = cmdDoc loadConfigs(DocConfig) defineSymbol("nimdoc") - commandDoc2() + commandDoc2(false) of "rst2html": gCmd = cmdRst2html loadConfigs(DocConfig) @@ -296,7 +297,13 @@ proc mainCommand* = loadConfigs(DocConfig) wantMainModule() defineSymbol("nimdoc") - commandJSON() + commandJson() + of "jsondoc2": + gCmd = cmdDoc + loadConfigs(DocConfig) + wantMainModule() + defineSymbol("nimdoc") + commandDoc2(true) of "buildindex": gCmd = cmdDoc loadConfigs(DocConfig) diff --git a/doc/advopt.txt b/doc/advopt.txt index 02aada4fbd..02e69c5b8c 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -6,6 +6,7 @@ Advanced commands: //rst2html convert a reStructuredText file to HTML //rst2tex convert a reStructuredText file to TeX //jsondoc extract the documentation to a json file + //jsondoc2 extract documentation to a json file (uses doc2) //buildIndex build an index for the whole documentation //run run the project (with Tiny C backend; buggy!) //genDepend generate a DOT file containing the From 7df8b4bb435dc40ae4bf919c215980e12e187fc7 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 13 Jul 2016 21:26:37 +0200 Subject: [PATCH 23/25] nimsuggest: dependencies are recalculated properly --- compiler/modules.nim | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/modules.nim b/compiler/modules.nim index 03b9dc9f0a..d653e8b8f3 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -105,12 +105,13 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile = resetModule(fileIdx) return Yes - if gMemCacheData[fileIdx].needsRecompile != Maybe: - return gMemCacheData[fileIdx].needsRecompile + # cycle detection: We claim that a cycle does no harm. + if gMemCacheData[fileIdx].needsRecompile == Probing: + return No + #return gMemCacheData[fileIdx].needsRecompile - if optForceFullMake in gGlobalOptions or - hashChanged(fileIdx): - markDirty + if optForceFullMake in gGlobalOptions or hashChanged(fileIdx): + markDirty() if gMemCacheData[fileIdx].deps != nil: gMemCacheData[fileIdx].needsRecompile = Probing @@ -118,7 +119,7 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile = let d = checkDepMem(dep) if d in {Yes, Recompiled}: # echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d - markDirty + markDirty() gMemCacheData[fileIdx].needsRecompile = No return No From b43d5148c5ffa3da82199a915b4f2887a9e82fec Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 13 Jul 2016 21:26:58 +0200 Subject: [PATCH 24/25] --listCmd also needs to affect linking step --- compiler/extccomp.nim | 2 +- compiler/msgs.nim | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index b2ee9c7f14..eb9aac4902 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -754,7 +754,7 @@ proc callCCompiler*(projectfile: string) = "lib", quoteShell(libpath)]) if optCompileOnly notin gGlobalOptions: execExternalProgram(linkCmd, - if gVerbosity > 1: hintExecuting else: hintLinking) + if optListCmd in gGlobalOptions or gVerbosity > 1: hintExecuting else: hintLinking) else: linkCmd = "" if optGenScript in gGlobalOptions: diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 03a63483da..83914753fa 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -518,7 +518,6 @@ const warnGcUnsafe, hintPath, hintDependency, - hintExecuting, hintCodeBegin, hintCodeEnd, hintSource, hintStackTrace, hintGCStats}, @@ -530,7 +529,7 @@ const var ForeignPackageNotes*: TNoteKinds = {hintProcessing, warnUnknownMagic, - hintQuitCalled} + hintQuitCalled, hintExecuting} filenameToIndexTbl = initTable[string, int32]() fileInfos*: seq[TFileInfo] = @[] systemFileIdx*: int32 From 491e8d04ec3d1631f5bde71148649b05c27d8b7d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 13 Jul 2016 21:27:39 +0200 Subject: [PATCH 25/25] docgen improvement: hidden 'attachedType' span is generated for upcoming docgen improvements --- compiler/docgen.nim | 52 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 4bd10437d4..67092780bb 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -14,7 +14,7 @@ import ast, strutils, strtabs, options, msgs, os, ropes, idents, wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite, - importer, sempass2, json, xmltree, cgi, typesrenderer + importer, sempass2, json, xmltree, cgi, typesrenderer, astalgo type TSections = array[TSymKind, Rope] @@ -26,9 +26,31 @@ type analytics: string # Google Analytics javascript, "" if doesn't exist seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML. jArray: JsonNode + types: TStrTable PDoc* = ref TDocumentor ## Alias to type less. +proc whichType(d: PDoc; n: PNode): PSym = + if n.kind == nkSym: + if d.types.strTableContains(n.sym): + result = n.sym + else: + for i in 0.. 1: check(1) + if params.len > 0: check(0) + for i in 2..$1", "\\spanOther{$1}", [rope(esc(d.target, literal))]) + + if k in routineKinds and nameNode.kind == nkSym: + let att = attachToType(d, nameNode.sym) + if att != nil: + dispA(result, """""", "", + [rope esc(d.target, att.name.s)]) inc(d.id) let plainNameRope = rope(xmltree.escape(plainName.strip)) @@ -440,6 +488,8 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = setIndexTerm(d[], symbolOrId, name, linkTitle, xmltree.escape(plainDocstring.docstringSummary)) + if k == skType and nameNode.kind == nkSym: + d.types.strTableAdd nameNode.sym proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode = if not isVisible(nameNode): return