diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ccgexprs.nim | 7 | ||||
-rw-r--r-- | compiler/ccgstmts.nim | 32 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 21 | ||||
-rw-r--r-- | compiler/ccgutils.nim | 2 | ||||
-rw-r--r-- | compiler/guards.nim | 4 | ||||
-rw-r--r-- | compiler/installer.ini | 114 | ||||
-rw-r--r-- | compiler/nimfix/nimfix.nim.cfg | 2 | ||||
-rw-r--r-- | compiler/nimsuggest/nimsuggest.nim | 11 | ||||
-rw-r--r-- | compiler/nimsuggest/nimsuggest.nim.cfg | 2 | ||||
-rw-r--r-- | compiler/options.nim | 2 | ||||
-rw-r--r-- | compiler/sem.nim | 4 | ||||
-rw-r--r-- | compiler/semexprs.nim | 83 | ||||
-rw-r--r-- | compiler/semfold.nim | 12 | ||||
-rw-r--r-- | compiler/seminst.nim | 4 | ||||
-rw-r--r-- | compiler/semmacrosanity.nim | 8 | ||||
-rw-r--r-- | compiler/sempass2.nim | 12 | ||||
-rw-r--r-- | compiler/semtypes.nim | 2 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 31 | ||||
-rw-r--r-- | compiler/transf.nim | 6 | ||||
-rw-r--r-- | compiler/types.nim | 42 | ||||
-rw-r--r-- | compiler/vm.nim | 21 | ||||
-rw-r--r-- | compiler/vmdef.nim | 9 | ||||
-rw-r--r-- | compiler/vmgen.nim | 46 | ||||
-rw-r--r-- | compiler/vmmarshal.nim | 283 |
24 files changed, 625 insertions, 135 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 93a9dd65d..05a3602d1 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -964,8 +964,11 @@ proc genEcho(p: BProc, n: PNode) = var args: Rope = nil var a: TLoc for i in countup(0, n.len-1): - initLocExpr(p, n.sons[i], a) - addf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)]) + if n.sons[i].skipConv.kind == nkNilLit: + add(args, ", \"nil\"") + else: + initLocExpr(p, n.sons[i], a) + addf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)]) linefmt(p, cpsStmts, "printf($1$2);$n", makeCString(repeat("%s", n.len) & tnl), args) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index b6572d960..6d29b1684 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -551,12 +551,7 @@ proc genBreakStmt(p: BProc, t: PNode) = lineF(p, cpsStmts, "goto $1;$n", [label]) proc getRaiseFrmt(p: BProc): string = - if p.module.compileToCpp: - result = "throw NimException($1, $2);$n" - elif getCompilerProc("Exception") != nil: - result = "#raiseException((#Exception*)$1, $2);$n" - else: - result = "#raiseException((#E_Base*)$1, $2);$n" + result = "#raiseException((#Exception*)$1, $2);$n" proc genRaiseStmt(p: BProc, t: PNode) = if p.inExceptBlock > 0: @@ -797,11 +792,8 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = # finallyPart(); if not isEmptyType(t.typ) and d.k == locNone: getTemp(p, t.typ, d) - var - exc: Rope - i, length, blen: int genLineDir(p, t) - exc = getTempName() + let exc = getTempName() if getCompilerProc("Exception") != nil: discard cgsym(p.module, "Exception") else: @@ -809,20 +801,23 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = add(p.nestedTryStmts, t) startBlock(p, "try {$n") expr(p, t.sons[0], d) - length = sonsLen(t) + let length = sonsLen(t) endBlock(p, ropecg(p.module, "} catch (NimException& $1) {$n", [exc])) if optStackTrace in p.options: - linefmt(p, cpsStmts, "#setFrame((TFrame*)&F);$n") + linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR);$n") inc p.inExceptBlock - i = 1 + var i = 1 var catchAllPresent = false while (i < length) and (t.sons[i].kind == nkExceptBranch): - blen = sonsLen(t.sons[i]) + let blen = sonsLen(t.sons[i]) if i > 1: addf(p.s(cpsStmts), "else ", []) if blen == 1: # general except section: catchAllPresent = true - exprBlock(p, t.sons[i].sons[0], d) + startBlock(p) + expr(p, t.sons[i].sons[0], d) + linefmt(p, cpsStmts, "#popCurrentException();$n") + endBlock(p) else: var orExpr: Rope = nil for j in countup(0, blen - 2): @@ -832,7 +827,10 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = "#isObj($1.exp->m_type, $2)", [exc, genTypeInfo(p.module, t.sons[i].sons[j].typ)]) lineF(p, cpsStmts, "if ($1) ", [orExpr]) - exprBlock(p, t.sons[i].sons[blen-1], d) + startBlock(p) + expr(p, t.sons[i].sons[blen-1], d) + linefmt(p, cpsStmts, "#popCurrentException();$n") + endBlock(p) inc(i) # reraise the exception if there was no catch all @@ -912,7 +910,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) = startBlock(p, "else {$n") linefmt(p, cpsStmts, "#popSafePoint();$n") if optStackTrace in p.options: - linefmt(p, cpsStmts, "#setFrame((TFrame*)&F);$n") + linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR);$n") inc p.inExceptBlock var i = 1 while (i < length) and (t.sons[i].kind == nkExceptBranch): diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 60ebf591b..3742fd2fd 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -11,20 +11,21 @@ # ------------------------- Name Mangling -------------------------------- -proc mangleField(name: string): string = - result = mangle(name) - result[0] = result[0].toUpper # Mangling makes everything lowercase, - # but some identifiers are C keywords - proc isKeyword(w: PIdent): bool = - # nimrod and C++ share some keywords - # it's more efficient to test the whole nimrod keywords range + # Nim and C++ share some keywords + # it's more efficient to test the whole Nim keywords range case w.id of ccgKeywordsLow..ccgKeywordsHigh, nimKeywordsLow..nimKeywordsHigh, ord(wInline): return true else: return false +proc mangleField(name: PIdent): string = + result = mangle(name.s) + if isKeyword(name): + result[0] = result[0].toUpper # Mangling makes everything lowercase, + # but some identifiers are C keywords + proc mangleName(s: PSym): Rope = result = s.loc.r if result == nil: @@ -110,7 +111,7 @@ proc mapSetType(typ: PType): TCTypeKind = else: result = ctArray proc mapType(typ: PType): TCTypeKind = - ## Maps a nimrod type to a C type + ## Maps a Nim type to a C type case typ.kind of tyNone, tyStmt: result = ctVoid of tyBool: result = ctBool @@ -379,7 +380,7 @@ proc mangleRecFieldName(field: PSym, rectype: PType): Rope = ({sfImportc, sfExportc} * rectype.sym.flags != {}): result = field.loc.r else: - result = rope(mangleField(field.name.s)) + result = rope(mangleField(field.name)) if result == nil: internalError(field.info, "mangleRecFieldName") proc genRecordFieldsAux(m: BModule, n: PNode, @@ -642,7 +643,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope = result.add getTypeDescAux(m, typeInSlot, check) else: inc i - + if chunkStart != 0: result.add cppName.data.substr(chunkStart) else: diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index 4e94c1867..4ba6643ec 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -176,7 +176,7 @@ proc mangle*(name: string): string = result = newStringOfCap(name.len) case name[0] of Letters: - result.add(name[0].toLower) + result.add(name[0]) of Digits: result.add("N" & name[0]) else: diff --git a/compiler/guards.nim b/compiler/guards.nim index dc2b24add..df2c1dd75 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -123,7 +123,7 @@ proc neg(n: PNode): PNode = let eAsNode = newIntNode(nkIntLit, e.sym.position) if not inSet(n.sons[1], eAsNode): s.add eAsNode result.sons[1] = s - elif lengthOrd(t) < 1000: + elif t.kind notin {tyString, tySequence} and lengthOrd(t) < 1000: result.sons[1] = complement(n.sons[1]) else: # not ({2, 3, 4}.contains(x)) x != 2 and x != 3 and x != 4 @@ -908,5 +908,5 @@ proc buildProperFieldCheck(access, check: PNode): PNode = proc checkFieldAccess*(m: TModel, n: PNode) = for i in 1..n.len-1: let check = buildProperFieldCheck(n.sons[0], n.sons[i]) - if m.doesImply(check) != impYes: + if check != nil and m.doesImply(check) != impYes: message(n.info, warnProveField, renderTree(n.sons[0])); break diff --git a/compiler/installer.ini b/compiler/installer.ini index 12a8e702d..fff82cb5b 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -47,7 +47,7 @@ Start: "doc/overview.html" [Other] Files: "readme.txt;install.txt;contributors.txt;copying.txt" -Files: "configure;makefile" +Files: "makefile" Files: "*.ini" Files: "koch.nim" @@ -70,6 +70,10 @@ Files: "doc/*.nim" Files: "doc/*.cfg" Files: "compiler/nimfix/*.nim" Files: "compiler/nimfix/*.cfg" +Files: "compiler/nimsuggest/*.nim" +Files: "compiler/nimsuggest/*.cfg" +Files: "compiler/plugins/locals/*.nim" +Files: "compiler/plugins/active.nim" Files: "tools/*.nim" Files: "tools/*.cfg" Files: "tools/*.tmpl" @@ -97,13 +101,8 @@ Files: "lib/pure/concurrency/*.cfg" Files: "lib/impure/*.nim" Files: "lib/wrappers/*.nim" -Files: "lib/wrappers/cairo/*.nim" -Files: "lib/wrappers/gtk/*.nim" -Files: "lib/wrappers/lua/*.nim" -Files: "lib/wrappers/opengl/*.nim" Files: "lib/wrappers/readline/*.nim" Files: "lib/wrappers/sdl/*.nim" -Files: "lib/wrappers/x11/*.nim" Files: "lib/wrappers/zip/*.nim" Files: "lib/wrappers/zip/libzip_all.c" @@ -115,8 +114,6 @@ Files: "lib/packages/docutils/*.nim" [Other] Files: "examples/*.nim" -Files: "examples/gtk/*.nim" -Files: "examples/0mq/*.nim" Files: "examples/c++iface/*.nim" Files: "examples/objciface/*.nim" Files: "examples/cross_calculator/" @@ -126,12 +123,109 @@ Files: "examples/*.txt" Files: "examples/*.cfg" Files: "examples/*.tmpl" +Files: "tests/actiontable/*.nim" +Files: "tests/alias/*.nim" +Files: "tests/ambsym/*.nim" +Files: "tests/array/*.nim" +Files: "tests/assign/*.nim" +Files: "tests/astoverload/*.nim" +Files: "tests/async/*.nim" +Files: "tests/benchmarks/*.nim" +Files: "tests/bind/*.nim" +Files: "tests/borrow/*.nim" +Files: "tests/casestmt/*.nim" +Files: "tests/ccgbugs/*.nim" +Files: "tests/clearmsg/*.nim" +Files: "tests/closure/*.nim" +Files: "tests/cnstseq/*.nim" +Files: "tests/collections/*.nim" +Files: "tests/compiles/*.nim" +Files: "tests/concat/*.nim" +Files: "tests/concepts/*.nim" +Files: "tests/constr/*.nim" +Files: "tests/constraints/*.nim" +Files: "tests/controlflow/*.nim" +Files: "tests/converter/*.nim" +Files: "tests/cpp/*.nim" +Files: "tests/defaultprocparam/*.nim" +Files: "tests/deprecated/*.nim" +Files: "tests/destructor/*.nim" +Files: "tests/dir with space/*.nim" +Files: "tests/discard/*.nim" +Files: "tests/distinct/*.nim" +Files: "tests/dll/*.nim" +Files: "tests/effects/*.nim" +Files: "tests/enum/*.nim" +Files: "tests/exception/*.nim" +Files: "tests/exprs/*.nim" +Files: "tests/fields/*.nim" +Files: "tests/float/*.nim" +Files: "tests/friends/*.nim" +Files: "tests/gc/*.nim" +Files: "tests/generics/*.nim" +Files: "tests/gensym/*.nim" +Files: "tests/global/*.nim" +Files: "tests/implicit/*.nim" +Files: "tests/init/*.nim" +Files: "tests/iter/*.nim" +Files: "tests/js/*.nim" +Files: "tests/js/*.cfg" +Files: "tests/let/*.nim" +Files: "tests/lexer/*.nim" +Files: "tests/lookups/*.nim" +Files: "tests/macros/*.nim" +Files: "tests/magics/*.nim" +Files: "tests/metatype/*.nim" +Files: "tests/method/*.nim" +Files: "tests/misc/*.nim" +Files: "tests/modules/*.nim" +Files: "tests/namedparams/*.nim" +Files: "tests/notnil/*.nim" +Files: "tests/objects/*.nim" +Files: "tests/objvariant/*.nim" +Files: "tests/openarray/*.nim" +Files: "tests/osproc/*.nim" +Files: "tests/overflw/*.nim" +Files: "tests/overload/*.nim" +Files: "tests/parallel/*.nim" +Files: "tests/parallel/*.cfg" +Files: "tests/parser/*.nim" +Files: "tests/pragmas/*.nim" +Files: "tests/proc/*.nim" +Files: "tests/procvar/*.nim" +Files: "tests/range/*.nim" +Files: "tests/rodfiles/*.nim" +Files: "tests/seq/*.nim" +Files: "tests/sets/*.nim" +Files: "tests/showoff/*.nim" +Files: "tests/specialops/*.nim" +Files: "tests/stdlib/*.nim" +Files: "tests/system/*.nim" +Files: "tests/template/*.nim" +Files: "tests/testament/*.nim" +Files: "tests/testdata/*.nim" +Files: "tests/threads/*.nim" +Files: "tests/threads/*.cfg" +Files: "tests/trmacros/*.nim" +Files: "tests/tuples/*.nim" +Files: "tests/typerel/*.nim" +Files: "tests/types/*.nim" +Files: "tests/usingstmt/*.nim" +Files: "tests/varres/*.nim" +Files: "tests/varstmt/*.nim" +Files: "tests/vm/*.nim" +Files: "tests/readme.txt" +Files: "tests/testament/css/*.css" +Files: "tests/testament/*.cfg" +Files: "lib/pure/unidecode/unidecode.dat" [Windows] Files: "bin/nim.exe" -Files: "bin/nim_debug.exe" Files: "bin/c2nim.exe" Files: "bin/nimgrep.exe" +Files: "bin/nimsuggest.exe" +Files: "bin/nimble.exe" +Files: "bin/*.dll" Files: "dist/*.dll" Files: "koch.exe" @@ -142,7 +236,7 @@ BinPath: r"bin;dist\mingw\bin;dist" ; Section | dir | zipFile | size hint (in KB) | url | exe start menu entry Download: r"Documentation|doc|docs.zip|13824|http://nim-lang.org/download/docs-${version}.zip|overview.html" Download: r"C Compiler (MingW)|dist|mingw.zip|82944|http://nim-lang.org/download/${mingw}.zip" -Download: r"Aporia IDE|dist|aporia.zip|97997|http://nim-lang.org/download/aporia-0.1.3.zip|aporia\bin\aporia.exe" +Download: r"Aporia IDE|dist|aporia.zip|97997|http://nim-lang.org/download/aporia-0.3.0.zip|aporia-0.3.0\bin\aporia.exe" ; for now only NSIS supports optional downloads [UnixBin] diff --git a/compiler/nimfix/nimfix.nim.cfg b/compiler/nimfix/nimfix.nim.cfg index 533563a98..73219d6f8 100644 --- a/compiler/nimfix/nimfix.nim.cfg +++ b/compiler/nimfix/nimfix.nim.cfg @@ -5,7 +5,7 @@ hint[XDeclaredButNotUsed]:off path:"$projectPath/.." path:"$lib/packages/docutils" -path:"$nim/compiler" +path:"../../compiler" define:useStdoutAsStdmsg symbol:nimfix diff --git a/compiler/nimsuggest/nimsuggest.nim b/compiler/nimsuggest/nimsuggest.nim index b45ca475c..8285d81d9 100644 --- a/compiler/nimsuggest/nimsuggest.nim +++ b/compiler/nimsuggest/nimsuggest.nim @@ -82,7 +82,8 @@ proc action(cmd: string) = if cmd[i] == ';': i = parseQuoted(cmd, dirtyfile, i+1) i += skipWhile(cmd, seps, i) - var line, col = -1 + var line = -1 + var col = 0 i += parseInt(cmd, line, i) i += skipWhile(cmd, seps, i) i += parseInt(cmd, col, i) @@ -97,7 +98,7 @@ proc action(cmd: string) = resetModule dirtyIdx if dirtyIdx != gProjectMainIdx: resetModule gProjectMainIdx - gTrackPos = newLineInfo(dirtyIdx, line, col) + gTrackPos = newLineInfo(dirtyIdx, line, col-1) #echo dirtyfile, gDirtyBufferIdx, " project ", gProjectMainIdx gErrorCounter = 0 if not isKnownFile: @@ -150,11 +151,11 @@ proc mainCommand = proc processCmdLine*(pass: TCmdLinePass, cmd: string) = var p = parseopt.initOptParser(cmd) - while true: + while true: parseopt.next(p) case p.kind - of cmdEnd: break - of cmdLongoption, cmdShortOption: + of cmdEnd: break + of cmdLongoption, cmdShortOption: case p.key.normalize of "port": gPort = parseInt(p.val).Port of "address": gAddress = p.val diff --git a/compiler/nimsuggest/nimsuggest.nim.cfg b/compiler/nimsuggest/nimsuggest.nim.cfg index 062092f16..acca17396 100644 --- a/compiler/nimsuggest/nimsuggest.nim.cfg +++ b/compiler/nimsuggest/nimsuggest.nim.cfg @@ -6,7 +6,7 @@ hint[XDeclaredButNotUsed]:off path:"$projectPath/../.." path:"$lib/packages/docutils" -path:"$nim/compiler" +path:"../../compiler" define:useStdoutAsStdmsg define:nimsuggest diff --git a/compiler/options.nim b/compiler/options.nim index 65250f519..998ab7781 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -1,7 +1,7 @@ # # # The Nim Compiler -# (c) Copyright 2013 Andreas Rumpf +# (c) Copyright 2015 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. diff --git a/compiler/sem.nim b/compiler/sem.nim index 2e13c88c3..346a17df1 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -89,6 +89,10 @@ proc fitNode(c: PContext, formal: PType, arg: PNode): PNode = let x = result.skipConv if x.kind == nkPar and formal.kind != tyExpr: changeType(x, formal, check=true) + else: + result = skipHiddenSubConv(result) + #result.typ = takeType(formal, arg.typ) + #echo arg.info, " picked ", result.typ.typeToString proc inferWithMetatype(c: PContext, formal: PType, arg: PNode, coerceDistincts = false): PNode diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index eb8d0c561..cd6ba3753 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -24,7 +24,7 @@ proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # same as 'semExprWithType' but doesn't check for proc vars result = semExpr(c, n, flags + {efOperand}) - if result.kind == nkEmpty: + if result.kind == nkEmpty and result.typ.isNil: # do not produce another redundant error message: #raiseRecoverableError("") result = errorNode(c, n) @@ -447,6 +447,7 @@ proc changeType(n: PNode, newType: PType, check: bool) = of nkPar: let tup = newType.skipTypes({tyGenericInst}) if tup.kind != tyTuple: + if tup.kind == tyObject: return internalError(n.info, "changeType: no tuple type for constructor") elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr: # named tuple? @@ -535,43 +536,55 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = result.typ.sons[0] = makeRangeType(c, 0, sonsLen(result) - 1, n.info) proc fixAbstractType(c: PContext, n: PNode) = - # XXX finally rewrite that crap! - for i in countup(1, sonsLen(n) - 1): - var it = n.sons[i] - case it.kind - of nkHiddenStdConv, nkHiddenSubConv: - if it.sons[1].kind == nkBracket: - it.sons[1].typ = arrayConstrType(c, it.sons[1]) - #it.sons[1] = semArrayConstr(c, it.sons[1]) - if skipTypes(it.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: - #if n.sons[0].kind == nkSym and IdentEq(n.sons[0].sym.name, "[]="): - # debug(n) - - var s = skipTypes(it.sons[1].typ, abstractVar) - if s.kind == tyArrayConstr and s.sons[1].kind == tyEmpty: - s = copyType(s, getCurrOwner(), false) - skipTypes(s, abstractVar).sons[1] = elemType( - skipTypes(it.typ, abstractVar)) - it.sons[1].typ = s - elif s.kind == tySequence and s.sons[0].kind == tyEmpty: - s = copyType(s, getCurrOwner(), false) - skipTypes(s, abstractVar).sons[0] = elemType( - skipTypes(it.typ, abstractVar)) - it.sons[1].typ = s - - elif skipTypes(it.sons[1].typ, abstractVar).kind in - {tyNil, tyArrayConstr, tyTuple, tySet}: + for i in 1 .. < n.len: + let it = n.sons[i] + # do not get rid of nkHiddenSubConv for OpenArrays, the codegen needs it: + if it.kind == nkHiddenSubConv and + skipTypes(it.typ, abstractVar).kind notin {tyOpenArray, tyVarargs}: + if skipTypes(it.sons[1].typ, abstractVar).kind in + {tyNil, tyArrayConstr, tyTuple, tySet}: var s = skipTypes(it.typ, abstractVar) if s.kind != tyExpr: changeType(it.sons[1], s, check=true) n.sons[i] = it.sons[1] - of nkBracket: - # an implicitly constructed array (passed to an open array): - n.sons[i] = semArrayConstr(c, it, {}) - else: - discard - #if (it.typ == nil): - # InternalError(it.info, "fixAbstractType: " & renderTree(it)) + when false: + # XXX finally rewrite that crap! + for i in countup(1, sonsLen(n) - 1): + var it = n.sons[i] + case it.kind + of nkHiddenStdConv, nkHiddenSubConv: + if it.sons[1].kind == nkBracket: + it.sons[1].typ = arrayConstrType(c, it.sons[1]) + #it.sons[1] = semArrayConstr(c, it.sons[1]) + if skipTypes(it.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: + #if n.sons[0].kind == nkSym and IdentEq(n.sons[0].sym.name, "[]="): + # debug(n) + + var s = skipTypes(it.sons[1].typ, abstractVar) + if s.kind == tyArrayConstr and s.sons[1].kind == tyEmpty: + s = copyType(s, getCurrOwner(), false) + skipTypes(s, abstractVar).sons[1] = elemType( + skipTypes(it.typ, abstractVar)) + it.sons[1].typ = s + elif s.kind == tySequence and s.sons[0].kind == tyEmpty: + s = copyType(s, getCurrOwner(), false) + skipTypes(s, abstractVar).sons[0] = elemType( + skipTypes(it.typ, abstractVar)) + it.sons[1].typ = s + + elif skipTypes(it.sons[1].typ, abstractVar).kind in + {tyNil, tyArrayConstr, tyTuple, tySet}: + var s = skipTypes(it.typ, abstractVar) + if s.kind != tyExpr: + changeType(it.sons[1], s, check=true) + n.sons[i] = it.sons[1] + of nkBracket: + # an implicitly constructed array (passed to an open array): + n.sons[i] = semArrayConstr(c, it, {}) + else: + discard + #if (it.typ == nil): + # InternalError(it.info, "fixAbstractType: " & renderTree(it)) proc skipObjConv(n: PNode): PNode = case n.kind @@ -2040,7 +2053,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkEmpty, nkNone, nkCommentStmt: discard of nkNilLit: - result.typ = getSysType(tyNil) + if result.typ == nil: result.typ = getSysType(tyNil) of nkIntLit: if result.typ == nil: setIntLitType(result) of nkInt8Lit: diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 796dde9a6..da24005c2 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -286,10 +286,13 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = of mNot: result = newIntNodeT(1 - getInt(a), n) of mCard: result = newIntNodeT(nimsets.cardSet(a), n) of mBitnotI, mBitnotI64: result = newIntNodeT(not getInt(a), n) - of mLengthStr, mXLenStr: result = newIntNodeT(len(getStr(a)), n) + of mLengthStr, mXLenStr: + if a.kind == nkNilLit: result = newIntNodeT(0, n) + else: result = newIntNodeT(len(getStr(a)), n) of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n) of mLengthSeq, mLengthOpenArray, mXLenSeq: - result = newIntNodeT(sonsLen(a), n) # BUGFIX + if a.kind == nkNilLit: result = newIntNodeT(0, n) + else: result = newIntNodeT(sonsLen(a), n) # BUGFIX of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away of mToFloat, mToBiggestFloat: result = newFloatNodeT(toFloat(int(getInt(a))), n) @@ -431,7 +434,8 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq, mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait, mDotDot, - mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn, mParallel: + mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn, + mParallel, mPlugin: discard else: internalError(a.info, "evalOp(" & $m & ')') @@ -651,7 +655,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode = result = copyNode(n) of nkIfExpr: result = getConstIfExpr(m, n) - of nkCall, nkCommand, nkCallStrLit, nkPrefix, nkInfix: + of nkCallKinds: if n.sons[0].kind != nkSym: return var s = n.sons[0].sym if s.kind != skProc: return diff --git a/compiler/seminst.nim b/compiler/seminst.nim index f72e2dc5b..b2aef63a8 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -187,7 +187,9 @@ proc instantiateProcType(c: PContext, pt: TIdTable, let param = copySym(oldParam) param.owner = prc param.typ = result.sons[i] - param.ast = oldParam.ast.copyTree + if oldParam.ast != nil: + param.ast = fitNode(c, param.typ, oldParam.ast) + # don't be lazy here and call replaceTypeVarsN(cl, originalParams[i])! result.n.sons[i] = newSymNode(param) addDecl(c, param) diff --git a/compiler/semmacrosanity.nim b/compiler/semmacrosanity.nim index 2ef7a54e7..bb9814a16 100644 --- a/compiler/semmacrosanity.nim +++ b/compiler/semmacrosanity.nim @@ -16,9 +16,9 @@ proc ithField(n: PNode, field: int): PSym = result = nil case n.kind of nkRecList: - for i in countup(0, sonsLen(n) - 1): + for i in countup(0, sonsLen(n) - 1): result = ithField(n.sons[i], field-i) - if result != nil: return + if result != nil: return of nkRecCase: if n.sons[0].kind != nkSym: internalError(n.info, "ithField") result = ithField(n.sons[0], field-1) @@ -34,7 +34,7 @@ proc ithField(n: PNode, field: int): PSym = else: discard proc annotateType*(n: PNode, t: PType) = - let x = t.skipTypes(abstractInst) + let x = t.skipTypes(abstractInst+{tyRange}) # Note: x can be unequal to t and we need to be careful to use 't' # to not to skip tyGenericInst case n.kind @@ -80,7 +80,7 @@ proc annotateType*(n: PNode, t: PType) = if x.kind in {tyString, tyCString}: n.typ = t else: - globalError(n.info, "string literal must be of some string type") + globalError(n.info, "string literal must be of some string type") of nkNilLit: if x.kind in NilableTypes: n.typ = t diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 6bc0fa32c..adf03be64 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -560,7 +560,10 @@ proc trackCase(tracked: PEffects, n: PNode) = track(tracked, n.sons[0]) let oldState = tracked.init.len let oldFacts = tracked.guards.len - let interesting = interestingCaseExpr(n.sons[0]) and warnProveField in gNotes + let stringCase = skipTypes(n.sons[0].typ, + abstractVarRange-{tyTypeDesc}).kind in {tyFloat..tyFloat128, tyString} + let interesting = not stringCase and interestingCaseExpr(n.sons[0]) and + warnProveField in gNotes var inter: TIntersection = @[] var toCover = 0 for i in 1.. <n.len: @@ -575,13 +578,8 @@ proc trackCase(tracked: PEffects, n: PNode) = for i in oldState.. <tracked.init.len: addToIntersection(inter, tracked.init[i]) - let exh = case skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc}).kind - of tyFloat..tyFloat128, tyString: - lastSon(n).kind == nkElse - else: - true setLen(tracked.init, oldState) - if exh: + if not stringCase or lastSon(n).kind == nkElse: for id, count in items(inter): if count >= toCover: tracked.init.add id # else we can't merge diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 304fe6d14..8c7bd7243 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -629,7 +629,7 @@ proc skipGenericInvocation(t: PType): PType {.inline.} = result = t if result.kind == tyGenericInvocation: result = result.sons[0] - if result.kind == tyGenericBody: + while result.kind in {tyGenericInst, tyGenericBody}: result = lastSon(result) proc addInheritedFields(c: PContext, check: var IntSet, pos: var int, diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 5c8a3bc58..2a9d15b5a 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -147,6 +147,7 @@ proc copyCandidate(a: var TCandidate, b: TCandidate) = proc sumGeneric(t: PType): int = var t = t + var isvar = 1 while true: case t.kind of tyGenericInst, tyArray, tyRef, tyPtr, tyDistinct, tyArrayConstr, @@ -154,18 +155,20 @@ proc sumGeneric(t: PType): int = t = t.lastSon inc result of tyVar: - # but do not make 'var T' more specific than 'T'! t = t.sons[0] + inc result + inc isvar of tyGenericInvocation, tyTuple: - result = ord(t.kind == tyGenericInvocation) + result += ord(t.kind == tyGenericInvocation) for i in 0 .. <t.len: result += t.sons[i].sumGeneric break of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break of tyBool, tyChar, tyEnum, tyObject, tyProc, tyPointer, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128, tyUInt..tyUInt64: - return 1 - else: return 0 + return isvar + else: + return 0 #var ggDebug: bool @@ -919,6 +922,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = of tyAnd: considerPreviousT: + result = isEqual for branch in f.sons: let x = typeRel(c, branch, aOrig) if x < isSubtype: return isNone @@ -1196,15 +1200,6 @@ proc isInlineIterator*(t: PType): bool = result = t.kind == tyIter or (t.kind == tyBuiltInTypeClass and t.base.kind == tyIter) -proc isEmptyContainer*(t: PType): bool = - case t.kind - of tyExpr, tyNil: result = true - of tyArray, tyArrayConstr: result = t.sons[1].kind == tyEmpty - of tySet, tySequence, tyOpenArray, tyVarargs: - result = t.sons[0].kind == tyEmpty - of tyGenericInst: result = isEmptyContainer(t.lastSon) - else: result = false - proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) = case r of isConvertible, isIntConv: inc(m.convMatches, convMatch) @@ -1309,7 +1304,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, if arg.typ == nil: result = arg elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple: - result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) + result = implicitConv(nkHiddenSubConv, f, arg, m, c) elif arg.typ.isEmptyContainer: result = arg.copyTree result.typ = getInstantiatedType(c, arg, m, f) @@ -1324,7 +1319,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, inc(m.exactMatches) result = arg if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}: - result = implicitConv(nkHiddenStdConv, f, arg, m, c) + result = implicitConv(nkHiddenSubConv, f, arg, m, c) of isNone: # do not do this in ``typeRel`` as it then can't infere T in ``ref T``: if a.kind in {tyProxy, tyUnknown}: @@ -1470,9 +1465,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m.state = csNoMatch return if formal.typ.kind == tyVar: - if n.isLValue: - inc(m.genericMatches, 100) - else: + if not n.isLValue: m.state = csNoMatch return @@ -1578,6 +1571,8 @@ proc matchesAux(c: PContext, n, nOrig: PNode, #assert(container == nil) if container.isNil: container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg)) + else: + incrIndexType(container.typ) addSon(container, arg) setSon(m.call, formal.position + 1, implicitConv(nkHiddenStdConv, formal.typ, container, m, c)) diff --git a/compiler/transf.nim b/compiler/transf.nim index 2143b6bec..57547b682 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -379,6 +379,9 @@ proc transformConv(c: PTransf, n: PNode): PTransNode = result = transformSons(c, n) of tyOpenArray, tyVarargs: result = transform(c, n.sons[1]) + PNode(result).typ = takeType(n.typ, n.sons[1].typ) + #echo n.info, " came here and produced ", typeToString(PNode(result).typ), + # " from ", typeToString(n.typ), " and ", typeToString(n.sons[1].typ) of tyCString: if source.kind == tyString: result = newTransNode(nkStringToCString, n, 1) @@ -713,8 +716,7 @@ proc transform(c: PTransf, n: PNode): PTransNode = add(result, PTransNode(newSymNode(labl))) of nkBreakStmt: result = transformBreak(c, n) of nkWhileStmt: result = transformWhile(c, n) - of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix, - nkCallStrLit: + of nkCallKinds: result = transformCall(c, n) of nkAddr, nkHiddenAddr: result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref) diff --git a/compiler/types.nim b/compiler/types.nim index 7f05e7051..e205f5722 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1439,3 +1439,45 @@ proc skipConv*(n: PNode): PNode = proc skipConvTakeType*(n: PNode): PNode = result = n.skipConv result.typ = n.typ + +proc isEmptyContainer*(t: PType): bool = + case t.kind + of tyExpr, tyNil: result = true + of tyArray, tyArrayConstr: result = t.sons[1].kind == tyEmpty + of tySet, tySequence, tyOpenArray, tyVarargs: + result = t.sons[0].kind == tyEmpty + of tyGenericInst: result = isEmptyContainer(t.lastSon) + else: result = false + +proc takeType*(formal, arg: PType): PType = + # param: openArray[string] = [] + # [] is an array constructor of length 0 of type string! + if arg.kind == tyNil: + # and not (formal.kind == tyProc and formal.callConv == ccClosure): + result = formal + elif formal.kind in {tyOpenArray, tyVarargs, tySequence} and + arg.isEmptyContainer: + let a = copyType(arg.skipTypes({tyGenericInst}), arg.owner, keepId=false) + a.sons[ord(arg.kind in {tyArray, tyArrayConstr})] = formal.sons[0] + result = a + elif formal.kind in {tyTuple, tySet} and arg.kind == formal.kind: + result = formal + else: + result = arg + +proc skipHiddenSubConv*(n: PNode): PNode = + if n.kind == nkHiddenSubConv: + # param: openArray[string] = [] + # [] is an array constructor of length 0 of type string! + let formal = n.typ + result = n.sons[1] + let arg = result.typ + let dest = takeType(formal, arg) + if dest == arg and formal.kind != tyExpr: + #echo n.info, " came here for ", formal.typeToString + result = n + else: + result = copyTree(result) + result.typ = dest + else: + result = n diff --git a/compiler/vm.nim b/compiler/vm.nim index 6fae5a8b7..1c6c9a30b 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -16,7 +16,8 @@ import ast except getstr import strutils, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, unsigned, - parser, vmdeps, idents, trees, renderer, options, transf, parseutils + parser, vmdeps, idents, trees, renderer, options, transf, parseutils, + vmmarshal from semfold import leValueConv, ordinalValToString from evaltempl import evalTemplate @@ -371,11 +372,6 @@ template handleJmpBack() {.dirty.} = globalError(c.debug[pc], errTooManyIterations) dec(c.loopIterations) -proc skipColon(n: PNode): PNode = - result = n - if n.kind == nkExprColonExpr: - result = n.sons[1] - proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = var pc = start var tos = tos @@ -1369,6 +1365,19 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = while typ.kind == tyTypeDesc and typ.len > 0: typ = typ.sons[0] createStr regs[ra] regs[ra].node.strVal = typ.typeToString(preferExported) + of opcMarshalLoad: + let ra = instr.regA + let rb = instr.regB + inc pc + let typ = c.types[c.code[pc].regBx - wordExcess] + putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ)) + of opcMarshalStore: + decodeB(rkNode) + inc pc + let typ = c.types[c.code[pc].regBx - wordExcess] + createStrKeepNode(regs[ra]) + if regs[ra].node.strVal.isNil: regs[ra].node.strVal = newStringOfCap(1000) + storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode) inc pc proc execute(c: PCtx, start: int): PNode = diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index b4892d010..047009f01 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -66,7 +66,8 @@ type opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr, opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq, opcSwap, opcIsNil, opcOf, opcIs, - opcSubStr, opcParseFloat, opcConv, opcCast, opcQuit, opcReset, + opcSubStr, opcParseFloat, opcConv, opcCast, + opcQuit, opcReset, opcNarrowS, opcNarrowU, opcAddStrCh, @@ -132,7 +133,8 @@ type opcLdImmInt, # dest = immediate value opcNBindSym, opcSetType, # dest.typ = types[Bx] - opcTypeTrait + opcTypeTrait, + opcMarshalLoad, opcMarshalStore TBlock* = object label*: PSym @@ -221,7 +223,8 @@ proc registerCallback*(c: PCtx; name: string; callback: VmCallback) = const firstABxInstr* = opcTJmp largeInstrs* = { # instructions which use 2 int32s instead of 1: - opcSubStr, opcConv, opcCast, opcNewSeq, opcOf} + opcSubStr, opcConv, opcCast, opcNewSeq, opcOf, + opcMarshalLoad, opcMarshalStore} slotSomeTemp* = slotTempUnknown relativeJumps* = {opcTJmp, opcFJmp, opcJmp, opcJmpBack} diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index b354061a9..0743a4502 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -76,6 +76,11 @@ proc codeListing(c: PCtx, result: var string, start=0; last = -1) = elif opc in {opcLdConst, opcAsgnConst}: result.addf("\t$#\tr$#, $#", ($opc).substr(3), x.regA, c.constants[x.regBx-wordExcess].renderTree) + elif opc in {opcMarshalLoad, opcMarshalStore}: + let y = c.code[i+1] + result.addf("\t$#\tr$#, r$#, $#", ($opc).substr(3), x.regA, x.regB, + c.types[y.regBx-wordExcess].typeToString) + inc i else: result.addf("\t$#\tr$#, $#", ($opc).substr(3), x.regA, x.regBx-wordExcess) result.add("\t#") @@ -696,8 +701,7 @@ proc genCard(c: PCtx; n: PNode; dest: var TDest) = c.gABC(n, opcCard, dest, tmp) c.freeTemp(tmp) -proc genMagic(c: PCtx; n: PNode; dest: var TDest) = - let m = n.sons[0].sym.magic +proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = case m of mAnd: c.genAndOr(n, opcFJmp, dest) of mOr: c.genAndOr(n, opcTJmp, dest) @@ -1028,6 +1032,22 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) = # mGCref, mGCunref, internalError(n.info, "cannot generate code for: " & $m) +proc genMarshalLoad(c: PCtx, n: PNode, dest: var TDest) = + ## Signature: proc to*[T](data: string): T + if dest < 0: dest = c.getTemp(n.typ) + var tmp = c.genx(n.sons[1]) + c.gABC(n, opcMarshalLoad, dest, tmp) + c.gABx(n, opcMarshalLoad, 0, c.genType(n.typ)) + c.freeTemp(tmp) + +proc genMarshalStore(c: PCtx, n: PNode, dest: var TDest) = + ## Signature: proc `$$`*[T](x: T): string + if dest < 0: dest = c.getTemp(n.typ) + var tmp = c.genx(n.sons[1]) + c.gABC(n, opcMarshalStore, dest, tmp) + c.gABx(n, opcMarshalStore, 0, c.genType(n.sons[1].typ)) + c.freeTemp(tmp) + const atomicTypes = {tyBool, tyChar, tyExpr, tyStmt, tyTypeDesc, tyStatic, @@ -1533,6 +1553,15 @@ proc matches(s: PSym; x: string): bool = dec L result = true +proc matches(s: PSym; y: varargs[string]): bool = + var s = s + var L = y.len-1 + while L >= 0: + if s == nil or y[L].cmpIgnoreStyle(s.name.s) != 0: return false + s = if sfFromGeneric in s.flags: s.owner.owner else: s.owner + dec L + result = true + proc procIsCallback(c: PCtx; s: PSym): bool = if s.offset < -1: return true var i = -2 @@ -1570,8 +1599,17 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = else: internalError(n.info, "cannot generate code for: " & s.name.s) of nkCallKinds: - if n.sons[0].kind == nkSym and n.sons[0].sym.magic != mNone: - genMagic(c, n, dest) + if n.sons[0].kind == nkSym: + let s = n.sons[0].sym + if s.magic != mNone: + genMagic(c, n, dest, s.magic) + elif matches(s, "stdlib", "marshal", "to"): + genMarshalLoad(c, n, dest) + elif matches(s, "stdlib", "marshal", "$$"): + genMarshalStore(c, n, dest) + else: + genCall(c, n, dest) + clearDest(c, n, dest) else: genCall(c, n, dest) clearDest(c, n, dest) diff --git a/compiler/vmmarshal.nim b/compiler/vmmarshal.nim new file mode 100644 index 000000000..293d0d949 --- /dev/null +++ b/compiler/vmmarshal.nim @@ -0,0 +1,283 @@ +# +# +# The Nim Compiler +# (c) Copyright 2015 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Implements marshaling for the VM. + +import streams, json, intsets, tables, ast, astalgo, idents, types, msgs + +proc ptrToInt(x: PNode): int {.inline.} = + result = cast[int](x) # don't skip alignment + +proc getField(n: PNode; position: int): PSym = + case n.kind + of nkRecList: + for i in countup(0, sonsLen(n) - 1): + result = getField(n.sons[i], position) + if result != nil: return + of nkRecCase: + result = getField(n.sons[0], position) + if result != nil: return + for i in countup(1, sonsLen(n) - 1): + case n.sons[i].kind + of nkOfBranch, nkElse: + result = getField(lastSon(n.sons[i]), position) + if result != nil: return + else: internalError(n.info, "getField(record case branch)") + of nkSym: + if n.sym.position == position: result = n.sym + else: discard + +proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) + +proc storeObj(s: var string; typ: PType; x: PNode; stored: var IntSet) = + internalAssert x.kind in {nkObjConstr, nkPar} + let start = ord(x.kind == nkObjConstr) + for i in countup(start, sonsLen(x) - 1): + if i > start: s.add(", ") + var it = x.sons[i] + if it.kind == nkExprColonExpr: + internalAssert it.sons[0].kind == nkSym + let field = it.sons[0].sym + s.add(escapeJson(field.name.s)) + s.add(": ") + storeAny(s, field.typ, it.sons[1], stored) + elif typ.n != nil: + let field = getField(typ.n, i) + s.add(escapeJson(field.name.s)) + s.add(": ") + storeAny(s, field.typ, it, stored) + +proc skipColon*(n: PNode): PNode = + result = n + if n.kind == nkExprColonExpr: + result = n.sons[1] + +proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) = + case t.kind + of tyNone: assert false + of tyBool: s.add($(a.intVal != 0)) + of tyChar: + let ch = char(a.intVal) + if ch < '\128': + s.add(escapeJson($ch)) + else: + s.add($int(ch)) + of tyArray, tySequence: + if t.kind == tySequence and a.kind == nkNilLit: s.add("null") + else: + s.add("[") + for i in 0 .. a.len-1: + if i > 0: s.add(", ") + storeAny(s, t.elemType, a[i], stored) + s.add("]") + of tyTuple: + s.add("{") + for i in 0.. <t.len: + if i > 0: s.add(", ") + s.add("\"Field" & $i) + s.add("\": ") + storeAny(s, t.sons[i], a[i].skipColon, stored) + s.add("}") + of tyObject: + s.add("{") + storeObj(s, t, a, stored) + s.add("}") + of tySet: + s.add("[") + for i in 0.. <a.len: + if i > 0: s.add(", ") + if a[i].kind == nkRange: + var x = copyNode(a[i][0]) + storeAny(s, t.lastSon, x, stored) + while x.intVal+1 <= a[i][1].intVal: + s.add(", ") + storeAny(s, t.lastSon, x, stored) + inc x.intVal + else: + storeAny(s, t.lastSon, a[i], stored) + s.add("]") + of tyRange, tyGenericInst: storeAny(s, t.lastSon, a, stored) + of tyEnum: + # we need a slow linear search because of enums with holes: + for e in items(t.n): + if e.sym.position == a.intVal: + s.add e.sym.name.s.escapeJson + break + of tyPtr, tyRef: + var x = a + if isNil(x) or x.kind == nkNilLit: s.add("null") + elif stored.containsOrIncl(x.ptrToInt): + # already stored, so we simply write out the pointer as an int: + s.add($x.ptrToInt) + else: + # else as a [value, key] pair: + # (reversed order for convenient x[0] access!) + s.add("[") + s.add($x.ptrToInt) + s.add(", ") + storeAny(s, t.lastSon, a, stored) + s.add("]") + of tyString, tyCString: + if a.kind == nkNilLit or a.strVal.isNil: s.add("null") + else: s.add(escapeJson(a.strVal)) + of tyInt..tyInt64, tyUInt..tyUInt64: s.add($a.intVal) + of tyFloat..tyFloat128: s.add($a.floatVal) + else: + internalError a.info, "cannot marshal at compile-time " & t.typeToString + +proc storeAny*(s: var string; t: PType; a: PNode) = + var stored = initIntSet() + storeAny(s, t, a, stored) + +proc loadAny(p: var JsonParser, t: PType, + tab: var Table[BiggestInt, PNode]): PNode = + case t.kind + of tyNone: assert false + of tyBool: + case p.kind + of jsonFalse: result = newIntNode(nkIntLit, 0) + of jsonTrue: result = newIntNode(nkIntLit, 1) + else: raiseParseErr(p, "'true' or 'false' expected for a bool") + next(p) + of tyChar: + if p.kind == jsonString: + var x = p.str + if x.len == 1: + result = newIntNode(nkIntLit, ord(x[0])) + next(p) + return + elif p.kind == jsonInt: + result = newIntNode(nkIntLit, getInt(p)) + next(p) + return + raiseParseErr(p, "string of length 1 expected for a char") + of tyEnum: + if p.kind == jsonString: + for e in items(t.n): + if e.sym.name.s == p.str: + result = newIntNode(nkIntLit, e.sym.position) + next(p) + return + raiseParseErr(p, "string expected for an enum") + of tyArray: + if p.kind != jsonArrayStart: raiseParseErr(p, "'[' expected for an array") + next(p) + result = newNode(nkBracket) + while p.kind != jsonArrayEnd and p.kind != jsonEof: + result.add loadAny(p, t.elemType, tab) + if p.kind == jsonArrayEnd: next(p) + else: raiseParseErr(p, "']' end of array expected") + of tySequence: + case p.kind + of jsonNull: + result = newNode(nkNilLit) + next(p) + of jsonArrayStart: + next(p) + result = newNode(nkBracket) + while p.kind != jsonArrayEnd and p.kind != jsonEof: + result.add loadAny(p, t.elemType, tab) + if p.kind == jsonArrayEnd: next(p) + else: raiseParseErr(p, "") + else: + raiseParseErr(p, "'[' expected for a seq") + of tyTuple: + if p.kind != jsonObjectStart: raiseParseErr(p, "'{' expected for an object") + next(p) + result = newNode(nkPar) + var i = 0 + while p.kind != jsonObjectEnd and p.kind != jsonEof: + if p.kind != jsonString: + raiseParseErr(p, "string expected for a field name") + next(p) + if i >= t.len: + raiseParseErr(p, "too many fields to tuple type " & typeToString(t)) + result.add loadAny(p, t.sons[i], tab) + inc i + if p.kind == jsonObjectEnd: next(p) + else: raiseParseErr(p, "'}' end of object expected") + of tyObject: + if p.kind != jsonObjectStart: raiseParseErr(p, "'{' expected for an object") + next(p) + result = newNode(nkPar) + result.sons = @[] + while p.kind != jsonObjectEnd and p.kind != jsonEof: + if p.kind != jsonString: + raiseParseErr(p, "string expected for a field name") + let field = lookupInRecord(t.n, getIdent(p.str)) + if field.isNil: + raiseParseErr(p, "unknown field for object of type " & typeToString(t)) + next(p) + if field.position >= result.sons.len: + setLen(result.sons, field.position+1) + result.sons[field.position] = loadAny(p, field.typ, tab) + if p.kind == jsonObjectEnd: next(p) + else: raiseParseErr(p, "'}' end of object expected") + of tySet: + if p.kind != jsonArrayStart: raiseParseErr(p, "'[' expected for a set") + next(p) + result = newNode(nkCurly) + while p.kind != jsonArrayEnd and p.kind != jsonEof: + result.add loadAny(p, t.lastSon, tab) + next(p) + if p.kind == jsonArrayEnd: next(p) + else: raiseParseErr(p, "']' end of array expected") + of tyPtr, tyRef: + case p.kind + of jsonNull: + result = newNode(nkNilLit) + next(p) + of jsonInt: + result = tab[p.getInt] + if result.isNil: + raiseParseErr(p, "cannot load object with address " & $p.getInt) + next(p) + of jsonArrayStart: + next(p) + if p.kind == jsonInt: + let idx = p.getInt + next(p) + result = loadAny(p, t.lastSon, tab) + tab[idx] = result + else: raiseParseErr(p, "index for ref type expected") + if p.kind == jsonArrayEnd: next(p) + else: raiseParseErr(p, "']' end of ref-address pair expected") + else: raiseParseErr(p, "int for pointer type expected") + of tyString, tyCString: + case p.kind + of jsonNull: + result = newNode(nkNilLit) + next(p) + of jsonString: + result = newStrNode(nkStrLit, p.str) + next(p) + else: raiseParseErr(p, "string expected") + of tyInt..tyInt64, tyUInt..tyUInt64: + if p.kind == jsonInt: + result = newIntNode(nkIntLit, getInt(p)) + next(p) + return + raiseParseErr(p, "int expected") + of tyFloat..tyFloat128: + if p.kind == jsonFloat: + result = newFloatNode(nkFloatLit, getFloat(p)) + next(p) + return + raiseParseErr(p, "float expected") + of tyRange, tyGenericInst: result = loadAny(p, t.lastSon, tab) + else: + internalError "cannot marshal at compile-time " & t.typeToString + +proc loadAny*(s: string; t: PType): PNode = + var tab = initTable[BiggestInt, PNode]() + var p: JsonParser + open(p, newStringStream(s), "unknown file") + next(p) + result = loadAny(p, t, tab) + close(p) |