From 4099abc8675ca37e713098c211bfe73aabd34259 Mon Sep 17 00:00:00 2001 From: Billingsly Wetherfordshire Date: Sat, 3 May 2014 16:49:41 -0500 Subject: [PATCH 01/44] added `==` for PJsonNode --- lib/pure/json.nim | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 4250847e5..b325c2905 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -619,6 +619,25 @@ proc `%`*(elements: openArray[PJsonNode]): PJsonNode = newSeq(result.elems, elements.len) for i, p in pairs(elements): result.elems[i] = p +proc `==`* (a,b: PJsonNode): bool = + if a.kind != b.kind: false + else: + case a.kind + of JString: + a.str == b.str + of JInt: + a.num == b.num + of JFloat: + a.fnum == b.fnum + of JBool: + a.bval == b.bval + of JNull: + true + of JArray: + a.elems == b.elems + of JObject: + a.fields == b.fields + proc len*(n: PJsonNode): int = ## If `n` is a `JArray`, it returns the number of elements. ## If `n` is a `JObject`, it returns the number of pairs. From 56a912fb2a6d7cf3723b0ec5e5af1967ea583657 Mon Sep 17 00:00:00 2001 From: klaufir Date: Sun, 1 Jun 2014 04:20:47 +0200 Subject: [PATCH 02/44] adding header pragma for printf ffi example --- doc/manual.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.txt b/doc/manual.txt index 5afe385bb..57cf39765 100644 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -5485,7 +5485,7 @@ the argument is missing, the C name is the Nimrod identifier *exactly as spelled*: .. code-block:: - proc printf(formatstr: cstring) {.importc: "printf", varargs.} + proc printf(formatstr: cstring) {.header: "stdio.h", importc: "printf", varargs.} Note that this pragma is somewhat of a misnomer: Other backends will provide the same feature under the same name. From 93fa75bb07b11dfb5346d2598210bc10162ce804 Mon Sep 17 00:00:00 2001 From: Clay Sweetser Date: Sun, 1 Jun 2014 17:40:06 -0400 Subject: [PATCH 03/44] Fixed #1172 (for real) --- compiler/sem.nim | 10 +++++++--- compiler/semdata.nim | 4 ++-- compiler/seminst.nim | 8 +++++--- compiler/semstmts.nim | 10 ++++++++-- compiler/suggest.nim | 7 +++++-- lib/pure/collections/queues.nim | 2 +- 6 files changed, 28 insertions(+), 13 deletions(-) diff --git a/compiler/sem.nim b/compiler/sem.nim index bdc2a0b3c..0c793eeba 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -268,11 +268,15 @@ include hlo, seminst, semcall proc semAfterMacroCall(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = + ## Semantically check the output of a macro. + ## This involves processes such as re-checking the macro output for type + ## coherence, making sure that variables declared with 'let' aren't + ## reassigned, and binding the unbound identifiers that the macro output + ## contains. inc(evalTemplateCounter) if evalTemplateCounter > 100: globalError(s.info, errTemplateInstantiationTooNested) - let oldFriend = c.friendModule - c.friendModule = s.owner.getModule + c.friendModules.add(s.owner.getModule) result = n if s.typ.sons[0] == nil: @@ -296,7 +300,7 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym, result = fitNode(c, s.typ.sons[0], result) #GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0])) dec(evalTemplateCounter) - c.friendModule = oldFriend + discard c.friendModules.pop() proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, flags: TExprFlags = {}): PNode = diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 987a70a41..d2b2f90cd 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -52,7 +52,7 @@ type importTable*: PScope # scope for all imported symbols topLevelScope*: PScope # scope for all top-level symbols p*: PProcCon # procedure context - friendModule*: PSym # current friend module; may access private data; + friendModules*: seq[PSym] # friend modules; may access private data; # this is used so that generic instantiations # can access private object fields instCounter*: int # to prevent endless instantiations @@ -168,7 +168,7 @@ proc newContext(module: PSym): PContext = initLinkedList(result.libs) append(result.optionStack, newOptionEntry()) result.module = module - result.friendModule = module + result.friendModules = @[module] result.converters = @[] result.patterns = @[] result.includedFiles = initIntSet() diff --git a/compiler/seminst.nim b/compiler/seminst.nim index f7d5fa6f8..b93d7ca15 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -190,6 +190,9 @@ proc instantiateProcType(c: PContext, pt: TIdTable, proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, info: TLineInfo): PSym = + ## Generates a new instance of a generic procedure. + ## The `pt` parameter is a type-unsafe mapping table used to link generic + ## parameters to their concrete types within the generic instance. # no need to instantiate generic templates/macros: if fn.kind in {skTemplate, skMacro}: return fn # generates an instantiated proc @@ -199,8 +202,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, var n = copyTree(fn.ast) # NOTE: for access of private fields within generics from a different module # we set the friend module: - var oldFriend = c.friendModule - c.friendModule = getModule(fn) + c.friendModules.add(getModule(fn)) #let oldScope = c.currentScope #c.currentScope = fn.scope result = copySym(fn, false) @@ -236,6 +238,6 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, closeScope(c) # close scope for parameters popOwner() #c.currentScope = oldScope - c.friendModule = oldFriend + discard c.friendModules.pop() dec(c.instCounter) if result.kind == skMethod: finishMethod(c, result) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 43c7bf3fe..d17351988 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -66,10 +66,16 @@ proc toCover(t: PType): BiggestInt = result = lengthOrd(skipTypes(t, abstractVar-{tyTypeDesc})) proc performProcvarCheck(c: PContext, n: PNode, s: PSym) = + ## Checks that the given symbol is a proper procedure variable, meaning + ## that it var smoduleId = getModule(s).id if sfProcvar notin s.flags and s.typ.callConv == ccDefault and - smoduleId != c.module.id and smoduleId != c.friendModule.id: - localError(n.info, errXCannotBePassedToProcVar, s.name.s) + smoduleId != c.module.id: + block outer: + for module in c.friendModules: + if smoduleId == module.id: + break outer + localError(n.info, errXCannotBePassedToProcVar, s.name.s) proc semProcvarCheck(c: PContext, n: PNode) = let n = n.skipConv diff --git a/compiler/suggest.nim b/compiler/suggest.nim index fc6ba2f77..a46c6a082 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -63,8 +63,11 @@ proc filterSym(s: PSym): bool {.inline.} = proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} = let fmoduleId = getModule(f).id - result = sfExported in f.flags or fmoduleId == c.module.id or - fmoduleId == c.friendModule.id + result = sfExported in f.flags or fmoduleId == c.module.id + for module in c.friendModules: + if fmoduleId == module.id: + result = true + break proc suggestField(c: PContext, s: PSym, outputs: var int) = if filterSym(s) and fieldVisible(c, s): diff --git a/lib/pure/collections/queues.nim b/lib/pure/collections/queues.nim index db1d50569..5481272f0 100644 --- a/lib/pure/collections/queues.nim +++ b/lib/pure/collections/queues.nim @@ -59,7 +59,7 @@ proc enqueue*[T](q: var TQueue[T], item: T) = proc dequeue*[T](q: var TQueue[T]): T = ## removes and returns the first element of the queue `q`. - assert q.len > 0 + assert q.count > 0 dec q.count result = q.data[q.rd] q.rd = (q.rd + 1) and q.mask From c2b58f3a542655d877c2b6f6662466338cc4606b Mon Sep 17 00:00:00 2001 From: Reimer Behrends Date: Mon, 2 Jun 2014 19:38:51 +0200 Subject: [PATCH 04/44] Properly terminate "nimrod i" on end of file. Nimrod in interactive mode got stuck in an infinite loop when encountering EOF (Ctrl-D), unless GNU Readline was being used. This change mimics the GNU Readline behavior in rdstdin.nim and calls quit(0) when encountering EOF while reading from stdin in interactive mode. --- compiler/llstream.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/llstream.nim b/compiler/llstream.nim index 510880ffd..86bfeaabd 100644 --- a/compiler/llstream.nim +++ b/compiler/llstream.nim @@ -82,6 +82,9 @@ when not defined(readLineFromStdin): proc readLineFromStdin(prompt: string, line: var string): bool = stdout.write(prompt) result = readLine(stdin, line) + if not result: + stdout.write("\n") + quit(0) proc endsWith*(x: string, s: set[char]): bool = var i = x.len-1 From ac797e1801b7b24df95b1513c37c4e2813f27c5a Mon Sep 17 00:00:00 2001 From: Billingsly Wetherfordshire Date: Mon, 2 Jun 2014 18:13:56 -0500 Subject: [PATCH 05/44] added json.hash --- lib/pure/json.nim | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index b325c2905..c56589803 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -620,6 +620,7 @@ proc `%`*(elements: openArray[PJsonNode]): PJsonNode = for i, p in pairs(elements): result.elems[i] = p proc `==`* (a,b: PJsonNode): bool = + ## Check two nodes for equality if a.kind != b.kind: false else: case a.kind @@ -638,6 +639,24 @@ proc `==`* (a,b: PJsonNode): bool = of JObject: a.fields == b.fields +proc hash* (n:PJsonNode): THash = + ## Compute the hash for a JSON node + case n.kind + of jArray: + result = hash(n.elems) + of jObject: + result = hash(n.fields) + of jInt: + result = hash(n.num) + of jFloat: + result = hash(n.fnum) + of jBool: + result = hash(n.bval.int) + of jString: + result = hash(n.str) + of jNull: + result = hash(0) + proc len*(n: PJsonNode): int = ## If `n` is a `JArray`, it returns the number of elements. ## If `n` is a `JObject`, it returns the number of pairs. From 4ae9486eef1fcddc1e38c9196df4bc729bee9522 Mon Sep 17 00:00:00 2001 From: Billingsly Wetherfordshire Date: Mon, 2 Jun 2014 18:21:37 -0500 Subject: [PATCH 06/44] fix #1241 --- lib/pure/fsmonitor.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pure/fsmonitor.nim b/lib/pure/fsmonitor.nim index d6584c1a0..b35466771 100644 --- a/lib/pure/fsmonitor.nim +++ b/lib/pure/fsmonitor.nim @@ -119,8 +119,8 @@ proc getEvent(m: PFSMonitor, fd: cint): seq[TMonitorEvent] = var mev: TMonitorEvent mev.wd = event.wd if event.len.int != 0: - mev.name = newString(event.len.int) - copyMem(addr(mev.name[0]), addr event.name, event.len.int-1) + let cstr = event.name.addr.cstring + mev.name = $cstr else: mev.name = "" @@ -211,4 +211,4 @@ when isMainModule: while true: if not disp.poll(): break - \ No newline at end of file + From 24c00440464edb68277fd5bc4f90caa0ad11c988 Mon Sep 17 00:00:00 2001 From: klaufir Date: Tue, 3 Jun 2014 08:07:27 +0200 Subject: [PATCH 07/44] header pragma set to '' in importc section --- doc/manual.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.txt b/doc/manual.txt index 57cf39765..3af41faec 100644 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -5485,7 +5485,7 @@ the argument is missing, the C name is the Nimrod identifier *exactly as spelled*: .. code-block:: - proc printf(formatstr: cstring) {.header: "stdio.h", importc: "printf", varargs.} + proc printf(formatstr: cstring) {.header: "", importc: "printf", varargs.} Note that this pragma is somewhat of a misnomer: Other backends will provide the same feature under the same name. From 3db3c0e3827a9a9bd70a8f635b0e6650c89b2b7b Mon Sep 17 00:00:00 2001 From: flaviut Date: Tue, 3 Jun 2014 10:12:31 -0400 Subject: [PATCH 08/44] Generalize accent parsing --- compiler/parser.nim | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 2f9deb6b3..61816f443 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -147,8 +147,10 @@ proc expectIdent(p: TParser) = proc eat(p: var TParser, tokType: TTokType) = ## Move the parser to the next token if the current token is of type ## `tokType`, otherwise error. - if p.tok.tokType == tokType: getTok(p) - else: lexMessage(p.lex, errTokenExpected, TokTypeToStr[tokType]) + if p.tok.tokType == tokType: + getTok(p) + else: + lexMessage(p.lex, errTokenExpected, TokTypeToStr[tokType]) proc parLineInfo(p: TParser): TLineInfo = ## Retrieve the line information associated with the parser's current state. @@ -285,7 +287,7 @@ proc colcom(p: var TParser, n: PNode) = skipComment(p, n) proc parseSymbol(p: var TParser, allowNil = false): PNode = - #| symbol = '`' (KEYW|IDENT|operator|'(' ')'|'[' ']'|'{' '}'|'='|literal)+ '`' + #| symbol = '`' (KEYW|IDENT|operator|'('|')'|'['|']'|'{'|'}'|'='|literal)+ '`' #| | IDENT case p.tok.tokType of tkSymbol: @@ -296,29 +298,16 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode = getTok(p) while true: case p.tok.tokType - of tkBracketLe: - add(result, newIdentNodeP(getIdent"[]", p)) + of tkIntLit..tkCharLit, tkBracketLe, tkBracketRi, tkParLe, tkParRi, + tkCurlyRi, tkCurlyLe, tkEquals: + add(result, newIdentNodeP(getIdent(tokToStr(p.tok)), p)) getTok(p) - eat(p, tkBracketRi) - of tkEquals: - add(result, newIdentNodeP(getIdent"=", p)) - getTok(p) - of tkParLe: - add(result, newIdentNodeP(getIdent"()", p)) - getTok(p) - eat(p, tkParRi) - of tkCurlyLe: - add(result, newIdentNodeP(getIdent"{}", p)) - getTok(p) - eat(p, tkCurlyRi) of tokKeywordLow..tokKeywordHigh, tkSymbol, tkOpr, tkDot, tkDotDot: add(result, newIdentNodeP(p.tok.ident, p)) getTok(p) - of tkIntLit..tkCharLit: - add(result, newIdentNodeP(getIdent(tokToStr(p.tok)), p)) - getTok(p) else: if result.len == 0: + echo repr p.tok parMessage(p, errIdentifierExpected, p.tok) break eat(p, tkAccent) From 7b1b3cbf2505f1b0f31349bd7f22c3c608820204 Mon Sep 17 00:00:00 2001 From: flaviut Date: Tue, 3 Jun 2014 10:12:57 -0400 Subject: [PATCH 09/44] More descriptive error message in semtypes enum --- compiler/semtypes.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index d88a95603..d70ed3465 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -72,7 +72,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = e = n.sons[i].sym of nkIdent: e = newSymS(skEnumField, n.sons[i], c) - else: illFormedAst(n) + else: illFormedAst(n[i]) e.typ = result e.position = int(counter) if e.position == 0: hasNull = true From 20cb567bf5e404a30bb4b898b87865e4304b1130 Mon Sep 17 00:00:00 2001 From: flaviut Date: Tue, 3 Jun 2014 10:22:12 -0400 Subject: [PATCH 10/44] Fix accents in enums --- compiler/parser.nim | 8 +++++--- compiler/semtypes.nim | 5 +++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 61816f443..f89aee119 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -296,20 +296,22 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode = of tkAccent: result = newNodeP(nkAccQuoted, p) getTok(p) + var bracketAccm = "" while true: case p.tok.tokType of tkIntLit..tkCharLit, tkBracketLe, tkBracketRi, tkParLe, tkParRi, tkCurlyRi, tkCurlyLe, tkEquals: - add(result, newIdentNodeP(getIdent(tokToStr(p.tok)), p)) + bracketAccm.add(tokToStr(p.tok)) getTok(p) of tokKeywordLow..tokKeywordHigh, tkSymbol, tkOpr, tkDot, tkDotDot: add(result, newIdentNodeP(p.tok.ident, p)) getTok(p) else: - if result.len == 0: - echo repr p.tok + if result.len == 0 and bracketAccm == "": parMessage(p, errIdentifierExpected, p.tok) break + if bracketAccm != "": + result.add(newIdentNodeP(getIdent(bracketAccm), p)) eat(p, tkAccent) else: if allowNil and p.tok.tokType == tkNil: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index d70ed3465..2dcca8f1e 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -70,9 +70,10 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = counter = x of nkSym: e = n.sons[i].sym - of nkIdent: + of nkIdent, nkAccQuoted: e = newSymS(skEnumField, n.sons[i], c) - else: illFormedAst(n[i]) + else: + illFormedAst(n[i]) e.typ = result e.position = int(counter) if e.position == 0: hasNull = true From 7a9bcf47697a004de8d3b3ec54beb8ac4bdb9872 Mon Sep 17 00:00:00 2001 From: flaviut Date: Tue, 3 Jun 2014 18:58:59 -0400 Subject: [PATCH 11/44] Clean up code --- compiler/parser.nim | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index f89aee119..ae115e749 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -296,22 +296,17 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode = of tkAccent: result = newNodeP(nkAccQuoted, p) getTok(p) - var bracketAccm = "" + var accm = "" while true: case p.tok.tokType - of tkIntLit..tkCharLit, tkBracketLe, tkBracketRi, tkParLe, tkParRi, - tkCurlyRi, tkCurlyLe, tkEquals: - bracketAccm.add(tokToStr(p.tok)) - getTok(p) - of tokKeywordLow..tokKeywordHigh, tkSymbol, tkOpr, tkDot, tkDotDot: - add(result, newIdentNodeP(p.tok.ident, p)) - getTok(p) - else: - if result.len == 0 and bracketAccm == "": + of tkAccent, tkEof: + if accm == "": parMessage(p, errIdentifierExpected, p.tok) break - if bracketAccm != "": - result.add(newIdentNodeP(getIdent(bracketAccm), p)) + else: + accm.add(tokToStr(p.tok)) + getTok(p) + result.add(newIdentNodeP(getIdent(accm), p)) eat(p, tkAccent) else: if allowNil and p.tok.tokType == tkNil: From 7e60cf2a3496eebe5757486230a5540405079980 Mon Sep 17 00:00:00 2001 From: flaviut Date: Tue, 3 Jun 2014 19:01:24 -0400 Subject: [PATCH 12/44] Add test --- tests/misc/tbug1217bracketquotes.nim | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tests/misc/tbug1217bracketquotes.nim diff --git a/tests/misc/tbug1217bracketquotes.nim b/tests/misc/tbug1217bracketquotes.nim new file mode 100644 index 000000000..90e67d45b --- /dev/null +++ b/tests/misc/tbug1217bracketquotes.nim @@ -0,0 +1,14 @@ +discard """ + output: "13{(.{}}{*4&*$**()&*@1235" +""" + +type + Test = enum + `1`, `3`, `{`, `(.`, `{}}{`, `*4&*$**()&*@` + +let `.}` = 1 +let `(}` = 2 +let `[` = 3 +let `]` = 5 + +echo `1`, `3`, `{`, `(.`, `{}}{`, `*4&*$**()&*@`, `.}`, `(}`, `[`, `]` From 90dc35c10998c279daf2b413aaf896cadaced699 Mon Sep 17 00:00:00 2001 From: flaviut Date: Wed, 4 Jun 2014 15:30:37 -0400 Subject: [PATCH 13/44] fix bug with unexpected tkInvalid,tkEof,tkComment --- compiler/parser.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/parser.nim b/compiler/parser.nim index ae115e749..ec829f644 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -303,6 +303,8 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode = if accm == "": parMessage(p, errIdentifierExpected, p.tok) break + of tkEof, tkInvalid, tkComment: + parMessage(p, errIdentifierExpected, p.tok) else: accm.add(tokToStr(p.tok)) getTok(p) From 6b9359d90161887b2dc4fa12d9861883d22530f6 Mon Sep 17 00:00:00 2001 From: flaviut Date: Wed, 4 Jun 2014 15:40:31 -0400 Subject: [PATCH 14/44] updated grammer, fixed oversight --- compiler/parser.nim | 2 +- doc/grammar.txt | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index ec829f644..7b6ef8ee5 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -299,7 +299,7 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode = var accm = "" while true: case p.tok.tokType - of tkAccent, tkEof: + of tkAccent: if accm == "": parMessage(p, errIdentifierExpected, p.tok) break diff --git a/doc/grammar.txt b/doc/grammar.txt index 63e898e11..61557b68c 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -24,7 +24,7 @@ ampExpr = plusExpr (OP6 optInd plusExpr)* plusExpr = mulExpr (OP7 optInd mulExpr)* mulExpr = dollarExpr (OP8 optInd dollarExpr)* dollarExpr = primary (OP9 optInd primary)* -symbol = '`' (KEYW|IDENT|operator|'(' ')'|'[' ']'|'{' '}'|'='|literal)+ '`' +symbol = '`' (KEYW|IDENT|operator|'('|')'|'['|']'|'{'|'}'|'='|literal)+ '`' | IDENT indexExpr = expr indexExprList = indexExpr ^+ comma @@ -166,7 +166,6 @@ object = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart typeClassParam = ('var')? symbol typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')? &IND{>} stmt -distinct = 'distinct' optInd typeDesc typeDef = identWithPragma genericParamList? '=' optInd typeDefAux indAndComment? varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr From 69a595480790d985f2d2f79d5d74bb6adb8568a7 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 5 Jun 2014 23:12:22 +0100 Subject: [PATCH 15/44] Capitalised enum value names in JSON module. --- lib/pure/json.nim | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 0476dc2ae..799cd6d58 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -642,19 +642,19 @@ proc `==`* (a,b: PJsonNode): bool = proc hash* (n:PJsonNode): THash = ## Compute the hash for a JSON node case n.kind - of jArray: + of JArray: result = hash(n.elems) - of jObject: + of JObject: result = hash(n.fields) - of jInt: + of JInt: result = hash(n.num) - of jFloat: + of JFloat: result = hash(n.fnum) - of jBool: + of JBool: result = hash(n.bval.int) - of jString: + of JString: result = hash(n.str) - of jNull: + of JNull: result = hash(0) proc len*(n: PJsonNode): int = From 6975e77d43de640d9d0ca933fe64dc6d2f161b97 Mon Sep 17 00:00:00 2001 From: Grzegorz Adam Hankiewicz Date: Fri, 6 Jun 2014 19:10:08 +0200 Subject: [PATCH 16/44] Adds docstring example to system.fieldPairs. --- lib/system.nim | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index c69a335e4..4a4872b98 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1767,9 +1767,38 @@ iterator fields*[S:tuple|object, T:tuple|object](x: S, y: T): tuple[a,b: expr] { ## in the loop body. iterator fieldPairs*[T: tuple|object](x: T): TObject {. magic: "FieldPairs", noSideEffect.} - ## iterates over every field of `x`. Warning: This really transforms - ## the 'for' and unrolls the loop. The current implementation also has a bug - ## that affects symbol binding in the loop body. + ## Iterates over every field of `x` returning their name and value. + ## + ## When you iterate over objects with different field types you have to use + ## the compile time ``when`` instead of a runtime ``if`` to select the code + ## you want to run for each type. To perform the comparison use the `is + ## operator `_. Example: + ## + ## .. code-block:: Nimrod + ## + ## type + ## Custom = object + ## foo: string + ## bar: bool + ## + ## proc `$`(x: Custom): string = + ## result = "Custom:" + ## for name, value in x.fieldPairs: + ## when value is bool: + ## result.add("\n\t" & name & " is " & $value) + ## else: + ## if value.isNil: + ## result.add("\n\t" & name & " (nil)") + ## else: + ## result.add("\n\t" & name & " '" & value & "'") + ## + ## Another way to do the same without ``when`` is to leave the task of + ## picking the appropriate code to a secondary proc which you overload for + ## each field type and pass the `value` to. + ## + ## Warning: This really transforms the 'for' and unrolls the loop. The + ## current implementation also has a bug that affects symbol binding in the + ## loop body. iterator fieldPairs*[S: tuple|object, T: tuple|object](x: S, y: T): tuple[ a, b: expr] {. magic: "FieldPairs", noSideEffect.} From 7da3c5e71e485ef4326dcf415a297267a47ab971 Mon Sep 17 00:00:00 2001 From: Grzegorz Adam Hankiewicz Date: Fri, 6 Jun 2014 19:32:36 +0200 Subject: [PATCH 17/44] Adds do notation example to algorithm.sort. --- lib/pure/algorithm.nim | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 37fbc948c..86d329763 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -150,6 +150,15 @@ proc sort*[T](a: var openArray[T], ## # overload: ## sort(myStrArray, system.cmp) ## + ## You can inline adhoc comparison procs with the `do notation + ## `_. Example: + ## + ## .. code-block:: nimrod + ## + ## people.sort do (x, y: Person) -> int: + ## result = cmp(x.surname, y.surname) + ## if result == 0: + ## result = cmp(x.name, y.name) var n = a.len var b: seq[T] newSeq(b, n div 2) From 9009841d623d268c649f96bd0215b3013de35eeb Mon Sep 17 00:00:00 2001 From: Grzegorz Adam Hankiewicz Date: Fri, 6 Jun 2014 19:53:39 +0200 Subject: [PATCH 18/44] Avoids temporal string in tables hashing example. --- lib/pure/collections/tables.nim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 848f4b8ba..b5fc1737a 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -37,7 +37,8 @@ ## ## Piggyback on the already available string hash proc. ## ## ## ## Without this proc nothing works! -## result = hash(x.firstName & x.lastName) +## result = x.firstName.hash !& x.lastName.hash +## result = !$result ## ## var ## salaries = initTable[Person, int]() @@ -841,7 +842,8 @@ when isMainModule: ## Piggyback on the already available string hash proc. ## ## Without this proc nothing works! - result = hash(x.firstName & x.lastName) + result = x.firstName.hash !& x.lastName.hash + result = !$result var salaries = initTable[Person, int]() From bde9d1ac0753e46c726dc63930539bb82d09f19d Mon Sep 17 00:00:00 2001 From: Grzegorz Adam Hankiewicz Date: Fri, 6 Jun 2014 20:10:13 +0200 Subject: [PATCH 19/44] Adds to tables module example of reference type vs value type. --- lib/pure/collections/tables.nim | 34 +++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index b5fc1737a..e51a04dd1 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -52,8 +52,25 @@ ## p2.lastName = "박" ## salaries[p2] = 45_000 ## -## **Note:** The data types declared here have *value semantics*: This means -## that ``=`` performs a copy of the hash table. +## **Note:** The data types declared here starting with the **T** prefix have +## *value semantics*: This means that ``=`` performs a copy of the hash table. +## On the other hand, types declared with the **P** prefix have *reference +## semantics*. Behaviour comparison: +## +## .. code-block:: nimrod +## var valueWords = initTable[string, string]() +## valueWords["teh"] = "the" +## var valueWordsClone = valueWords +## # Changing the clone won't change the original. +## valueWordsClone["teh"] = "thehehe" +## assert valueWords["teh"] != valueWordsClone["teh"] +## +## var refWords = newTable[string, string]() +## refWords["teh"] = "the" +## var refWordsShadow = refWords +## # Both the shadow and the original share the same data. +## refWordsShadow["teh"] = "thehehe" +## assert refWords["teh"] == refWordsShadow["teh"] import hashes, math @@ -861,3 +878,16 @@ when isMainModule: s2[p2] = 45_000 s3[p1] = 30_000 s3[p2] = 45_000 + + # Ref verification. + var valueWords = initTable[string, string]() + valueWords["teh"] = "the" + var valueWordsClone = valueWords + valueWordsClone["teh"] = "thehehe" + assert valueWords["teh"] != valueWordsClone["teh"] + + var refWords = newTable[string, string]() + refWords["teh"] = "the" + var refWordsShadow = refWords + refWordsShadow["teh"] = "thehehe" + assert refWords["teh"] == refWordsShadow["teh"] From f45a1dbf1d1eaba511b6673c5955aa108430c165 Mon Sep 17 00:00:00 2001 From: Grzegorz Adam Hankiewicz Date: Fri, 6 Jun 2014 20:58:51 +0200 Subject: [PATCH 20/44] Adds brief intro to hashes module. --- lib/pure/hashes.nim | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 5784a96c1..740355e55 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -8,7 +8,34 @@ # ## This module implements efficient computations of hash values for diverse -## Nimrod types. +## Nimrod types. All the procs are based on these two building blocks: the `!& +## proc <#!&>`_ used to start or mix a hash value, and the `!$ proc <#!$>`_ +## used to *finish* the hash value. If you want to implement hash procs for +## your custom types you will end up writing the following kind of skeleton of +## code: +## +## .. code-block:: nimrod +## proc hash(x: Something): THash = +## ## Computes a THash from `x`. +## var h: THash = 0 +## # Iterate over parts of `x`. +## for xAtom in x: +## # Mix the atom with the partial hash. +## h = h !& xAtom +## # Finish the hash. +## result = !$h +## +## If your custom types contain fields for which there already is a hash proc, +## like for example objects made up of ``strings``, you can simply hash +## together the hash value of the individual fields: +## +## .. code-block:: nimrod +## proc hash(x: Something): THash = +## ## Computes a THash from `x`. +## var h: THash = 0 +## h = h &! hash(x.foo) +## h = h &! hash(x.bar) +## result = !$h import strutils From 3f9ad7ef22dfea8fa58c378322581ab3b2ff48b2 Mon Sep 17 00:00:00 2001 From: Grzegorz Adam Hankiewicz Date: Fri, 6 Jun 2014 21:55:20 +0200 Subject: [PATCH 21/44] Documents -d: in the compiler guide and hyperlinks assert/defined. --- doc/nimrodc.txt | 12 ++++++++++++ lib/system.nim | 20 +++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/doc/nimrodc.txt b/doc/nimrodc.txt index e4f1c41dc..fea1037da 100644 --- a/doc/nimrodc.txt +++ b/doc/nimrodc.txt @@ -87,6 +87,18 @@ Level Description for compiler developers. ===== ============================================ + +Compile time symbols +-------------------- + +Through the ``-d:x`` or ``--define:x`` switch you can define compile time +symbols for conditional compilation. The defined switches can be checked in +source code with the `when statement `_ and +`defined proc `_. The typical use of this switch is to +enable builds in release mode (``-d:release``) where certain safety checks are +omitted for better performance. Another common use is the ``-d:ssl`` switch to +activate `SSL sockets `_. + Configuration files ------------------- diff --git a/lib/system.nim b/lib/system.nim index 4a4872b98..2f24f68b1 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -88,6 +88,15 @@ proc defined*(x: expr): bool {.magic: "Defined", noSideEffect.} ## when not defined(strutils.toUpper): ## # provide our own toUpper proc here, because strutils is ## # missing it. + ## + ## You can also check external symbols introduced through the compiler's + ## `-d:x switch `_ to enable build time + ## conditionals: + ## + ## .. code-block:: Nimrod + ## when not defined(release): + ## # Do here programmer friendly expensive sanity checks. + ## # Put here the normal code when defined(useNimRtl): {.deadCodeElim: on.} @@ -2812,10 +2821,15 @@ when true: THide(raiseAssert)(msg) template assert*(cond: bool, msg = "") = - ## provides a means to implement `programming by contracts`:idx: in Nimrod. + ## Raises ``EAssertionFailure`` with `msg` if `cond` is false. + ## + ## Provides a means to implement `programming by contracts`:idx: in Nimrod. ## ``assert`` evaluates expression ``cond`` and if ``cond`` is false, it - ## raises an ``EAssertionFailure`` exception. However, the compiler may - ## not generate any code at all for ``assert`` if it is advised to do so. + ## raises an ``EAssertionFailure`` exception. However, the compiler may not + ## generate any code at all for ``assert`` if it is advised to do so through + ## the ``-d:release`` or ``--assertions:off`` `command line switches + ## `_. + ## ## Use ``assert`` for debugging purposes only. bind instantiationInfo mixin failedAssertImpl From 145cb3ae8ccf58495a3e38f6646041661de2affb Mon Sep 17 00:00:00 2001 From: flaviut Date: Sun, 8 Jun 2014 15:46:19 -0400 Subject: [PATCH 22/44] fix overlooked grammer comment --- compiler/parser.nim | 1 + doc/grammar.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/compiler/parser.nim b/compiler/parser.nim index 7b6ef8ee5..0f52750c9 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -981,6 +981,7 @@ proc parseSymbolList(p: var TParser, result: PNode, allowNil = false) = proc parseTypeDescKAux(p: var TParser, kind: TNodeKind, mode: TPrimaryMode): PNode = + #| distinct = 'distinct' optInd typeDesc result = newNodeP(kind, p) getTok(p) optInd(p, result) diff --git a/doc/grammar.txt b/doc/grammar.txt index 61557b68c..fe5341840 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -82,6 +82,7 @@ paramListColon = paramList? (':' optInd typeDesc)? doBlock = 'do' paramListArrow pragmas? colcom stmt doBlocks = doBlock ^* IND{=} procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)? +distinct = 'distinct' optInd typeDesc expr = (ifExpr | whenExpr | caseExpr From ce29b9f78c74285a31908135a73ee62051bd7525 Mon Sep 17 00:00:00 2001 From: flaviut Date: Sun, 8 Jun 2014 19:41:36 -0400 Subject: [PATCH 23/44] fix tokenizing bug --- compiler/parser.nim | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 0f52750c9..18de1570a 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -287,7 +287,7 @@ proc colcom(p: var TParser, n: PNode) = skipComment(p, n) proc parseSymbol(p: var TParser, allowNil = false): PNode = - #| symbol = '`' (KEYW|IDENT|operator|'('|')'|'['|']'|'{'|'}'|'='|literal)+ '`' + #| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`' #| | IDENT case p.tok.tokType of tkSymbol: @@ -296,19 +296,24 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode = of tkAccent: result = newNodeP(nkAccQuoted, p) getTok(p) - var accm = "" while true: case p.tok.tokType of tkAccent: - if accm == "": + if result.len == 0: parMessage(p, errIdentifierExpected, p.tok) break - of tkEof, tkInvalid, tkComment: - parMessage(p, errIdentifierExpected, p.tok) - else: - accm.add(tokToStr(p.tok)) + of tkOpr, tkDot, tkDotDot, tkEquals, tkParLe..tkParDotRi: + var accm = "" + while p.tok.tokType in {tkOpr, tkDot, tkDotDot, tkEquals, + tkParLe..tkParDotRi}: + accm.add(tokToStr(p.tok)) + getTok(p) + result.add(newIdentNodeP(getIdent(accm), p)) + of tokKeywordLow..tokKeywordHigh, tkSymbol, tkIntLit..tkCharLit: + result.add(newIdentNodeP(getIdent(tokToStr(p.tok)), p)) getTok(p) - result.add(newIdentNodeP(getIdent(accm), p)) + else: + parMessage(p, errIdentifierExpected, p.tok) eat(p, tkAccent) else: if allowNil and p.tok.tokType == tkNil: From bebc3f62a98fc97f9e45614d9479cfbbfd678a91 Mon Sep 17 00:00:00 2001 From: flaviut Date: Sun, 8 Jun 2014 19:42:28 -0400 Subject: [PATCH 24/44] Regenerate docs --- doc/grammar.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/grammar.txt b/doc/grammar.txt index fe5341840..47ae095f6 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -24,7 +24,7 @@ ampExpr = plusExpr (OP6 optInd plusExpr)* plusExpr = mulExpr (OP7 optInd mulExpr)* mulExpr = dollarExpr (OP8 optInd dollarExpr)* dollarExpr = primary (OP9 optInd primary)* -symbol = '`' (KEYW|IDENT|operator|'('|')'|'['|']'|'{'|'}'|'='|literal)+ '`' +symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`' | IDENT indexExpr = expr indexExprList = indexExpr ^+ comma From af6abac4911be18bd92a9190ccbe39aa72ab1a79 Mon Sep 17 00:00:00 2001 From: Grzegorz Adam Hankiewicz Date: Tue, 10 Jun 2014 00:39:19 +0200 Subject: [PATCH 25/44] Revert "Adds to tables module example of reference type vs value type." This reverts commit bde9d1ac0753e46c726dc63930539bb82d09f19d. --- lib/pure/collections/tables.nim | 34 ++------------------------------- 1 file changed, 2 insertions(+), 32 deletions(-) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index e51a04dd1..b5fc1737a 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -52,25 +52,8 @@ ## p2.lastName = "박" ## salaries[p2] = 45_000 ## -## **Note:** The data types declared here starting with the **T** prefix have -## *value semantics*: This means that ``=`` performs a copy of the hash table. -## On the other hand, types declared with the **P** prefix have *reference -## semantics*. Behaviour comparison: -## -## .. code-block:: nimrod -## var valueWords = initTable[string, string]() -## valueWords["teh"] = "the" -## var valueWordsClone = valueWords -## # Changing the clone won't change the original. -## valueWordsClone["teh"] = "thehehe" -## assert valueWords["teh"] != valueWordsClone["teh"] -## -## var refWords = newTable[string, string]() -## refWords["teh"] = "the" -## var refWordsShadow = refWords -## # Both the shadow and the original share the same data. -## refWordsShadow["teh"] = "thehehe" -## assert refWords["teh"] == refWordsShadow["teh"] +## **Note:** The data types declared here have *value semantics*: This means +## that ``=`` performs a copy of the hash table. import hashes, math @@ -878,16 +861,3 @@ when isMainModule: s2[p2] = 45_000 s3[p1] = 30_000 s3[p2] = 45_000 - - # Ref verification. - var valueWords = initTable[string, string]() - valueWords["teh"] = "the" - var valueWordsClone = valueWords - valueWordsClone["teh"] = "thehehe" - assert valueWords["teh"] != valueWordsClone["teh"] - - var refWords = newTable[string, string]() - refWords["teh"] = "the" - var refWordsShadow = refWords - refWordsShadow["teh"] = "thehehe" - assert refWords["teh"] == refWordsShadow["teh"] From 9354b8a9d7a4cbc47b0d427c34849dd316b2a65e Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 12 Jun 2014 14:45:56 +0200 Subject: [PATCH 26/44] added allValues iterator --- lib/pure/collections/tables.nim | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 848f4b8ba..091bf8590 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -145,6 +145,14 @@ proc mget*[A, B](t: var TTable[A, B], key: A): var B = if index >= 0: result = t.data[index].val else: raise newException(EInvalidKey, "key not found: " & $key) +iterator allValues*[A, B](t: TTable[A, B]; key: A): B = + ## iterates over any value in the table `t` that belongs to the given `key`. + var h: THash = hash(key) and high(t.data) + while t.data[h].slot != seEmpty: + if t.data[h].key == key and t.data[h].slot == seFilled: + yield t.data[h].val + h = nextTry(h, high(t.data)) + proc hasKey*[A, B](t: TTable[A, B], key: A): bool = ## returns true iff `key` is in the table `t`. result = rawGet(t, key) >= 0 @@ -313,8 +321,7 @@ proc newTable*[A, B](initialSize=64): PTable[A, B] = new(result) result[] = initTable[A, B](initialSize) -proc newTable*[A, B](pairs: openArray[tuple[key: A, - val: B]]): PTable[A, B] = +proc newTable*[A, B](pairs: openArray[tuple[key: A, val: B]]): PTable[A, B] = ## creates a new hash table that contains the given `pairs`. new(result) result[] = toTable[A, B](pairs) From 15909c7be25a5956d0af7bd8d975b23d51fba560 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 12 Jun 2014 16:05:50 +0200 Subject: [PATCH 27/44] optimized method dispatchers --- compiler/ast.nim | 1 + compiler/ccgexprs.nim | 24 ++++++++++++++++++++---- compiler/ccgtypes.nim | 4 ++++ compiler/cgen.nim | 1 + compiler/cgendata.nim | 1 + lib/system/chcks.nim | 22 ++++++++++++++++++++++ todo.txt | 1 - 7 files changed, 49 insertions(+), 5 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 80b9e9bb2..d74818e1f 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -510,6 +510,7 @@ const tfUncheckedArray* = tfVarargs tfUnion* = tfNoSideEffect tfGcSafe* = tfThread + tfObjHasKids* = tfEnumHasHoles skError* = skUnknown # type flags that are essential for type equality: diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 39333a80d..13b3091fc 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1144,6 +1144,24 @@ proc genNewFinalize(p: BProc, e: PNode) = genObjectInit(p, cpsStmts, bt, a, false) gcUsage(e) +proc genOfHelper(p: BProc; dest: PType; a: PRope): PRope = + # unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we + # have to call it here first: + let ti = genTypeInfo(p.module, dest) + if tfFinal in dest.flags or (p.module.objHasKidsValid and + tfObjHasKids notin dest.flags): + result = ropef("$1.m_type == $2", a, ti) + else: + discard cgsym(p.module, "TNimType") + inc p.module.labels + let cache = con("Nim_OfCheck_CACHE", p.module.labels.toRope) + appf(p.module.s[cfsVars], "static TNimType* $#[2];$n", cache) + result = rfmt(p.module, "#isObjWithCache($#.m_type, $#, $#)", a, ti, cache) + when false: + # former version: + result = rfmt(p.module, "#isObj($1.m_type, $2)", + a, genTypeInfo(p.module, dest)) + proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = var a: TLoc initLocExpr(p, x, a) @@ -1163,11 +1181,9 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = globalError(x.info, errGenerated, "no 'of' operator available for pure objects") if nilCheck != nil: - r = rfmt(p.module, "(($1) && #isObj($2.m_type, $3))", - nilCheck, r, genTypeInfo(p.module, dest)) + r = rfmt(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r)) else: - r = rfmt(p.module, "#isObj($1.m_type, $2)", - r, genTypeInfo(p.module, dest)) + r = rfmt(p.module, "($1)", genOfHelper(p, dest, r)) putIntoDest(p, d, getSysType(tyBool), r) proc genOf(p: BProc, n: PNode, d: var TLoc) = diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 7a490082f..28c791e42 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -796,6 +796,10 @@ proc genObjectInfo(m: BModule, typ: PType, name: PRope) = var tmp = getNimNode(m) genObjectFields(m, typ, typ.n, tmp) appf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp]) + var t = typ.sons[0] + while t != nil: + t.skipTypes(abstractInst).flags.incl tfObjHasKids + t = t.sons[0] proc genTupleInfo(m: BModule, typ: PType, name: PRope) = genTypeInfoAuxBase(m, typ, name, toRope("0")) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 198b1187d..7094990f7 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1383,6 +1383,7 @@ proc myClose(b: PPassContext, n: PNode): PNode = registerModuleToMain(m.module) if sfMainModule in m.module.flags: + m.objHasKidsValid = true var disp = generateMethodDispatchers() for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym) genMainProc(m) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index e7d818556..12041c55b 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -96,6 +96,7 @@ type # a frame var twice in an init proc isHeaderFile*: bool # C source file is the header file includesStringh*: bool # C source file already includes ```` + objHasKidsValid*: bool # whether we can rely on tfObjHasKids cfilename*: string # filename of the module (including path, # without extension) typeCache*: TIdTable # cache the generated types diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim index f29e222e8..387b54ef1 100644 --- a/lib/system/chcks.nim +++ b/lib/system/chcks.nim @@ -67,6 +67,28 @@ proc chckObjAsgn(a, b: PNimType) {.compilerproc, inline.} = if a != b: sysFatal(EInvalidObjectAssignment, "invalid object assignment") +type ObjCheckCache = array[0..1, PNimType] + +proc isObjSlowPath(obj, subclass: PNimType; + cache: var ObjCheckCache): bool {.noinline.} = + # checks if obj is of type subclass: + var x = obj.base + while x != subclass: + if x == nil: + cache[0] = obj + return false + x = x.base + cache[1] = obj + return true + +proc isObjWithCache(obj, subclass: PNimType; + cache: var ObjCheckCache): bool {.compilerProc, inline.} = + if obj == subclass: return true + if obj.base == subclass: return true + if cache[0] == obj: return false + if cache[1] == obj: return true + return isObjSlowPath(obj, subclass, cache) + proc isObj(obj, subclass: PNimType): bool {.compilerproc.} = # checks if obj is of type subclass: var x = obj diff --git a/todo.txt b/todo.txt index 996067175..539089281 100644 --- a/todo.txt +++ b/todo.txt @@ -138,7 +138,6 @@ Not essential for 1.0.0 - implement the "snoopResult" pragma; no, make a strutils with string append semantics instead ... - implement "closure tuple consists of a single 'ref'" optimization -- optimize method dispatchers - new feature: ``distinct T with operations`` - arglist as a type (iterator chaining); variable length type lists for generics - implement marker procs for message passing From d3c8f1ab25a810516baccc2b1bff761dbbc2d011 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 12 Jun 2014 16:35:53 +0200 Subject: [PATCH 28/44] fixes recently introduced regression --- compiler/ccgtypes.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 28c791e42..8e762ce27 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -798,7 +798,8 @@ proc genObjectInfo(m: BModule, typ: PType, name: PRope) = appf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp]) var t = typ.sons[0] while t != nil: - t.skipTypes(abstractInst).flags.incl tfObjHasKids + t = t.skipTypes(abstractInst) + t.flags.incl tfObjHasKids t = t.sons[0] proc genTupleInfo(m: BModule, typ: PType, name: PRope) = From 13542572ab9d554593f772c955910ca1c9a18100 Mon Sep 17 00:00:00 2001 From: Varriount Date: Sat, 14 Jun 2014 22:10:54 -0400 Subject: [PATCH 29/44] Update json.nim Fixed a bug with json.[], which caused a segfault on debug builds. --- 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 799cd6d58..bd5259f95 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -669,7 +669,7 @@ proc len*(n: PJsonNode): int = proc `[]`*(node: PJsonNode, name: string): PJsonNode = ## Gets a field from a `JObject`, which must not be nil. ## If the value at `name` does not exist, returns nil - assert(node != nil) + assert(not isNil(node)) assert(node.kind == JObject) for key, item in items(node.fields): if key == name: From 370f06d55719e8832a6c41d360bd78bf441c415c Mon Sep 17 00:00:00 2001 From: Varriount Date: Sat, 14 Jun 2014 22:32:37 -0400 Subject: [PATCH 30/44] Update categories.nim Fixed the tester from crashing when the babel package file is invalid. --- tests/testament/categories.nim | 45 ++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index bb9c90d2a..841eb8159 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -282,26 +282,33 @@ proc testBabelPackages(r: var TResults, cat: Category, filter: PackageFilter) = echo("[Warning] - Cannot run babel tests: Babel update failed.") return - for name, url in listPackages(filter): - var test = makeTest(name, "", cat) - echo(url) - let - installProcess = startProcess(babelExe, "", ["install", "-y", name]) - installStatus = waitForExitEx(installProcess) - installProcess.close - if installStatus != quitSuccess: - r.addResult(test, "", "", reInstallFailed) - continue + let packageFileTest = makeTest("PackageFileParsed", "", cat) + try: + for name, url in listPackages(filter): + var test = makeTest(name, "", cat) + echo(url) + let + installProcess = startProcess(babelExe, "", ["install", "-y", name]) + installStatus = waitForExitEx(installProcess) + installProcess.close + if installStatus != quitSuccess: + r.addResult(test, "", "", reInstallFailed) + continue + + let + buildPath = getPackageDir(name)[0.. -3] + let + buildProcess = startProcess(babelExe, buildPath, ["build"]) + buildStatus = waitForExitEx(buildProcess) + buildProcess.close + if buildStatus != quitSuccess: + r.addResult(test, "", "", reBuildFailed) + r.addResult(test, "", "", reSuccess) + r.addResult(packageFileTest, "", "", reSuccess) + except EJsonParsingError: + echo("[Warning] - Cannot run babel tests: Invalid package file.") + r.addResult(packageFileTest, "", "", reBuildFailed) - let - buildPath = getPackageDir(name)[0.. -3] - let - buildProcess = startProcess(babelExe, buildPath, ["build"]) - buildStatus = waitForExitEx(buildProcess) - buildProcess.close - if buildStatus != quitSuccess: - r.addResult(test, "", "", reBuildFailed) - r.addResult(test, "", "", reSuccess) # ---------------------------------------------------------------------------- From 8965ee59840dfa0ab439f9f6c11d725b41a1a013 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 15 Jun 2014 12:56:06 +0100 Subject: [PATCH 31/44] Add osproc stdin test. --- tests/osproc/ta.nim | 3 +++ tests/osproc/tstdin.nim | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 tests/osproc/ta.nim create mode 100644 tests/osproc/tstdin.nim diff --git a/tests/osproc/ta.nim b/tests/osproc/ta.nim new file mode 100644 index 000000000..6c1495590 --- /dev/null +++ b/tests/osproc/ta.nim @@ -0,0 +1,3 @@ +import strutils +let x = stdin.readLine() +echo x.parseInt + 5 \ No newline at end of file diff --git a/tests/osproc/tstdin.nim b/tests/osproc/tstdin.nim new file mode 100644 index 000000000..2ea939992 --- /dev/null +++ b/tests/osproc/tstdin.nim @@ -0,0 +1,16 @@ +discard """ + file: "tstdin.nim" + output: "10" +""" +import osproc, os, streams + +doAssert fileExists(getCurrentDir() / "tests" / "osproc" / "ta.exe") + +var p = startProcess("ta.exe", getCurrentDir() / "tests" / "osproc") +p.inputStream.write("5\n") +while true: + let line = p.outputStream.readLine() + if line != "": + echo line + else: + break \ No newline at end of file From 1658a29ec6bf24a4c144ad3cd36a41ebf35756ff Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 15 Jun 2014 12:56:28 +0100 Subject: [PATCH 32/44] Fixes #1263. --- tests/testament/caasdriver.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/testament/caasdriver.nim b/tests/testament/caasdriver.nim index 22c5ed6fa..8804f3ed7 100644 --- a/tests/testament/caasdriver.nim +++ b/tests/testament/caasdriver.nim @@ -86,6 +86,10 @@ proc doProcCommand(session: var TNimrodSession, command: string): string = proc doCommand(session: var TNimrodSession, command: string) = if session.mode == CaasRun: + if not session.nim.running: + session.lastOutput = "FAILED TO EXECUTE: " & command & "\n" & + "Exit code " & $session.nim.peekExitCode + return session.lastOutput = doCaasCommand(session, command & " " & session.filename) else: From 79b08488f725db10c29afe52250897fc830496e3 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 15 Jun 2014 20:17:23 +0100 Subject: [PATCH 33/44] Fix idetools --def crash. --- compiler/suggest.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/suggest.nim b/compiler/suggest.nim index a46c6a082..db95c480f 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -322,7 +322,7 @@ proc suggestSym*(n: PNode, s: PSym) {.inline.} = findUsages(n, s) if optDef in gGlobalOptions: findDefinition(n, s) - if isServing: + if isServing and not n.isNil: addToSourceMap(s, n.info) proc markUsed(n: PNode, s: PSym) = From 21423e5107b958422eeffd1f095713ac415bbf00 Mon Sep 17 00:00:00 2001 From: PavelVozenilek Date: Sun, 15 Jun 2014 22:53:09 +0200 Subject: [PATCH 34/44] making clear structural equivalency for tuples doc --- doc/tut1.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/tut1.txt b/doc/tut1.txt index 8c6f140eb..9874f267b 100644 --- a/doc/tut1.txt +++ b/doc/tut1.txt @@ -1385,8 +1385,8 @@ Tuples A tuple type defines various named *fields* and an *order* of the fields. The constructor ``()`` can be used to construct tuples. The order of the fields in the constructor must match the order in the tuple's definition. -Different tuple-types are *equivalent* if they specify the same fields of -the same type in the same order. +Different tuple-types are *equivalent* if they specify fields of +the same type and of the same name in the same order. The assignment operator for tuples copies each component. The notation ``t.field`` is used to access a tuple's field. Another notation is From ec23f5ec0a5d65a8aca2dadddf052852f53d83ba Mon Sep 17 00:00:00 2001 From: Clay Sweetser Date: Mon, 26 May 2014 07:24:57 -0400 Subject: [PATCH 35/44] Fix issue #1216 --- compiler/guards.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/guards.nim b/compiler/guards.nim index f475f5068..2b69024d2 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -484,7 +484,7 @@ proc factImplies(fact, prop: PNode): TImplication = # == not a or not b == not (a and b) let arg = fact.sons[1] case arg.getMagic - of mIsNil: + of mIsNil, mEqRef: return ~factImplies(arg, prop) of mAnd: # not (a and b) means not a or not b: From 2456c8dfe31e1bf54e5f98908e41fe3b6c7a1a6f Mon Sep 17 00:00:00 2001 From: flaviut Date: Mon, 16 Jun 2014 17:25:34 -0400 Subject: [PATCH 36/44] Fix bootstrapping --- lib/system.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system.nim b/lib/system.nim index 2c1257467..f45707849 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2985,7 +2985,7 @@ proc locals*(): TObject {.magic: "Locals", noSideEffect.} = ## # -> B is 1 discard -proc deepCopy*[T](x: T): T {.magic: "DeepCopy", noSideEffect.} +proc deepCopy*[T](x: T): T {.magic: "DeepCopy", noSideEffect.} = discard ## performs a deep copy of `x`. This is also used by the code generator ## for the implementation of ``spawn``. From ebff5f1f28ecc31a64ca9804c9a9a3ef4ba8e916 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 16 Jun 2014 23:36:11 +0100 Subject: [PATCH 37/44] Improve caasdriver output. --- tests/testament/caasdriver.nim | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/tests/testament/caasdriver.nim b/tests/testament/caasdriver.nim index 8804f3ed7..ddfe88273 100644 --- a/tests/testament/caasdriver.nim +++ b/tests/testament/caasdriver.nim @@ -106,7 +106,7 @@ proc close(session: var TNimrodSession) {.destructor.} = if session.mode == CaasRun: session.nim.close -proc doScenario(script: string, output: PStream, mode: TRunMode): bool = +proc doScenario(script: string, output: PStream, mode: TRunMode, verbose: bool): bool = result = true var f = open(script) @@ -138,7 +138,7 @@ proc doScenario(script: string, output: PStream, mode: TRunMode): bool = continue elif line.startsWith(">"): s.doCommand(line.substr(1).strip) - output.writeln line, "\n", s.lastOutput + output.writeln line, "\n", if verbose: s.lastOutput else: "" else: var expectMatch = true var pattern = s.replaceVars(line) @@ -155,13 +155,14 @@ proc doScenario(script: string, output: PStream, mode: TRunMode): bool = output.writeln "FAILURE ", line result = false -iterator caasTestsRunner*(filter = ""): tuple[test, output: string, - status: bool, mode: TRunMode] = +iterator caasTestsRunner*(filter = "", verbose = false): tuple[test, + output: string, status: bool, + mode: TRunMode] = for scenario in os.walkFiles(TesterDir / "caas/*.txt"): if filter.len > 0 and find(scenario, filter) == -1: continue for mode in modes: var outStream = newStringStream() - let r = doScenario(scenario, outStream, mode) + let r = doScenario(scenario, outStream, mode, verbose) yield (scenario, outStream.data, r, mode) when isMainModule: @@ -179,9 +180,12 @@ when isMainModule: if verbose and len(filter) > 0: echo "Running only test cases matching filter '$1'" % [filter] - for test, output, result, mode in caasTestsRunner(filter): + for test, output, result, mode in caasTestsRunner(filter, verbose): if not result or verbose: - echo test, "\n", output, "-> ", $mode, ":", $result, "\n-----" + echo "Mode ", $mode, " (", if result: "succeeded)" else: "failed)" + echo test + echo output + echo "---------\n" if not result: failures += 1 From 13608c0a1a5a5625c83f59864ec8326034c28438 Mon Sep 17 00:00:00 2001 From: Billingsly Wetherfordshire Date: Tue, 17 Jun 2014 15:05:50 -0700 Subject: [PATCH 38/44] fix json.`[]` --- 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 bd5259f95..4e369b854 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -679,8 +679,8 @@ proc `[]`*(node: PJsonNode, name: string): PJsonNode = proc `[]`*(node: PJsonNode, index: int): PJsonNode = ## Gets the node at `index` in an Array. Result is undefined if `index` ## is out of bounds + assert(not isNil(node)) assert(node.kind == JArray) - assert(node != nil) return node.elems[index] proc hasKey*(node: PJsonNode, key: string): bool = From a48c728ab3f8d3b0a3357d62b352d9913a600d9e Mon Sep 17 00:00:00 2001 From: Clay Sweetser Date: Wed, 18 Jun 2014 17:47:37 -0400 Subject: [PATCH 39/44] Added notnil test for issue #1216 --- tests/notnil/tnotnil4.nim | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tests/notnil/tnotnil4.nim diff --git a/tests/notnil/tnotnil4.nim b/tests/notnil/tnotnil4.nim new file mode 100644 index 000000000..23968ee48 --- /dev/null +++ b/tests/notnil/tnotnil4.nim @@ -0,0 +1,14 @@ +discard "" +type + TObj = ref object + +proc check(a: TObj not nil) = + echo repr(a) + +proc doit() = + var x : array[0..1, TObj] + + if x[0] != nil: + check(x[0]) + +doit() \ No newline at end of file From 7ebbc09578a0204a9bcf361a351e514dec0219c3 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 19 Jun 2014 00:05:27 +0100 Subject: [PATCH 40/44] Allow async lambdas. Other socket modifications. --- lib/pure/asyncdispatch.nim | 27 ++++++++++++++++++--------- lib/pure/asynchttpserver.nim | 7 ++++++- lib/pure/net.nim | 2 +- lib/pure/rawsockets.nim | 1 - 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 87ee83ad9..6d9e605f1 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -27,9 +27,11 @@ export TPort # TODO: Discarded void PFutures need to checked for exception. -# TODO: Exceptions are currently uncatchable due to the limitation that -# you cannot have yield in a try stmt. Perhaps I can get the macro to put -# a user's try except around ``future.read``. +# TODO: ``except`` statement (without `try`) does not work. +# TODO: Multiple exception names in a ``except`` don't work. +# TODO: The effect system (raises: []) has trouble with my try transformation. +# TODO: Can't await in a 'except' body + # -- Futures @@ -922,14 +924,17 @@ proc getName(node: PNimrodNode): string {.compileTime.} = return $node[1].ident of nnkIdent: return $node.ident + of nnkEmpty: + return "anonymous" else: - assert false + error("Unknown name.") macro async*(prc: stmt): stmt {.immediate.} = ## Macro which processes async procedures into the appropriate ## iterators and yield statements. - - expectKind(prc, nnkProcDef) + if prc.kind notin {nnkProcDef, nnkLambda}: + error("Cannot transform this node kind into an async proc." & + " Proc definition or lambda node expected.") hint("Processing " & prc[0].getName & " as an async proc.") @@ -941,7 +946,9 @@ macro async*(prc: stmt): stmt {.immediate.} = if $returnType[0] != "PFuture": error("Expected return type of 'PFuture' got '" & $returnType[0] & "'") - let subtypeIsVoid = returnType.kind == nnkEmpty + let subtypeIsVoid = returnType.kind == nnkEmpty or + (returnType.kind == nnkBracketExpr and + returnType[1].kind == nnkIdent and returnType[1].ident == !"void") var outerProcBody = newNimNode(nnkStmtList) @@ -990,17 +997,19 @@ macro async*(prc: stmt): stmt {.immediate.} = # Remove the 'async' pragma. for i in 0 .. Date: Sat, 21 Jun 2014 13:36:26 +0200 Subject: [PATCH 41/44] Use monospace as fallback font on website --- web/assets/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/assets/style.css b/web/assets/style.css index 5cee279fc..91bb4bd8a 100644 --- a/web/assets/style.css +++ b/web/assets/style.css @@ -93,7 +93,7 @@ html, body { border-left:10px solid #8f9698; background:#f3f6f8; font-size:15px; - font-family:courier; + font-family:courier, monospace; letter-spacing:0; line-height:17px; } From 3c89ad78eb3158a49509ac86152195fb1f6ea8e5 Mon Sep 17 00:00:00 2001 From: def Date: Sat, 21 Jun 2014 13:42:29 +0200 Subject: [PATCH 42/44] Rename {.effect.} to {.effects.} in Tut 2 --- doc/tut2.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tut2.txt b/doc/tut2.txt index 11b485f50..1e23618e0 100644 --- a/doc/tut2.txt +++ b/doc/tut2.txt @@ -501,7 +501,7 @@ with the file and line where the uncaught exception is being raised, which may help you locate the offending code which has changed. If you want to add the ``{.raises.}`` pragma to existing code, the compiler can -also help you. You can add the ``{.effect.}`` pragma statement to your proc and +also help you. You can add the ``{.effects.}`` pragma statement to your proc and the compiler will output all inferred effects up to that point (exception tracking is part of Nimrod's effect system). Another more roundabout way to find out the list of exceptions raised by a proc is to use the Nimrod ``doc2`` From 672e72487be702b15856ef51dda7f107f66cb462 Mon Sep 17 00:00:00 2001 From: Reimer Behrends Date: Sun, 22 Jun 2014 02:05:17 +0200 Subject: [PATCH 43/44] Fixed gorge/staticExec to not strip newlines. --- compiler/vmdeps.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 0e01f5031..9a213d813 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -15,6 +15,8 @@ proc readOutput(p: PProcess): string = discard p.waitForExit while not output.atEnd: result.add(output.readLine) + result.add("\n") + result.setLen(result.len - "\n".len) proc opGorge*(cmd, input: string): string = var p = startCmd(cmd) From 38cdd7595eeafe9906c42d258edeacaf50743bb1 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 22 Jun 2014 20:25:38 +0100 Subject: [PATCH 44/44] Remove varargs from json.`{}` --- lib/pure/json.nim | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 4e369b854..508e564c5 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -713,14 +713,12 @@ proc `[]=`*(obj: PJsonNode, key: string, val: PJsonNode) = return obj.fields.add((key, val)) -proc `{}`*(node: PJsonNode, names: varargs[string]): PJsonNode = +proc `{}`*(node: PJsonNode, key: string): PJsonNode = ## Transverses the node and gets the given value. If any of the ## names does not exist, returns nil result = node - for name in names: - result = result[name] - if isNil(result): - return nil + if isNil(node): return nil + result = result[key] proc `{}=`*(node: PJsonNode, names: varargs[string], value: PJsonNode) = ## Transverses the node and tries to set the value at the given location @@ -1059,7 +1057,7 @@ when isMainModule: let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd" }""" # nil passthrough - assert(testJson{"doesnt_exist", "anything"} == nil) + assert(testJson{"doesnt_exist"}{"anything"}.isNil) testJson{["c", "d"]} = %true assert(testJson["c"]["d"].bval)