From 4301744e49f4b3758cc7a777c2d78c827bfbb344 Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 18 Mar 2018 11:04:53 +0100 Subject: raise the max instruction count for the VM to one billion --- compiler/vmdef.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'compiler/vmdef.nim') diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 5395d4bad..dd4bc5060 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -16,7 +16,7 @@ const byteExcess* = 128 # we use excess-K for immediates wordExcess* = 32768 - MaxLoopIterations* = 1500_000 # max iterations of all loops + MaxLoopIterations* = 1_000_000_000 # max iterations of all loops type -- cgit 1.4.1-2-gfad0 From 6baca58693672f8fc9485272b3c350d0b0b77163 Mon Sep 17 00:00:00 2001 From: Arne Döring Date: Wed, 11 Apr 2018 16:48:01 +0200 Subject: Get symbol kind (#7491) --- changelog.md | 2 + compiler/ast.nim | 5 +- compiler/condsyms.nim | 1 + compiler/guards.nim | 6 +- compiler/vm.nim | 35 ++++---- compiler/vmdef.nim | 2 +- compiler/vmgen.nim | 2 +- doc/astspec.txt | 178 +++++++++++++++++++-------------------- lib/core/macros.nim | 162 +++++++++++++++++++++-------------- lib/pure/htmlgen.nim | 6 +- tests/macros/tgensym.nim | 2 + tests/parser/tpostexprblocks.nim | 178 +++++++++++++++++++-------------------- tests/vm/tnimnode.nim | 12 +-- 13 files changed, 319 insertions(+), 272 deletions(-) (limited to 'compiler/vmdef.nim') diff --git a/changelog.md b/changelog.md index 3bf9b8cb8..d3ac27d6d 100644 --- a/changelog.md +++ b/changelog.md @@ -26,6 +26,8 @@ - ``macros.astGenRepr``, ``macros.lispRepr`` and ``macros.treeRepr`` now escapes the content of string literals consistently. +- ``macros.NimSym`` and ``macros.NimIdent`` is now deprecated in favor + of the more general ``NimNode``. ### Language additions diff --git a/compiler/ast.nim b/compiler/ast.nim index 55032234f..8fbce84f0 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -632,10 +632,11 @@ type mCpuEndian, mHostOS, mHostCPU, mBuildOS, mBuildCPU, mAppType, mNaN, mInf, mNegInf, mCompileOption, mCompileOptionArg, - mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind, + mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, + mNKind, mNSymKind mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal, mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo, - mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr, + mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mNBindSym, mLocals, mNCallSite, mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNHint, mNWarning, mNError, diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 0be2899be..85ebdd7bf 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -113,3 +113,4 @@ proc initDefines*() = defineSymbol("nimHasRunnableExamples") defineSymbol("nimNewDot") defineSymbol("nimHasNilChecks") + defineSymbol("nimSymKind") diff --git a/compiler/guards.nim b/compiler/guards.nim index a5e6058c9..94af5202d 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -768,8 +768,10 @@ macro `=~`(x: PNode, pat: untyped): bool = var conds = newTree(nnkBracket) m(x, pat, conds) - when declared(macros.toNimIdent): - result = nestList(toNimIdent"and", conds) + when compiles(nestList(ident"and", conds)): + result = nestList(ident"and", conds) + #elif declared(macros.toNimIdent): + # result = nestList(toNimIdent"and", conds) else: result = nestList(!"and", conds) diff --git a/compiler/vm.nim b/compiler/vm.nim index 6ea6f1492..33c17eff4 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -892,7 +892,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = regs[ra].node = if a.sym.ast.isNil: newNode(nkNilLit) else: copyTree(a.sym.ast) else: - stackTrace(c, tos, pc, errFieldXNotFound, "symbol") + stackTrace(c, tos, pc, errGenerated, "node is not a symbol") of opcEcho: let rb = instr.regB if rb == 1: @@ -1233,6 +1233,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = decodeB(rkInt) regs[ra].intVal = ord(regs[rb].node.kind) c.comesFromHeuristic = regs[rb].node.info + of opcNSymKind: + decodeB(rkInt) + let a = regs[rb].node + if a.kind == nkSym: + regs[ra].intVal = ord(a.sym.kind) + else: + stackTrace(c, tos, pc, errGenerated, "node is not a symbol") + c.comesFromHeuristic = regs[rb].node.info of opcNIntVal: decodeB(rkInt) let a = regs[rb].node @@ -1295,9 +1303,17 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = decodeB(rkNode) createStr regs[ra] let a = regs[rb].node - if a.kind in {nkStrLit..nkTripleStrLit}: regs[ra].node.strVal = a.strVal - elif a.kind == nkCommentStmt: regs[ra].node.strVal = a.comment - else: stackTrace(c, tos, pc, errFieldXNotFound, "strVal") + case a.kind + of {nkStrLit..nkTripleStrLit}: + regs[ra].node.strVal = a.strVal + of nkCommentStmt: + regs[ra].node.strVal = a.comment + of nkIdent: + regs[ra].node.strVal = a.ident.s + of nkSym: + regs[ra].node.strVal = a.sym.name.s + else: + stackTrace(c, tos, pc, errFieldXNotFound, "strVal") of opcSlurp: decodeB(rkNode) createStr regs[ra] @@ -1387,17 +1403,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = else: regs[ra].node = newNodeI(nkIdent, c.debug[pc]) regs[ra].node.ident = getIdent(regs[rb].node.strVal) - of opcIdentToStr: - decodeB(rkNode) - let a = regs[rb].node - createStr regs[ra] - regs[ra].node.info = c.debug[pc] - if a.kind == nkSym: - regs[ra].node.strVal = a.sym.name.s - elif a.kind == nkIdent: - regs[ra].node.strVal = a.ident.s - else: - stackTrace(c, tos, pc, errFieldXNotFound, "ident") of opcSetType: if regs[ra].kind != rkNode: internalError(c.debug[pc], "cannot set type") diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index dd4bc5060..66bc8dfd2 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -79,6 +79,7 @@ type opcNAdd, opcNAddMultiple, opcNKind, + opcNSymKind, opcNIntVal, opcNFloatVal, opcNSymbol, @@ -101,7 +102,6 @@ type opcNGetLine, opcNGetColumn, opcNGetFile, opcEqIdent, opcStrToIdent, - opcIdentToStr, opcGetImpl, opcEcho, diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index b8f1ef711..a661f59eb 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1080,6 +1080,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mNAdd: genBinaryABC(c, n, dest, opcNAdd) of mNAddMultiple: genBinaryABC(c, n, dest, opcNAddMultiple) of mNKind: genUnaryABC(c, n, dest, opcNKind) + of mNSymKind: genUnaryABC(c, n, dest, opcNSymKind) of mNIntVal: genUnaryABC(c, n, dest, opcNIntVal) of mNFloatVal: genUnaryABC(c, n, dest, opcNFloatVal) of mNSymbol: genUnaryABC(c, n, dest, opcNSymbol) @@ -1125,7 +1126,6 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = else: localError(n.info, "invalid bindSym usage") of mStrToIdent: genUnaryABC(c, n, dest, opcStrToIdent) - of mIdentToStr: genUnaryABC(c, n, dest, opcIdentToStr) of mEqIdent: genBinaryABC(c, n, dest, opcEqIdent) of mEqNimrodNode: genBinaryABC(c, n, dest, opcEqNimrodNode) of mSameNodeType: genBinaryABC(c, n, dest, opcSameNodeType) diff --git a/doc/astspec.txt b/doc/astspec.txt index 6d755c2e2..73058cd93 100644 --- a/doc/astspec.txt +++ b/doc/astspec.txt @@ -28,12 +28,8 @@ contains: intVal: BiggestInt ## the int literal of nnkFloatLit..nnkFloat64Lit: floatVal: BiggestFloat ## the float literal - of nnkStrLit..nnkTripleStrLit: + of nnkStrLit..nnkTripleStrLit, nnkCommentStmt, nnkIdent, nnkSym: strVal: string ## the string literal - of nnkIdent: - ident: NimIdent ## the identifier - of nnkSym: - symbol: NimSym ## the symbol (after symbol lookup phase) else: sons: seq[NimNode] ## the node's sons (or children) @@ -74,8 +70,8 @@ Nim expression Corresponding AST ``"""abc"""`` ``nnkTripleStrLit(strVal = "abc")`` ``' '`` ``nnkCharLit(intVal = 32)`` ``nil`` ``nnkNilLit()`` -``myIdentifier`` ``nnkIdent(ident = !"myIdentifier")`` -``myIdentifier`` after lookup pass: ``nnkSym(symbol = ...)`` +``myIdentifier`` ``nnkIdent(strVal = "myIdentifier")`` +``myIdentifier`` after lookup pass: ``nnkSym(strVal = "myIdentifier", ...)`` ----------------- --------------------------------------------- Identifiers are ``nnkIdent`` nodes. After the name lookup pass these nodes @@ -97,7 +93,7 @@ AST: .. code-block:: nim nnkCommand( - nnkIdent(!"echo"), + nnkIdent("echo"), nnkStrLit("abc"), nnkStrLit("xyz") ) @@ -115,7 +111,7 @@ AST: .. code-block:: nim nnkCall( - nnkIdent(!"echo"), + nnkIdent("echo"), nnkStrLit("abc"), nnkStrLit("xyz") ) @@ -133,7 +129,7 @@ AST: .. code-block:: nim nnkInfix( - nnkIdent(!"&"), + nnkIdent("&"), nnkStrLit("abc"), nnkStrLit("xyz") ) @@ -150,10 +146,10 @@ AST: .. code-block:: nim nnkInfix( - nnkIdent(!"+"), + nnkIdent("+"), nnkIntLit(5), nnkInfix( - nnkIdent(!"*"), + nnkIdent("*"), nnkIntLit(3), nnkIntLit(4) ) @@ -174,7 +170,7 @@ AST: .. code-block:: nim nnkCall( nnkAccQuoted( - nnkIdent(!"+") + nnkIdent("+") ), nnkIntLit(3), nnkIntLit(4) @@ -192,7 +188,7 @@ AST: .. code-block:: nim nnkPrefix( - nnkIdent(!"?"), + nnkIdent("?"), nnkStrLit("abc") ) @@ -212,8 +208,8 @@ AST: .. code-block:: nim nnkPostfix( - nnkIdent(!"*"), - nnkIdent(!"identifier") + nnkIdent("*"), + nnkIdent("identifier") ) @@ -229,10 +225,10 @@ AST: .. code-block:: nim nnkCall( - nnkIdent(!"writeLine"), + nnkIdent("writeLine"), nnkExprEqExpr( - nnkIdent(!"file"), - nnkIdent(!"stdout") + nnkIdent("file"), + nnkIdent("stdout") ), nnkStrLit("hallo") ) @@ -253,7 +249,7 @@ AST: .. code-block:: nim nnkCallStrLit( - nnkIdent(!"echo"), + nnkIdent("echo"), nnkRStrLit("hello") ) @@ -268,7 +264,7 @@ Concrete syntax: AST: .. code-block:: nim - nnkDerefExpr(nnkIdent(!"x")) + nnkDerefExpr(nnkIdent("x")) Addr operator @@ -282,7 +278,7 @@ Concrete syntax: AST: .. code-block:: nim - nnkAddr(nnkIdent(!"x")) + nnkAddr(nnkIdent("x")) Cast operator @@ -296,7 +292,7 @@ Concrete syntax: AST: .. code-block:: nim - nnkCast(nnkIdent(!"T"), nnkIdent(!"x")) + nnkCast(nnkIdent("T"), nnkIdent("x")) Object access operator ``.`` @@ -310,7 +306,7 @@ Concrete syntax: AST: .. code-block:: nim - nnkDotExpr(nnkIdent(!"x"), nnkIdent(!"y")) + nnkDotExpr(nnkIdent("x"), nnkIdent("y")) If you use Nim's flexible calling syntax (as in ``x.len()``), the result is the same as above but wrapped in an ``nnkCall``. @@ -327,7 +323,7 @@ Concrete syntax: AST: .. code-block:: nim - nnkBracketExpr(nnkIdent(!"x"), nnkIdent(!"y")) + nnkBracketExpr(nnkIdent("x"), nnkIdent("y")) Parentheses @@ -373,8 +369,8 @@ AST: .. code-block:: nim nnkTableConstr( - nnkExprColonExpr(nnkIdent(!"a"), nnkIntLit(3)), - nnkExprColonExpr(nnkIdent(!"b"), nnkIntLit(5)) + nnkExprColonExpr(nnkIdent("a"), nnkIntLit(3)), + nnkExprColonExpr(nnkIdent("b"), nnkIntLit(5)) ) @@ -410,7 +406,7 @@ AST: .. code-block:: nim nnkInfix( - nnkIdent(!".."), + nnkIdent(".."), nnkIntLit(1), nnkIntLit(3) ) @@ -461,7 +457,7 @@ Documentation Comments ---------------------- Double-hash (``##``) comments in the code actually have their own format, -using ``strVal`` to get and set the comment text. Single-hash (``#``) +using ``strVal`` to get and set the comment text. Single-hash (``#``) comments are ignored. Concrete syntax: @@ -497,7 +493,7 @@ AST: .. code-block:: nim nnkPragma( nnkExprColonExpr( - nnkIdent(!"emit"), + nnkIdent("emit"), nnkStrLit("#include ") # the "argument" ) ) @@ -515,10 +511,10 @@ AST: .. code-block:: nim nnkPragma( nnkExprColonExpr( - nnkIdent(!"pragma"), # this is always first when declaring a new pragma - nnkIdent(!"cdeclRename") # the name of the pragma + nnkIdent("pragma"), # this is always first when declaring a new pragma + nnkIdent("cdeclRename") # the name of the pragma ), - nnkIdent(!"cdecl") + nnkIdent("cdecl") ) Statements @@ -570,7 +566,7 @@ Concrete syntax: AST: .. code-block:: nim - nnkAsgn(nnkIdent(!"x"), nnkIntLit(42)) + nnkAsgn(nnkIdent("x"), nnkIntLit(42)) This is not the syntax for assignment when combined with ``var``, ``let``, or ``const``. @@ -736,7 +732,7 @@ Concrete syntax: AST: .. code-block:: nim - nnkBreakStmt(nnkIdent(!"otherLocation")) + nnkBreakStmt(nnkIdent("otherLocation")) If ``break`` is used without a jump-to location, ``nnkEmpty`` replaces ``nnkIdent``. @@ -751,7 +747,7 @@ Concrete syntax: AST: .. code-block:: nim - nnkBlockStmt(nnkIdent(!"name"), nnkStmtList(...)) + nnkBlockStmt(nnkIdent("name"), nnkStmtList(...)) A ``block`` doesn't need an name, in which case ``nnkEmpty`` is used. @@ -787,7 +783,7 @@ Concrete syntax: AST: .. code-block:: nim - nnkImportStmt(nnkIdent(!"math")) + nnkImportStmt(nnkIdent("math")) With ``except``, we get ``nnkImportExceptStmt``. @@ -799,7 +795,7 @@ Concrete syntax: AST: .. code-block:: nim - nnkImportExceptStmt(nnkIdent(!"math"),nnkIdent(!"pow")) + nnkImportExceptStmt(nnkIdent("math"),nnkIdent("pow")) Note that ``import math as m`` does not use a different node; rather, we use ``nnkImportStmt`` with ``as`` as an infix operator. @@ -814,9 +810,9 @@ AST: .. code-block:: nim nnkImportStmt( nnkInfix( - nnkIdent(!"as"), - nnkIdent(!"strutils"), - nnkIdent(!"su") + nnkIdent("as"), + nnkIdent("strutils"), + nnkIdent("su") ) ) @@ -833,7 +829,7 @@ Concrete syntax: AST: .. code-block:: nim - nnkFromStmt(nnkIdent(!"math"), nnkIdent(!"pow")) + nnkFromStmt(nnkIdent("math"), nnkIdent("pow")) Using ``from math as m import pow`` works identically to the ``as`` modifier with the ``import`` statement, but wrapped in ``nnkFromStmt``. @@ -852,7 +848,7 @@ Concrete syntax: AST: .. code-block:: nim - nnkExportStmt(nnkIdent(!"unsigned")) + nnkExportStmt(nnkIdent("unsigned")) Similar to the ``import`` statement, the AST is different for ``export ... except``. @@ -865,7 +861,7 @@ Concrete syntax: AST: .. code-block:: nim - nnkExportExceptStmt(nnkIdent(!"math"),nnkIdent(!"pow")) + nnkExportExceptStmt(nnkIdent("math"),nnkIdent("pow")) Include statement ----------------- @@ -880,7 +876,7 @@ Concrete syntax: AST: .. code-block:: nim - nnkIncludeStmt(nnkIdent(!"blocks")) + nnkIncludeStmt(nnkIdent("blocks")) Var section ----------- @@ -895,7 +891,7 @@ AST: .. code-block:: nim nnkVarSection( nnkIdentDefs( - nnkIdent(!"a"), + nnkIdent("a"), nnkEmpty(), # or nnkIdent(...) if the variable declares the type nnkIntLit(3), ) @@ -925,7 +921,7 @@ AST: .. code-block:: nim nnkLetSection( nnkIdentDefs( - nnkIdent(!"a"), + nnkIdent("a"), nnkEmpty(), # or nnkIdent(...) for the type nnkIntLit(3), ) @@ -944,7 +940,7 @@ AST: .. code-block:: nim nnkConstSection( nnkConstDef( # not nnkConstDefs! - nnkIdent(!"a"), + nnkIdent("a"), nnkEmpty(), # or nnkIdent(...) if the variable declares the type nnkIntLit(3), # required in a const declaration! ) @@ -966,9 +962,9 @@ AST: .. code-block:: nim nnkTypeSection( nnkTypeDef( - nnkIdent(!"A"), + nnkIdent("A"), nnkEmpty(), - nnkIdent(!"int") + nnkIdent("int") ) ) @@ -985,10 +981,10 @@ AST: .. code-block:: nim # ... nnkTypeDef( - nnkIdent(!"MyInt"), + nnkIdent("MyInt"), nnkEmpty(), nnkDistinctTy( - nnkIdent(!"int") + nnkIdent("int") ) ) @@ -1004,10 +1000,10 @@ AST: .. code-block:: nim nnkTypeSection( nnkTypeDef( - nnkIdent(!"A"), + nnkIdent("A"), nnkGenericParams( nnkIdentDefs( - nnkIdent(!"T"), + nnkIdent("T"), nnkEmpty(), # if the type is declared with options, like # ``[T: SomeInteger]``, they are given here nnkEmpty(), @@ -1031,12 +1027,12 @@ AST: .. code-block:: nim # ... nnkTypeDef( - nnkIdent(!"IO"), + nnkIdent("IO"), nnkEmpty(), nnkObjectTy( nnkEmpty(), # no pragmas here nnkOfInherit( - nnkIdent(!"RootObj") # inherits from RootObj + nnkIdent("RootObj") # inherits from RootObj ) nnkEmpty() ) @@ -1062,43 +1058,43 @@ AST: # ... nnkObjectTy( nnkPragma( - nnkIdent(!"inheritable") + nnkIdent("inheritable") ), nnkEmpty(), nnkRecList( # list of object parameters nnkIdentDefs( - nnkIdent(!"name"), - nnkIdent(!"string"), + nnkIdent("name"), + nnkIdent("string"), nnkEmpty() ), nnkRecCase( # case statement within object (not nnkCaseStmt) nnkIdentDefs( - nnkIdent(!"isFat"), - nnkIdent(!"bool"), + nnkIdent("isFat"), + nnkIdent("bool"), nnkEmpty() ), nnkOfBranch( - nnkIdent(!"true"), + nnkIdent("true"), nnkRecList( # again, a list of object parameters nnkIdentDefs( - nnkIdent(!"m"), + nnkIdent("m"), nnkBracketExpr( - nnkIdent(!"array"), + nnkIdent("array"), nnkIntLit(100000), - nnkIdent(!"T") + nnkIdent("T") ), nnkEmpty() ) ), nnkOfBranch( - nnkIdent(!"false"), + nnkIdent("false"), nnkRecList( nnkIdentDefs( - nnkIdent(!"m"), + nnkIdent("m"), nnkBracketExpr( - nnkIdent(!"array"), + nnkIdent("array"), nnkIntLit(10), - nnkIdent(!"T") + nnkIdent("T") ), nnkEmpty() ) @@ -1123,7 +1119,7 @@ AST: # ... nnkEnumTy( nnkEmpty(), - nnkIdent(!"First") # you need at least one nnkIdent or the compiler complains + nnkIdent("First") # you need at least one nnkIdent or the compiler complains ) The usage of ``concept`` (experimental) is similar to objects. @@ -1158,9 +1154,9 @@ AST: .. code-block:: nim # ... within nnkGenericParams nnkIdentDefs( - nnkIdent(!"T"), + nnkIdent("T"), nnkStaticTy( - nnkIdent(!"int") + nnkIdent("int") ), nnkEmpty() ) @@ -1180,7 +1176,7 @@ Nim type Corresponding AST ``distinct`` ``nnkDistinctTy`` ``enum`` ``nnkEnumTy`` ``concept`` ``nnkTypeClassTy``\* -``array`` ``nnkBracketExpr(nnkIdent(!"array"),...``\* +``array`` ``nnkBracketExpr(nnkIdent("array"),...``\* ``proc`` ``nnkProcTy`` ``iterator`` ``nnkIteratorTy`` ``object`` ``nnkObjectTy`` @@ -1200,7 +1196,7 @@ AST: .. code-block:: nim # ... nnkTypeDef( - nnkIdent(!"MyProc"), + nnkIdent("MyProc"), nnkGenericParams( # here, not with the proc # ... ) @@ -1225,7 +1221,7 @@ Concrete syntax: AST: .. code-block:: nim - nnkMixinStmt(nnkIdent(!"x")) + nnkMixinStmt(nnkIdent("x")) Bind statement -------------- @@ -1238,7 +1234,7 @@ Concrete syntax: AST: .. code-block:: nim - nnkBindStmt(nnkIdent(!"x")) + nnkBindStmt(nnkIdent("x")) Procedure declaration --------------------- @@ -1255,26 +1251,26 @@ AST: .. code-block:: nim nnkProcDef( - nnkPostfix(nnkIdent(!"*"), nnkIdent(!"hello")), # the exported proc name + nnkPostfix(nnkIdent("*"), nnkIdent("hello")), # the exported proc name nnkEmpty(), # patterns for term rewriting in templates and macros (not procs) nnkGenericParams( # generic type parameters, like with type declaration nnkIdentDefs( - nnkIdent(!"T"), nnkIdent(!"SomeInteger") + nnkIdent("T"), nnkIdent("SomeInteger") ) ), nnkFormalParams( - nnkIdent(!"int"), # the first FormalParam is the return type. nnkEmpty() if there is none + nnkIdent("int"), # the first FormalParam is the return type. nnkEmpty() if there is none nnkIdentDefs( - nnkIdent(!"x"), - nnkIdent(!"int"), # type type (required for procs, not for templates) + nnkIdent("x"), + nnkIdent("int"), # type type (required for procs, not for templates) nnkIntLit(3) # a default value ), nnkIdentDefs( - nnkIdent(!"y"), - nnkIdent(!"float32"), + nnkIdent("y"), + nnkIdent("float32"), nnkEmpty() ) - nnkPragma(nnkIdent(!"inline")), + nnkPragma(nnkIdent("inline")), nnkEmpty(), # reserved slot for future use nnkStmtList(nnkDiscardStmt(nnkEmpty())) # the meat of the proc ) @@ -1296,9 +1292,9 @@ AST: nnkFormalParams( nnkEmpty(), # no return here nnkIdentDefs( - nnkIdent(!"a"), # the first parameter - nnkIdent(!"b"), # directly to the second parameter - nnkIdent(!"int"), # their shared type identifier + nnkIdent("a"), # the first parameter + nnkIdent("b"), # directly to the second parameter + nnkIdent("int"), # their shared type identifier nnkEmpty(), # default value would go here ) ), @@ -1318,7 +1314,7 @@ AST: # ... nnkFormalParams( nnkVarTy( - nnkIdent(!"int") + nnkIdent("int") ) ) @@ -1337,7 +1333,7 @@ AST: .. code-block:: nim nnkIteratorDef( - nnkIdent(!"nonsense"), + nnkIdent("nonsense"), nnkEmpty(), ... ) @@ -1356,7 +1352,7 @@ AST: .. code-block:: nim nnkConverterDef( - nnkIdent(!"toBool"), + nnkIdent("toBool"), # ... ) @@ -1378,7 +1374,7 @@ AST: .. code-block:: nim nnkTemplateDef( - nnkIdent(!"optOpt"), + nnkIdent("optOpt"), nnkStmtList( # instead of nnkEmpty() expr1 ), diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 5a4c4c1e9..9edaab237 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -118,7 +118,7 @@ type ## use ``ident"abc"``. NimSymObj = object # hidden - NimSym* = ref NimSymObj + NimSym* {.deprecated.} = ref NimSymObj ## represents a Nim *symbol* in the compiler; a *symbol* is a looked-up ## *ident*. @@ -134,25 +134,23 @@ const proc `!`*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect, deprecated.} ## constructs an identifier from the string `s` - ## **Deprecated since version 0.18.0**: Use ``toNimIdent`` instead. + ## **Deprecated since version 0.18.0**: Use ``ident`` or ``newIdentNode`` instead. -proc toNimIdent*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect.} +proc toNimIdent*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect, deprecated.} ## constructs an identifier from the string `s` + ## **Deprecated since version 0.18.1**; Use ``ident`` or ``newIdentNode`` instead. -proc `$`*(i: NimIdent): string {.magic: "IdentToStr", noSideEffect.} - ## converts a Nim identifier to a string - -proc `$`*(s: NimSym): string {.magic: "IdentToStr", noSideEffect.} - ## converts a Nim symbol to a string - -proc `==`*(a, b: NimIdent): bool {.magic: "EqIdent", noSideEffect.} +proc `==`*(a, b: NimIdent): bool {.magic: "EqIdent", noSideEffect, deprecated.} ## compares two Nim identifiers + ## **Deprecated since version 0.18.1**; Use ``==`` on ``NimNode`` instead. proc `==`*(a, b: NimNode): bool {.magic: "EqNimrodNode", noSideEffect.} ## compares two Nim nodes -proc `==`*(a, b: NimSym): bool {.magic: "EqNimrodNode", noSideEffect.} +proc `==`*(a, b: NimSym): bool {.magic: "EqNimrodNode", noSideEffect, deprecated.} ## compares two Nim symbols + ## **Deprecated since version 0.18.1**; Use ```==`(NimNode,NimNode)`` instead. + proc sameType*(a, b: NimNode): bool {.magic: "SameNodeType", noSideEffect.} = ## compares two Nim nodes' types. Return true if the types are the same, @@ -195,8 +193,47 @@ proc kind*(n: NimNode): NimNodeKind {.magic: "NKind", noSideEffect.} proc intVal*(n: NimNode): BiggestInt {.magic: "NIntVal", noSideEffect.} proc floatVal*(n: NimNode): BiggestFloat {.magic: "NFloatVal", noSideEffect.} -proc symbol*(n: NimNode): NimSym {.magic: "NSymbol", noSideEffect.} -proc ident*(n: NimNode): NimIdent {.magic: "NIdent", noSideEffect.} + +proc ident*(n: NimNode): NimIdent {.magic: "NIdent", noSideEffect, deprecated.} = + ## **Deprecated since version 0.18.1**; All functionality is defined on ``NimNode``. + +proc symbol*(n: NimNode): NimSym {.magic: "NSymbol", noSideEffect, deprecated.} + ## **Deprecated since version 0.18.1**; All functionality is defined on ``NimNode``. + +proc getImpl*(s: NimSym): NimNode {.magic: "GetImpl", noSideEffect, deprecated: "use `getImpl: NimNode -> NimNode` instead".} + +when defined(nimSymKind): + proc symKind*(symbol: NimNode): NimSymKind {.magic: "NSymKind", noSideEffect.} + proc getImpl*(symbol: NimNode): NimNode {.magic: "GetImpl", noSideEffect.} + proc strVal*(n: NimNode): string {.magic: "NStrVal", noSideEffect.} + ## retrieve the implementation of `symbol`. `symbol` can be a + ## routine or a const. + + proc `$`*(i: NimIdent): string {.magic: "NStrVal", noSideEffect, deprecated.} + ## converts a Nim identifier to a string + ## **Deprecated since version 0.18.1**; Use ``strVal`` instead. + + proc `$`*(s: NimSym): string {.magic: "NStrVal", noSideEffect, deprecated.} + ## converts a Nim symbol to a string + ## **Deprecated since version 0.18.1**; Use ``strVal`` instead. + +else: # bootstrapping substitute + proc getImpl*(symbol: NimNode): NimNode = + symbol.symbol.getImpl + + proc strValOld(n: NimNode): string {.magic: "NStrVal", noSideEffect.} + + proc `$`*(s: NimSym): string {.magic: "IdentToStr", noSideEffect.} + + proc `$`*(i: NimIdent): string {.magic: "IdentToStr", noSideEffect.} + + proc strVal*(n: NimNode): string = + if n.kind == nnkIdent: + $n.ident + elif n.kind == nnkSym: + $n.symbol + else: + n.strValOld proc getType*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.} ## with 'getType' you can access the node's `type`:idx:. A Nim type is @@ -228,12 +265,15 @@ proc getTypeImpl*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.} proc getTypeImpl*(n: typedesc): NimNode {.magic: "NGetType", noSideEffect.} ## Like getType except it includes generic parameters for the implementation -proc strVal*(n: NimNode): string {.magic: "NStrVal", noSideEffect.} - proc `intVal=`*(n: NimNode, val: BiggestInt) {.magic: "NSetIntVal", noSideEffect.} proc `floatVal=`*(n: NimNode, val: BiggestFloat) {.magic: "NSetFloatVal", noSideEffect.} -proc `symbol=`*(n: NimNode, val: NimSym) {.magic: "NSetSymbol", noSideEffect.} -proc `ident=`*(n: NimNode, val: NimIdent) {.magic: "NSetIdent", noSideEffect.} + +proc `symbol=`*(n: NimNode, val: NimSym) {.magic: "NSetSymbol", noSideEffect, deprecated.} + ## **Deprecated since version 0.18.1**; Generate a new ``NimNode`` with ``genSym`` instead. + +proc `ident=`*(n: NimNode, val: NimIdent) {.magic: "NSetIdent", noSideEffect, deprecated.} + ## **Deprecated since version 0.18.1**; Generate a new ``NimNode`` with ``ident(string)`` instead. + #proc `typ=`*(n: NimNode, typ: typedesc) {.magic: "NSetType".} # this is not sound! Unfortunately forbidding 'typ=' is not enough, as you # can easily do: @@ -255,11 +295,6 @@ proc newNimNode*(kind: NimNodeKind, proc copyNimNode*(n: NimNode): NimNode {.magic: "NCopyNimNode", noSideEffect.} proc copyNimTree*(n: NimNode): NimNode {.magic: "NCopyNimTree", noSideEffect.} -proc getImpl*(s: NimSym): NimNode {.magic: "GetImpl", noSideEffect.} = - ## retrieve the implementation of a symbol `s`. `s` can be a routine or a - ## const. - discard - proc error*(msg: string, n: NimNode = nil) {.magic: "NError", benign.} ## writes an error message at compile time @@ -294,11 +329,9 @@ proc newIdentNode*(i: NimIdent): NimNode {.compileTime.} = result = newNimNode(nnkIdent) result.ident = i -proc newIdentNode*(i: string): NimNode {.compileTime.} = - ## creates an identifier node from `i` - result = newNimNode(nnkIdent) - result.ident = toNimIdent i - +proc newIdentNode*(i: string): NimNode {.magic: "StrToIdent", noSideEffect.} + ## creates an identifier node from `i`. It is simply an alias for + ## ``ident(string)``. Use that, it's shorter. type BindSymRule* = enum ## specifies how ``bindSym`` behaves @@ -464,9 +497,11 @@ proc newCall*(theProc: NimNode, result.add(args) proc newCall*(theProc: NimIdent, - args: varargs[NimNode]): NimNode {.compileTime.} = + args: varargs[NimNode]): NimNode {.compileTime, deprecated.} = ## produces a new call node. `theProc` is the proc that is called with ## the arguments ``args[0..]``. + ## **Deprecated since version 0.18.1**; Use ``newCall(string, ...)``, + ## or ``newCall(NimNode, ...)`` instead. result = newNimNode(nnkCall) result.add(newIdentNode(theProc)) result.add(args) @@ -594,17 +629,30 @@ proc newLit*(s: string): NimNode {.compileTime.} = result = newNimNode(nnkStrLit) result.strVal = s -proc nestList*(theProc: NimIdent, - x: NimNode): NimNode {.compileTime.} = - ## nests the list `x` into a tree of call expressions: - ## ``[a, b, c]`` is transformed into ``theProc(a, theProc(c, d))``. +proc nestList*(op: NimNode; pack: NimNode): NimNode {.compileTime.} = + ## nests the list `pack` into a tree of call expressions: + ## ``[a, b, c]`` is transformed into ``op(a, op(c, d))``. + ## This is also known as fold expression. + if pack.len < 1: + error("`nestList` expects a node with at least 1 child") + result = pack[^1] + for i in countdown(pack.len - 2, 0): + result = newCall(op, pack[i], result) + +proc nestList*(op: NimNode; pack: NimNode; init: NimNode): NimNode {.compileTime.} = + ## nests the list `pack` into a tree of call expressions: + ## ``[a, b, c]`` is transformed into ``op(a, op(c, d))``. + ## This is also known as fold expression. + result = init + for i in countdown(pack.len - 1, 0): + result = newCall(op, pack[i], result) + +proc nestList*(theProc: NimIdent, x: NimNode): NimNode {.compileTime, deprecated.} = + ## **Deprecated since version 0.18.1**; Use one of ``nestList(NimNode, ...)`` instead. var L = x.len result = newCall(theProc, x[L-2], x[L-1]) for i in countdown(L-3, 0): - # XXX the 'copyNimTree' here is necessary due to a bug in the evaluation - # engine that would otherwise create an endless loop here. :-( - # This could easily user code and so should be fixed in evals.nim somehow. - result = newCall(theProc, x[i], copyNimTree(result)) + result = newCall(theProc, x[i], result) proc treeRepr*(n: NimNode): string {.compileTime, benign.} = ## Convert the AST `n` to a human-readable tree-like string. @@ -620,9 +668,8 @@ proc treeRepr*(n: NimNode): string {.compileTime, benign.} = of nnkNilLit: res.add(" nil") of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal) of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal) - of nnkStrLit..nnkTripleStrLit: res.add(" " & $n.strVal.newLit.repr) - of nnkIdent: res.add(" ident\"" & $n.ident & '"') - of nnkSym: res.add(" \"" & $n.symbol & '"') + of nnkStrLit..nnkTripleStrLit, nnkIdent, nnkSym: + res.add(" " & $n.strVal.newLit.repr) of nnkNone: assert false else: for j in 0..n.len-1: @@ -645,9 +692,8 @@ proc lispRepr*(n: NimNode): string {.compileTime, benign.} = of nnkNilLit: add(result, "nil") of nnkCharLit..nnkInt64Lit: add(result, $n.intVal) of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal) - of nnkStrLit..nnkTripleStrLit, nnkCommentStmt: add(result, n.strVal.newLit.repr) - of nnkIdent: add(result, "ident\"" & $n.ident & '"') - of nnkSym: add(result, $n.symbol) + of nnkStrLit..nnkTripleStrLit, nnkCommentStmt, nnkident, nnkSym: + add(result, n.strVal.newLit.repr) of nnkNone: assert false else: if n.len > 0: @@ -696,9 +742,8 @@ proc astGenRepr*(n: NimNode): string {.compileTime, benign.} = of nnkCharLit: res.add("'" & $chr(n.intVal) & "'") of nnkIntLit..nnkInt64Lit: res.add($n.intVal) of nnkFloatLit..nnkFloat64Lit: res.add($n.floatVal) - of nnkStrLit..nnkTripleStrLit, nnkCommentStmt: res.add($n.strVal.newLit.repr) - of nnkIdent: res.add(($n.ident).newLit.repr()) - of nnkSym: res.add(($n.symbol).newLit.repr()) + of nnkStrLit..nnkTripleStrLit, nnkCommentStmt, nnkIdent, nnkSym: + res.add(n.strVal.newLit.repr) of nnkNone: assert false else: res.add(".newTree(") @@ -742,10 +787,10 @@ macro dumpAstGen*(s: untyped): untyped = echo s.astGenRepr ## See `dumpTree`. macro dumpTreeImm*(s: untyped): untyped {.deprecated.} = echo s.treeRepr - ## Deprecated. + ## Deprecated. Use `dumpTree` instead. macro dumpLispImm*(s: untyped): untyped {.deprecated.} = echo s.lispRepr - ## Deprecated. + ## Deprecated. Use `dumpLisp` instead. proc newEmptyNode*(): NimNode {.compileTime, noSideEffect.} = ## Create a new empty node @@ -991,28 +1036,21 @@ proc `body=`*(someProc: NimNode, val: NimNode) {.compileTime.} = proc basename*(a: NimNode): NimNode {.compiletime, benign.} - proc `$`*(node: NimNode): string {.compileTime.} = ## Get the string of an identifier node case node.kind - of nnkIdent: - result = $node.ident of nnkPostfix: - result = $node.basename.ident & "*" - of nnkStrLit..nnkTripleStrLit: + result = node.basename.strVal & "*" + of nnkStrLit..nnkTripleStrLit, nnkCommentStmt, nnkSym, nnkIdent: result = node.strVal - of nnkSym: - result = $node.symbol of nnkOpenSymChoice, nnkClosedSymChoice: result = $node[0] of nnkAccQuoted: result = $node[0] - of nnkCommentStmt: - result = node.strVal else: badNodeKind node.kind, "$" -proc ident*(name: string): NimNode {.compileTime,inline.} = newIdentNode(name) +proc ident*(name: string): NimNode {.magic: "StrToIdent", noSideEffect.} ## Create a new ident node from a string iterator items*(n: NimNode): NimNode {.inline.} = @@ -1129,10 +1167,8 @@ proc eqIdent*(node: NimNode; s: string): bool {.compileTime.} = ## is the same as ``s``. Note that this is the preferred way to check! Most ## other ways like ``node.ident`` are much more error-prone, unfortunately. case node.kind - of nnkIdent: - result = node.ident == toNimIdent s - of nnkSym: - result = eqIdent($node.symbol, s) + of nnkSym, nnkIdent: + result = eqIdent(node.strVal, s) of nnkOpenSymChoice, nnkClosedSymChoice: result = eqIdent($node[0], s) else: @@ -1189,11 +1225,11 @@ macro expandMacros*(body: typed): untyped = proc customPragmaNode(n: NimNode): NimNode = expectKind(n, {nnkSym, nnkDotExpr}) if n.kind == nnkSym: - let sym = n.symbol.getImpl() + let sym = n.getImpl() sym.expectRoutine() result = sym.pragma elif n.kind == nnkDotExpr: - let typDef = getImpl(getTypeInst(n[0]).symbol) + let typDef = getImpl(getTypeInst(n[0])) typDef.expectKind(nnkTypeDef) typDef[2].expectKind(nnkObjectTy) let recList = typDef[2][2] diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim index c0934a45b..e7562029a 100644 --- a/lib/pure/htmlgen.nim +++ b/lib/pure/htmlgen.nim @@ -92,8 +92,10 @@ proc xmlCheckedTag*(e: NimNode, tag: string, optAttr = "", reqAttr = "", result.add(newStrLitNode("")) - result = nestList(!"&", result) - + when compiles(nestList(ident"&", result)): + result = nestList(ident"&", result) + else: + result = nestList(!"&", result) macro a*(e: varargs[untyped]): untyped = ## generates the HTML ``a`` element. diff --git a/tests/macros/tgensym.nim b/tests/macros/tgensym.nim index 955168939..1237b8bf7 100644 --- a/tests/macros/tgensym.nim +++ b/tests/macros/tgensym.nim @@ -28,6 +28,7 @@ macro async2(prc: untyped): untyped = # -> iterator nameIter(): FutureBase {.closure.} = # Changing this line to: newIdentNode($prc[0].ident & "Iter") # will make it work. var iteratorNameSym = genSym(nskIterator, $prc[0].ident & "Iter") + assert iteratorNameSym.symKind == nskIterator #var iteratorNameSym = newIdentNode($prc[0].ident & "Iter") var procBody = prc[6].convertReturns(retFutureSym) @@ -42,6 +43,7 @@ macro async2(prc: untyped): untyped = var varNameIter = newVarStmt(varNameIterSym, iteratorNameSym) outerProcBody.add varNameIter var varFirstSym = genSym(nskVar, "first") + assert varFirstSym.symKind == nskVar var varFirst = newVarStmt(varFirstSym, newCall(varNameIterSym)) outerProcBody.add varFirst diff --git a/tests/parser/tpostexprblocks.nim b/tests/parser/tpostexprblocks.nim index e97b9c7ee..c27bbf321 100644 --- a/tests/parser/tpostexprblocks.nim +++ b/tests/parser/tpostexprblocks.nim @@ -1,82 +1,82 @@ discard """ nimout: ''' StmtList - Ident ident"foo010" + Ident "foo010" Call - Ident ident"foo020" + Ident "foo020" Call - Ident ident"foo030" - Ident ident"x" + Ident "foo030" + Ident "x" Command - Ident ident"foo040" - Ident ident"x" + Ident "foo040" + Ident "x" Call - Ident ident"foo050" + Ident "foo050" StmtList DiscardStmt Empty Call - Ident ident"foo060" + Ident "foo060" StmtList DiscardStmt Empty Call - Ident ident"foo070" + Ident "foo070" StrLit "test" StmtList DiscardStmt Empty Call - Ident ident"foo080" + Ident "foo080" StrLit "test" StmtList DiscardStmt Empty Command - Ident ident"foo090" + Ident "foo090" StrLit "test" StmtList DiscardStmt Empty Command - Ident ident"foo100" + Ident "foo100" Call StrLit "test" StmtList DiscardStmt Empty Command - Ident ident"foo101" + Ident "foo101" Call IntLit 10 StmtList DiscardStmt Empty Command - Ident ident"foo110" + Ident "foo110" IntLit 1 Par Infix - Ident ident"+" + Ident "+" IntLit 2 IntLit 3 StmtList DiscardStmt Empty Command - Ident ident"foo120" + Ident "foo120" IntLit 1 Call Par Infix - Ident ident"+" + Ident "+" IntLit 2 IntLit 3 StmtList DiscardStmt Empty Call - Ident ident"foo130" + Ident "foo130" Do Empty Empty @@ -84,7 +84,7 @@ StmtList FormalParams Empty IdentDefs - Ident ident"x" + Ident "x" Empty Empty Empty @@ -93,7 +93,7 @@ StmtList DiscardStmt Empty Call - Ident ident"foo140" + Ident "foo140" Do Empty Empty @@ -101,8 +101,8 @@ StmtList FormalParams Empty IdentDefs - Ident ident"x" - Ident ident"int" + Ident "x" + Ident "int" Empty Empty Empty @@ -110,16 +110,16 @@ StmtList DiscardStmt Empty Call - Ident ident"foo150" + Ident "foo150" Do Empty Empty Empty FormalParams - Ident ident"int" + Ident "int" IdentDefs - Ident ident"x" - Ident ident"int" + Ident "x" + Ident "int" Empty Empty Empty @@ -127,9 +127,9 @@ StmtList DiscardStmt Empty Command - Ident ident"foo160" + Ident "foo160" Call - Ident ident"x" + Ident "x" Do Empty Empty @@ -137,7 +137,7 @@ StmtList FormalParams Empty IdentDefs - Ident ident"y" + Ident "y" Empty Empty Empty @@ -146,7 +146,7 @@ StmtList DiscardStmt Empty Call - Ident ident"foo170" + Ident "foo170" StmtList DiscardStmt Empty @@ -155,7 +155,7 @@ StmtList DiscardStmt Empty Call - Ident ident"foo180" + Ident "foo180" StmtList DiscardStmt Empty @@ -167,9 +167,9 @@ StmtList DiscardStmt Empty Command - Ident ident"foo190" + Ident "foo190" Call - Ident ident"x" + Ident "x" Do Empty Empty @@ -177,7 +177,7 @@ StmtList FormalParams Empty IdentDefs - Ident ident"y" + Ident "y" Empty Empty Empty @@ -190,9 +190,9 @@ StmtList Empty Empty FormalParams - Ident ident"int" + Ident "int" IdentDefs - Ident ident"z" + Ident "z" Empty Empty Empty @@ -205,10 +205,10 @@ StmtList Empty Empty FormalParams - Ident ident"int" + Ident "int" IdentDefs - Ident ident"w" - Ident ident"int" + Ident "w" + Ident "int" Empty Empty Empty @@ -223,10 +223,10 @@ StmtList DiscardStmt Empty Call - Ident ident"foo200" - Ident ident"x" + Ident "foo200" + Ident "x" Call - Ident ident"bar" + Ident "bar" StmtList DiscardStmt Empty @@ -236,53 +236,53 @@ StmtList Empty VarSection IdentDefs - Ident ident"a" + Ident "a" Empty - Ident ident"foo210" + Ident "foo210" VarSection IdentDefs - Ident ident"a" + Ident "a" Empty Call - Ident ident"foo220" + Ident "foo220" VarSection IdentDefs - Ident ident"a" + Ident "a" Empty Call - Ident ident"foo230" - Ident ident"x" + Ident "foo230" + Ident "x" VarSection IdentDefs - Ident ident"a" + Ident "a" Empty Command - Ident ident"foo240" - Ident ident"x" + Ident "foo240" + Ident "x" VarSection IdentDefs - Ident ident"a" + Ident "a" Empty Call - Ident ident"foo250" + Ident "foo250" StmtList DiscardStmt Empty VarSection IdentDefs - Ident ident"a" + Ident "a" Empty Call - Ident ident"foo260" + Ident "foo260" StmtList DiscardStmt Empty VarSection IdentDefs - Ident ident"a" + Ident "a" Empty Call - Ident ident"foo270" + Ident "foo270" StmtList DiscardStmt Empty @@ -292,12 +292,12 @@ StmtList Empty VarSection IdentDefs - Ident ident"a" + Ident "a" Empty Command - Ident ident"foo280" + Ident "foo280" Call - Ident ident"x" + Ident "x" Do Empty Empty @@ -305,7 +305,7 @@ StmtList FormalParams Empty IdentDefs - Ident ident"y" + Ident "y" Empty Empty Empty @@ -318,40 +318,40 @@ StmtList DiscardStmt Empty Asgn - Ident ident"a" - Ident ident"foo290" + Ident "a" + Ident "foo290" Asgn - Ident ident"a" + Ident "a" Call - Ident ident"foo300" + Ident "foo300" Asgn - Ident ident"a" + Ident "a" Call - Ident ident"foo310" - Ident ident"x" + Ident "foo310" + Ident "x" Asgn - Ident ident"a" + Ident "a" Command - Ident ident"foo320" - Ident ident"x" + Ident "foo320" + Ident "x" Asgn - Ident ident"a" + Ident "a" Call - Ident ident"foo330" + Ident "foo330" StmtList DiscardStmt Empty Asgn - Ident ident"a" + Ident "a" Call - Ident ident"foo340" + Ident "foo340" StmtList DiscardStmt Empty Asgn - Ident ident"a" + Ident "a" Call - Ident ident"foo350" + Ident "foo350" StmtList DiscardStmt Empty @@ -360,13 +360,13 @@ StmtList DiscardStmt Empty Asgn - Ident ident"a" + Ident "a" Command - Ident ident"foo360" + Ident "foo360" Call DotExpr - Ident ident"x" - Ident ident"bar" + Ident "x" + Ident "bar" Do Empty Empty @@ -374,7 +374,7 @@ StmtList FormalParams Empty IdentDefs - Ident ident"y" + Ident "y" Empty Empty Empty @@ -388,20 +388,20 @@ StmtList Empty Command DotExpr - Ident ident"foo370" - Ident ident"add" + Ident "foo370" + Ident "add" Call - Ident ident"quote" + Ident "quote" StmtList DiscardStmt Empty Call DotExpr - Ident ident"foo380" - Ident ident"add" + Ident "foo380" + Ident "add" BracketExpr Call - Ident ident"quote" + Ident "quote" StmtList DiscardStmt Empty diff --git a/tests/vm/tnimnode.nim b/tests/vm/tnimnode.nim index 2727df290..188bac9bf 100644 --- a/tests/vm/tnimnode.nim +++ b/tests/vm/tnimnode.nim @@ -26,12 +26,12 @@ proc checkNode(arg: NimNode; name: string): void {. compileTime .} = seqAppend.add(arg) # bit this creates a copy arg.add newCall(ident"echo", newLit("Hello World")) - assertEq arg.lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit("Hello World")))""" - assertEq node.lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit("Hello World")))""" - assertEq nodeArray[0].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit("Hello World")))""" - assertEq nodeSeq[0].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit("Hello World")))""" - assertEq seqAppend[0].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit("Hello World")))""" - assertEq seqAppend[1].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit("Hello World")))""" + assertEq arg.lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident("echo"), StrLit("Hello World")))""" + assertEq node.lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident("echo"), StrLit("Hello World")))""" + assertEq nodeArray[0].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident("echo"), StrLit("Hello World")))""" + assertEq nodeSeq[0].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident("echo"), StrLit("Hello World")))""" + assertEq seqAppend[0].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident("echo"), StrLit("Hello World")))""" + assertEq seqAppend[1].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident("echo"), StrLit("Hello World")))""" echo "OK" -- cgit 1.4.1-2-gfad0 From b7116a28eea13f4fd82b8b22323f2f75c813794f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 5 May 2018 18:47:29 +0200 Subject: compiler refactoring, pass config around explicitly --- compiler/docgen.nim | 6 +- compiler/lexer.nim | 35 +- compiler/main.nim | 13 +- compiler/modules.nim | 2 +- compiler/nimconf.nim | 2 +- compiler/options.nim | 1 + compiler/parser.nim | 16 +- compiler/passes.nim | 2 +- compiler/pbraces.nim | 1790 --------------------------------------------- compiler/reorder.nim | 8 +- compiler/scriptconfig.nim | 2 +- compiler/sem.nim | 6 +- compiler/semexprs.nim | 6 +- compiler/semstmts.nim | 5 +- compiler/syntaxes.nim | 29 +- compiler/vm.nim | 41 +- compiler/vmdef.nim | 8 +- 17 files changed, 93 insertions(+), 1879 deletions(-) delete mode 100644 compiler/pbraces.nim (limited to 'compiler/vmdef.nim') diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 6f3dcde8b..e1a70a23e 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -790,7 +790,7 @@ proc writeOutputJson*(d: PDoc, filename, outExt: string, discard "fixme: error report" proc commandDoc*() = - var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache()) + var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef()) if ast == nil: return var d = newDocumentor(gProjectFull, options.gConfigVars) d.hasToc = true @@ -840,7 +840,7 @@ proc commandRst2TeX*() = commandRstAux(gProjectFull, TexExt) proc commandJson*() = - var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache()) + var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef()) if ast == nil: return var d = newDocumentor(gProjectFull, options.gConfigVars) d.hasToc = true @@ -855,7 +855,7 @@ proc commandJson*() = writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false) proc commandTags*() = - var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache()) + var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef()) if ast == nil: return var d = newDocumentor(gProjectFull, options.gConfigVars) d.hasToc = true diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 0478ed574..0aeb44ca3 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -144,13 +144,12 @@ type cache*: IdentCache when defined(nimsuggest): previousToken: TLineInfo + config*: ConfigRef when defined(nimpretty): var gIndentationWidth*: int -var gLinesCompiled*: int # all lines that have been compiled - proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} = result = newLineInfo(L.fileIdx, tok.line, tok.col) when defined(nimpretty): @@ -222,7 +221,7 @@ proc fillToken(L: var TToken) = L.commentOffsetB = 0 proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream; - cache: IdentCache) = + cache: IdentCache; config: ConfigRef) = openBaseLexer(lex, inputstream) lex.fileIdx = fileidx lex.indentAhead = - 1 @@ -231,13 +230,14 @@ proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream; lex.cache = cache when defined(nimsuggest): lex.previousToken.fileIndex = fileIdx + lex.config = config proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream; - cache: IdentCache) = - openLexer(lex, filename.fileInfoIdx, inputstream, cache) + cache: IdentCache; config: ConfigRef) = + openLexer(lex, filename.fileInfoIdx, inputstream, cache, config) proc closeLexer*(lex: var TLexer) = - inc(gLinesCompiled, lex.lineNumber) + inc(lex.config.linesCompiled, lex.lineNumber) closeBaseLexer(lex) proc getLineInfo(L: TLexer): TLineInfo = @@ -576,17 +576,18 @@ proc getNumber(L: var TLexer, result: var TToken) = result.iNumber = parseBiggestInt(result.literal) # Explicit bounds checks - let outOfRange = case result.tokType: - of tkInt8Lit: (result.iNumber < int8.low or result.iNumber > int8.high) - of tkUInt8Lit: (result.iNumber < BiggestInt(uint8.low) or - result.iNumber > BiggestInt(uint8.high)) - of tkInt16Lit: (result.iNumber < int16.low or result.iNumber > int16.high) - of tkUInt16Lit: (result.iNumber < BiggestInt(uint16.low) or - result.iNumber > BiggestInt(uint16.high)) - of tkInt32Lit: (result.iNumber < int32.low or result.iNumber > int32.high) - of tkUInt32Lit: (result.iNumber < BiggestInt(uint32.low) or - result.iNumber > BiggestInt(uint32.high)) - else: false + let outOfRange = + case result.tokType + of tkInt8Lit: (result.iNumber < int8.low or result.iNumber > int8.high) + of tkUInt8Lit: (result.iNumber < BiggestInt(uint8.low) or + result.iNumber > BiggestInt(uint8.high)) + of tkInt16Lit: (result.iNumber < int16.low or result.iNumber > int16.high) + of tkUInt16Lit: (result.iNumber < BiggestInt(uint16.low) or + result.iNumber > BiggestInt(uint16.high)) + of tkInt32Lit: (result.iNumber < int32.low or result.iNumber > int32.high) + of tkUInt32Lit: (result.iNumber < BiggestInt(uint32.low) or + result.iNumber > BiggestInt(uint32.high)) + else: false if outOfRange: lexMessageLitNum(L, errNumberOutOfRange, startpos) diff --git a/compiler/main.nim b/compiler/main.nim index 401099fc3..f23a3a88e 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -129,9 +129,10 @@ proc commandEval(graph: ModuleGraph; cache: IdentCache; exp: string) = interactivePasses(graph, cache) compileSystemModule(graph, cache) let echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")" - evalNim(graph, echoExp.parseString(cache), makeStdinModule(graph), cache) + evalNim(graph, echoExp.parseString(cache, graph.config), + makeStdinModule(graph), cache) -proc commandScan(cache: IdentCache) = +proc commandScan(cache: IdentCache, config: ConfigRef) = var f = addFileExt(mainCommandArg(), NimExt) var stream = llStreamOpen(f, fmRead) if stream != nil: @@ -139,7 +140,7 @@ proc commandScan(cache: IdentCache) = L: TLexer tok: TToken initToken(tok) - openLexer(L, f, stream, cache) + openLexer(L, f, stream, cache, config) while true: rawGetTok(L, tok) printTok(tok) @@ -265,11 +266,11 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = of "parse": gCmd = cmdParse wantMainModule() - discard parseFile(FileIndex gProjectMainIdx, cache) + discard parseFile(FileIndex gProjectMainIdx, cache, graph.config) of "scan": gCmd = cmdScan wantMainModule() - commandScan(cache) + commandScan(cache, graph.config) msgWriteln("Beware: Indentation tokens depend on the parser's state!") of "secret": gCmd = cmdInteractive @@ -291,7 +292,7 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = let usedMem = formatSize(getMaxMem()) & " peakmem" else: let usedMem = formatSize(getTotalMem()) - rawMessage(hintSuccessX, [$gLinesCompiled, + rawMessage(hintSuccessX, [$graph.config.linesCompiled, formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3), usedMem, if condSyms.isDefined("release"): "Release Build" diff --git a/compiler/modules.nim b/compiler/modules.nim index 56bfdf662..7fe2336dd 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -107,7 +107,7 @@ proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex; proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex; cache: IdentCache): PNode {.procvar.} = - result = syntaxes.parseFile(fileIdx, cache) + result = syntaxes.parseFile(fileIdx, cache, graph.config) graph.addDep(s, fileIdx) graph.addIncludeDep(s.position.FileIndex, fileIdx) diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index bdf558134..dc8d082b3 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -205,7 +205,7 @@ proc readConfigFile(filename: string; cache: IdentCache; config: ConfigRef) = stream = llStreamOpen(filename, fmRead) if stream != nil: initToken(tok) - openLexer(L, filename, stream, cache) + openLexer(L, filename, stream, cache, config) tok.tokType = tkEof # to avoid a pointless warning confTok(L, tok, config) # read in the first token while tok.tokType != tkEof: parseAssignment(L, tok, config) diff --git a/compiler/options.nim b/compiler/options.nim index 5baaa1bfd..f8cb735ae 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -113,6 +113,7 @@ type notnil ConfigRef* = ref object ## eventually all global configuration should be moved here + linesCompiled*: int # all lines that have been compiled cppDefines*: HashSet[string] headerFile*: string features*: set[Feature] diff --git a/compiler/parser.nim b/compiler/parser.nim index c61519541..14683e307 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -27,7 +27,7 @@ when isMainModule: outp.close import - llstream, lexer, idents, strutils, ast, astalgo, msgs + llstream, lexer, idents, strutils, ast, astalgo, msgs, options type TParser* = object # A TParser object represents a file that @@ -84,20 +84,20 @@ proc getTok(p: var TParser) = p.hasProgress = true proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream, - cache: IdentCache; + cache: IdentCache; config: ConfigRef; strongSpaces=false) = ## Open a parser, using the given arguments to set up its internal state. ## initToken(p.tok) - openLexer(p.lex, fileIdx, inputStream, cache) + openLexer(p.lex, fileIdx, inputStream, cache, config) getTok(p) # read the first token p.firstTok = true p.strongSpaces = strongSpaces proc openParser*(p: var TParser, filename: string, inputStream: PLLStream, - cache: IdentCache; + cache: IdentCache; config: ConfigRef; strongSpaces=false) = - openParser(p, filename.fileInfoIdx, inputStream, cache, strongSpaces) + openParser(p, filename.fileInfoIdx, inputStream, cache, config, strongSpaces) proc closeParser(p: var TParser) = ## Close a parser, freeing up its resources. @@ -2178,8 +2178,8 @@ proc parseTopLevelStmt(p: var TParser): PNode = if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok) break -proc parseString*(s: string; cache: IdentCache; filename: string = ""; - line: int = 0; +proc parseString*(s: string; cache: IdentCache; config: ConfigRef; + filename: string = ""; line: int = 0; errorHandler: TErrorHandler = nil): PNode = ## Parses a string into an AST, returning the top node. ## `filename` and `line`, although optional, provide info so that the @@ -2192,7 +2192,7 @@ proc parseString*(s: string; cache: IdentCache; filename: string = ""; # XXX for now the builtin 'parseStmt/Expr' functions do not know about strong # spaces... parser.lex.errorHandler = errorHandler - openParser(parser, filename, stream, cache, false) + openParser(parser, filename, stream, cache, config, false) result = parser.parseAll closeParser(parser) diff --git a/compiler/passes.nim b/compiler/passes.nim index 6ff3f2bb5..b104cd132 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -207,7 +207,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, else: s = stream while true: - openParsers(p, fileIdx, s, cache) + openParsers(p, fileIdx, s, cache, graph.config) if sfSystemModule notin module.flags: # XXX what about caching? no processing then? what if I change the diff --git a/compiler/pbraces.nim b/compiler/pbraces.nim deleted file mode 100644 index fe438d58b..000000000 --- a/compiler/pbraces.nim +++ /dev/null @@ -1,1790 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2017 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -# This module implements the parser of the braces Nim syntax. - -import - llstream, lexer, idents, strutils, ast, astalgo, msgs - -from parser import TParser - -proc getTok(p: var TParser) = - ## Get the next token from the parser's lexer, and store it in the parser's - ## `tok` member. - rawGetTok(p.lex, p.tok) - -proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream; - cache: IdentCache) = - ## Open a parser, using the given arguments to set up its internal state. - ## - initToken(p.tok) - openLexer(p.lex, fileIdx, inputStream, cache) - getTok(p) # read the first token - p.lex.allowTabs = true - -proc openParser*(p: var TParser, filename: string, inputStream: PLLStream; - cache: IdentCache) = - openParser(p, filename.fileInfoIdx, inputStream, cache) - -proc closeParser*(p: var TParser) = - ## Close a parser, freeing up its resources. - closeLexer(p.lex) - -proc parMessage(p: TParser, msg: TMsgKind, arg = "") = - ## Produce and emit the parser message `arg` to output. - lexMessageTok(p.lex, msg, p.tok, arg) - -proc parMessage(p: TParser, msg: TMsgKind, tok: TToken) = - ## Produce and emit a parser message to output about the token `tok` - parMessage(p, msg, prettyTok(tok)) - -proc rawSkipComment(p: var TParser, node: PNode) = - if p.tok.tokType == tkComment: - if node != nil: - if node.comment == nil: node.comment = "" - add(node.comment, p.tok.literal) - else: - parMessage(p, errInternal, "skipComment") - getTok(p) - -proc skipComment(p: var TParser, node: PNode) = - rawSkipComment(p, node) - -proc flexComment(p: var TParser, node: PNode) = - rawSkipComment(p, node) - -proc skipInd(p: var TParser) = discard -proc optPar(p: var TParser) = discard - -proc optInd(p: var TParser, n: PNode) = - skipComment(p, n) - -proc getTokNoInd(p: var TParser) = - getTok(p) - -proc expectIdentOrKeyw(p: TParser) = - if p.tok.tokType != tkSymbol and not isKeyword(p.tok.tokType): - lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok)) - -proc expectIdent(p: TParser) = - if p.tok.tokType != tkSymbol: - lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok)) - -proc eat(p: var TParser, tokType: TTokType) = - ## Move the parser to the next token if the current token is of type - ## `tokType`, otherwise error. - if p.tok.tokType == tokType: - getTok(p) - else: - lexMessageTok(p.lex, errTokenExpected, p.tok, TokTypeToStr[tokType]) - -proc parLineInfo(p: TParser): TLineInfo = - ## Retrieve the line information associated with the parser's current state. - result = getLineInfo(p.lex, p.tok) - -proc indAndComment(p: var TParser, n: PNode) = - rawSkipComment(p, n) - -proc newNodeP(kind: TNodeKind, p: TParser): PNode = - result = newNodeI(kind, parLineInfo(p)) - -proc newIntNodeP(kind: TNodeKind, intVal: BiggestInt, p: TParser): PNode = - result = newNodeP(kind, p) - result.intVal = intVal - -proc newFloatNodeP(kind: TNodeKind, floatVal: BiggestFloat, - p: TParser): PNode = - result = newNodeP(kind, p) - result.floatVal = floatVal - -proc newStrNodeP(kind: TNodeKind, strVal: string, p: TParser): PNode = - result = newNodeP(kind, p) - result.strVal = strVal - -proc newIdentNodeP(ident: PIdent, p: TParser): PNode = - result = newNodeP(nkIdent, p) - result.ident = ident - -proc parseExpr(p: var TParser): PNode -proc parseStmt(p: var TParser): PNode -proc parseTypeDesc(p: var TParser): PNode -proc parseDoBlocks(p: var TParser, call: PNode) -proc parseParamList(p: var TParser, retColon = true): PNode -proc parseStmtPragma(p: var TParser): PNode -proc parseCase(p: var TParser): PNode -proc parseTry(p: var TParser): PNode - -proc isSigilLike(tok: TToken): bool {.inline.} = - result = tok.tokType == tkOpr and tok.ident.s[0] == '@' - -proc isAt(tok: TToken): bool {.inline.} = - tok.tokType == tkOpr and tok.ident.s == "@" and tok.strongSpaceB == 0 - -proc isRightAssociative(tok: TToken): bool {.inline.} = - ## Determines whether the token is right assocative. - result = tok.tokType == tkOpr and tok.ident.s[0] == '^' - # or (let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>')) - -proc getPrecedence(tok: TToken): int = - ## Calculates the precedence of the given token. - template considerStrongSpaces(x): untyped = x - - case tok.tokType - of tkOpr: - let L = tok.ident.s.len - let relevantChar = tok.ident.s[0] - - # arrow like? - if L > 1 and tok.ident.s[L-1] == '>' and - tok.ident.s[L-2] in {'-', '~', '='}: return considerStrongSpaces(1) - - template considerAsgn(value: untyped) = - result = if tok.ident.s[L-1] == '=': 1 else: value - - case relevantChar - of '$', '^': considerAsgn(10) - of '*', '%', '/', '\\': considerAsgn(9) - of '~': result = 8 - of '+', '-', '|': considerAsgn(8) - of '&': considerAsgn(7) - of '=', '<', '>', '!': result = 5 - of '.': considerAsgn(6) - of '?': result = 2 - else: considerAsgn(2) - of tkDiv, tkMod, tkShl, tkShr: result = 9 - of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5 - of tkDotDot: result = 6 - of tkAnd: result = 4 - of tkOr, tkXor, tkPtr, tkRef: result = 3 - else: return -10 - result = considerStrongSpaces(result) - -proc isOperator(tok: TToken): bool = - ## Determines if the given token is an operator type token. - tok.tokType in {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs, - tkIsnot, tkNot, tkOf, tkAs, tkDotDot, tkAnd, tkOr, tkXor} - -proc isUnary(p: TParser): bool = - ## Check if the current parser token is a unary operator - if p.tok.tokType in {tkOpr, tkDotDot}: - result = true - -proc checkBinary(p: TParser) {.inline.} = - ## Check if the current parser token is a binary operator. - # we don't check '..' here as that's too annoying - discard - -#| module = stmt ^* (';' / IND{=}) -#| -#| comma = ',' COMMENT? -#| semicolon = ';' COMMENT? -#| colon = ':' COMMENT? -#| colcom = ':' COMMENT? -#| -#| operator = OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9 -#| | 'or' | 'xor' | 'and' -#| | 'is' | 'isnot' | 'in' | 'notin' | 'of' -#| | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'static' | '..' -#| -#| prefixOperator = operator -#| -#| optInd = COMMENT? -#| optPar = (IND{>} | IND{=})? -#| -#| simpleExpr = arrowExpr (OP0 optInd arrowExpr)* -#| arrowExpr = assignExpr (OP1 optInd assignExpr)* -#| assignExpr = orExpr (OP2 optInd orExpr)* -#| orExpr = andExpr (OP3 optInd andExpr)* -#| andExpr = cmpExpr (OP4 optInd cmpExpr)* -#| cmpExpr = sliceExpr (OP5 optInd sliceExpr)* -#| sliceExpr = ampExpr (OP6 optInd ampExpr)* -#| ampExpr = plusExpr (OP7 optInd plusExpr)* -#| plusExpr = mulExpr (OP8 optInd mulExpr)* -#| mulExpr = dollarExpr (OP9 optInd dollarExpr)* -#| dollarExpr = primary (OP10 optInd primary)* - -proc colcom(p: var TParser, n: PNode) = - skipComment(p, n) - -proc parseSymbol(p: var TParser, allowNil = false): PNode = - #| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`' - #| | IDENT | 'addr' | 'type' - case p.tok.tokType - of tkSymbol, tkAddr, tkType: - result = newIdentNodeP(p.tok.ident, p) - getTok(p) - of tkAccent: - result = newNodeP(nkAccQuoted, p) - getTok(p) - while true: - case p.tok.tokType - of tkAccent: - if result.len == 0: - parMessage(p, errIdentifierExpected, p.tok) - break - of tkOpr, tkDot, tkDotDot, tkEquals, tkParLe..tkParDotRi: - var accm = "" - while p.tok.tokType in {tkOpr, tkDot, tkDotDot, tkEquals, - tkParLe..tkParDotRi}: - accm.add(tokToStr(p.tok)) - getTok(p) - result.add(newIdentNodeP(p.lex.cache.getIdent(accm), p)) - of tokKeywordLow..tokKeywordHigh, tkSymbol, tkIntLit..tkCharLit: - result.add(newIdentNodeP(p.lex.cache.getIdent(tokToStr(p.tok)), p)) - getTok(p) - else: - parMessage(p, errIdentifierExpected, p.tok) - break - eat(p, tkAccent) - else: - if allowNil and p.tok.tokType == tkNil: - result = newNodeP(nkNilLit, p) - getTok(p) - else: - parMessage(p, errIdentifierExpected, p.tok) - # BUGFIX: We must consume a token here to prevent endless loops! - # But: this really sucks for idetools and keywords, so we don't do it - # if it is a keyword: - if not isKeyword(p.tok.tokType): getTok(p) - result = ast.emptyNode - -proc colonOrEquals(p: var TParser, a: PNode): PNode = - if p.tok.tokType == tkColon: - result = newNodeP(nkExprColonExpr, p) - getTok(p) - #optInd(p, result) - addSon(result, a) - addSon(result, parseExpr(p)) - elif p.tok.tokType == tkEquals: - result = newNodeP(nkExprEqExpr, p) - getTok(p) - #optInd(p, result) - addSon(result, a) - addSon(result, parseExpr(p)) - else: - result = a - -proc exprColonEqExpr(p: var TParser): PNode = - #| exprColonEqExpr = expr (':'|'=' expr)? - var a = parseExpr(p) - result = colonOrEquals(p, a) - -proc exprList(p: var TParser, endTok: TTokType, result: PNode) = - #| exprList = expr ^+ comma - getTok(p) - optInd(p, result) - while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof): - var a = parseExpr(p) - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, a) - -proc dotExpr(p: var TParser, a: PNode): PNode = - #| dotExpr = expr '.' optInd symbol - var info = p.parLineInfo - getTok(p) - result = newNodeI(nkDotExpr, info) - optInd(p, result) - addSon(result, a) - addSon(result, parseSymbol(p)) - -proc qualifiedIdent(p: var TParser): PNode = - #| qualifiedIdent = symbol ('.' optInd symbol)? - result = parseSymbol(p) - if p.tok.tokType == tkDot: result = dotExpr(p, result) - -proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) = - assert(endTok in {tkCurlyLe, tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi}) - getTok(p) - optInd(p, result) - while p.tok.tokType != endTok and p.tok.tokType != tkEof: - var a = exprColonEqExpr(p) - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - skipComment(p, a) - optPar(p) - eat(p, endTok) - -proc exprColonEqExprList(p: var TParser, kind: TNodeKind, - endTok: TTokType): PNode = - #| exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)? - result = newNodeP(kind, p) - exprColonEqExprListAux(p, endTok, result) - -proc setOrTableConstr(p: var TParser): PNode = - result = newNodeP(nkCurly, p) - getTok(p) - optInd(p, result) - if p.tok.tokType == tkColon: - getTok(p) # skip ':' - result.kind = nkTableConstr - else: - while p.tok.tokType notin {tkBracketDotRi, tkEof}: - var a = exprColonEqExpr(p) - if a.kind == nkExprColonExpr: result.kind = nkTableConstr - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - skipComment(p, a) - optPar(p) - eat(p, tkBracketDotRi) - -proc parseCast(p: var TParser): PNode = - #| castExpr = 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')' - result = newNodeP(nkCast, p) - getTok(p) - eat(p, tkBracketLe) - optInd(p, result) - addSon(result, parseTypeDesc(p)) - optPar(p) - eat(p, tkBracketRi) - eat(p, tkParLe) - optInd(p, result) - addSon(result, parseExpr(p)) - optPar(p) - eat(p, tkParRi) - -proc setBaseFlags(n: PNode, base: TNumericalBase) = - case base - of base10: discard - of base2: incl(n.flags, nfBase2) - of base8: incl(n.flags, nfBase8) - of base16: incl(n.flags, nfBase16) - -proc parseGStrLit(p: var TParser, a: PNode): PNode = - case p.tok.tokType - of tkGStrLit: - result = newNodeP(nkCallStrLit, p) - addSon(result, a) - addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p)) - getTok(p) - of tkGTripleStrLit: - result = newNodeP(nkCallStrLit, p) - addSon(result, a) - addSon(result, newStrNodeP(nkTripleStrLit, p.tok.literal, p)) - getTok(p) - else: - result = a - -type - TPrimaryMode = enum pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix - -proc complexOrSimpleStmt(p: var TParser): PNode -proc simpleExpr(p: var TParser, mode = pmNormal): PNode - -proc semiStmtList(p: var TParser, result: PNode) = - inc p.inSemiStmtList - result.add(complexOrSimpleStmt(p)) - while p.tok.tokType == tkSemiColon: - getTok(p) - optInd(p, result) - result.add(complexOrSimpleStmt(p)) - dec p.inSemiStmtList - result.kind = nkStmtListExpr - -proc parsePar(p: var TParser): PNode = - #| parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try' - #| | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let' - #| | 'when' | 'var' | 'mixin' - #| par = '(' optInd - #| ( &parKeyw complexOrSimpleStmt ^+ ';' - #| | ';' complexOrSimpleStmt ^+ ';' - #| | pragmaStmt - #| | simpleExpr ( ('=' expr (';' complexOrSimpleStmt ^+ ';' )? ) - #| | (':' expr (',' exprColonEqExpr ^+ ',' )? ) ) ) - #| optPar ')' - # - # unfortunately it's ambiguous: (expr: expr) vs (exprStmt); however a - # leading ';' could be used to enforce a 'stmt' context ... - result = newNodeP(nkPar, p) - getTok(p) - optInd(p, result) - if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase, - tkTry, tkDefer, tkFinally, tkExcept, tkFor, tkBlock, - tkConst, tkLet, tkWhen, tkVar, - tkMixin}: - # XXX 'bind' used to be an expression, so we exclude it here; - # tests/reject/tbind2 fails otherwise. - semiStmtList(p, result) - elif p.tok.tokType == tkSemiColon: - # '(;' enforces 'stmt' context: - getTok(p) - optInd(p, result) - semiStmtList(p, result) - elif p.tok.tokType == tkCurlyDotLe: - result.add(parseStmtPragma(p)) - elif p.tok.tokType != tkParRi: - var a = simpleExpr(p) - if p.tok.tokType == tkEquals: - # special case: allow assignments - getTok(p) - optInd(p, result) - let b = parseExpr(p) - let asgn = newNodeI(nkAsgn, a.info, 2) - asgn.sons[0] = a - asgn.sons[1] = b - result.add(asgn) - if p.tok.tokType == tkSemiColon: - semiStmtList(p, result) - elif p.tok.tokType == tkSemiColon: - # stmt context: - result.add(a) - semiStmtList(p, result) - else: - a = colonOrEquals(p, a) - result.add(a) - if p.tok.tokType == tkComma: - getTok(p) - skipComment(p, a) - while p.tok.tokType != tkParRi and p.tok.tokType != tkEof: - var a = exprColonEqExpr(p) - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - skipComment(p, a) - optPar(p) - eat(p, tkParRi) - -proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode = - #| literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT - #| | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT - #| | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT - #| | STR_LIT | RSTR_LIT | TRIPLESTR_LIT - #| | CHAR_LIT - #| | NIL - #| generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT - #| identOrLiteral = generalizedLit | symbol | literal - #| | par | arrayConstr | setOrTableConstr - #| | castExpr - #| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')' - #| arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']' - case p.tok.tokType - of tkSymbol, tkType, tkAddr: - result = newIdentNodeP(p.tok.ident, p) - getTok(p) - result = parseGStrLit(p, result) - of tkAccent: - result = parseSymbol(p) # literals - of tkIntLit: - result = newIntNodeP(nkIntLit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkInt8Lit: - result = newIntNodeP(nkInt8Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkInt16Lit: - result = newIntNodeP(nkInt16Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkInt32Lit: - result = newIntNodeP(nkInt32Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkInt64Lit: - result = newIntNodeP(nkInt64Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkUIntLit: - result = newIntNodeP(nkUIntLit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkUInt8Lit: - result = newIntNodeP(nkUInt8Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkUInt16Lit: - result = newIntNodeP(nkUInt16Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkUInt32Lit: - result = newIntNodeP(nkUInt32Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkUInt64Lit: - result = newIntNodeP(nkUInt64Lit, p.tok.iNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkFloatLit: - result = newFloatNodeP(nkFloatLit, p.tok.fNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkFloat32Lit: - result = newFloatNodeP(nkFloat32Lit, p.tok.fNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkFloat64Lit: - result = newFloatNodeP(nkFloat64Lit, p.tok.fNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkFloat128Lit: - result = newFloatNodeP(nkFloat128Lit, p.tok.fNumber, p) - setBaseFlags(result, p.tok.base) - getTok(p) - of tkStrLit: - result = newStrNodeP(nkStrLit, p.tok.literal, p) - getTok(p) - of tkRStrLit: - result = newStrNodeP(nkRStrLit, p.tok.literal, p) - getTok(p) - of tkTripleStrLit: - result = newStrNodeP(nkTripleStrLit, p.tok.literal, p) - getTok(p) - of tkCharLit: - result = newIntNodeP(nkCharLit, ord(p.tok.literal[0]), p) - getTok(p) - of tkNil: - result = newNodeP(nkNilLit, p) - getTok(p) - of tkParLe: - # () constructor - if mode in {pmTypeDesc, pmTypeDef}: - result = exprColonEqExprList(p, nkPar, tkParRi) - else: - result = parsePar(p) - of tkBracketDotLe: - # {} constructor - result = setOrTableConstr(p) - of tkBracketLe: - # [] constructor - result = exprColonEqExprList(p, nkBracket, tkBracketRi) - of tkCast: - result = parseCast(p) - else: - parMessage(p, errExprExpected, p.tok) - getTok(p) # we must consume a token here to prevend endless loops! - result = ast.emptyNode - -proc namedParams(p: var TParser, callee: PNode, - kind: TNodeKind, endTok: TTokType): PNode = - let a = callee - result = newNodeP(kind, p) - addSon(result, a) - exprColonEqExprListAux(p, endTok, result) - -proc parseMacroColon(p: var TParser, x: PNode): PNode -proc primarySuffix(p: var TParser, r: PNode): PNode = - #| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks? - #| | doBlocks - #| | '.' optInd symbol generalizedLit? - #| | '[' optInd indexExprList optPar ']' - #| | '{' optInd indexExprList optPar '}' - #| | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax - result = r - - template somePar() = discard - while p.tok.indent < 0: - case p.tok.tokType - of tkParLe: - somePar() - result = namedParams(p, result, nkCall, tkParRi) - if result.len > 1 and result.sons[1].kind == nkExprColonExpr: - result.kind = nkObjConstr - else: - parseDoBlocks(p, result) - of tkDo: - var a = result - result = newNodeP(nkCall, p) - addSon(result, a) - parseDoBlocks(p, result) - of tkDot: - result = dotExpr(p, result) - result = parseGStrLit(p, result) - of tkBracketLe: - somePar() - result = namedParams(p, result, nkBracketExpr, tkBracketRi) - of tkBracketDotLe: - somePar() - result = namedParams(p, result, nkCurlyExpr, tkBracketDotRi) - of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType: - if p.inPragma == 0: - # actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet - # solution, but pragmas.nim can't handle that - let a = result - result = newNodeP(nkCommand, p) - addSon(result, a) - when true: - addSon result, parseExpr(p) - else: - while p.tok.tokType != tkEof: - let x = parseExpr(p) - addSon(result, x) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, x) - if p.tok.tokType == tkDo: - parseDoBlocks(p, result) - else: - result = parseMacroColon(p, result) - break - else: - break - -proc primary(p: var TParser, mode: TPrimaryMode): PNode -proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode - -proc parseOperators(p: var TParser, headNode: PNode, - limit: int, mode: TPrimaryMode): PNode = - result = headNode - # expand while operators have priorities higher than 'limit' - var opPrec = getPrecedence(p.tok) - let modeB = if mode == pmTypeDef: pmTypeDesc else: mode - # the operator itself must not start on a new line: - while opPrec >= limit and p.tok.indent < 0 and not isAt(p.tok): - checkBinary(p) - var leftAssoc = 1-ord(isRightAssociative(p.tok)) - var a = newNodeP(nkInfix, p) - var opNode = newIdentNodeP(p.tok.ident, p) # skip operator: - getTok(p) - optInd(p, a) - # read sub-expression with higher priority: - var b = simpleExprAux(p, opPrec + leftAssoc, modeB) - addSon(a, opNode) - addSon(a, result) - addSon(a, b) - result = a - opPrec = getPrecedence(p.tok) - -proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode = - result = primary(p, mode) - result = parseOperators(p, result, limit, mode) - -proc simpleExpr(p: var TParser, mode = pmNormal): PNode = - result = simpleExprAux(p, -1, mode) - -proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode = - #| condExpr = expr colcom expr optInd - #| ('elif' expr colcom expr optInd)* - #| 'else' colcom expr - #| ifExpr = 'if' condExpr - #| whenExpr = 'when' condExpr - result = newNodeP(kind, p) - while true: - getTok(p) # skip `if`, `elif` - var branch = newNodeP(nkElifExpr, p) - addSon(branch, parseExpr(p)) - colcom(p, branch) - addSon(branch, parseExpr(p)) - optInd(p, branch) - addSon(result, branch) - if p.tok.tokType != tkElif: break - var branch = newNodeP(nkElseExpr, p) - eat(p, tkElse) - colcom(p, branch) - addSon(branch, parseExpr(p)) - addSon(result, branch) - -proc parsePragma(p: var TParser): PNode = - result = newNodeP(nkPragma, p) - inc p.inPragma - if isAt(p.tok): - while isAt(p.tok): - getTok(p) - var a = parseExpr(p) - optInd(p, a) - if a.kind in nkCallKinds and a.len == 2: - let repaired = newNodeI(nkExprColonExpr, a.info) - repaired.add a[0] - repaired.add a[1] - a = repaired - addSon(result, a) - skipComment(p, a) - else: - getTok(p) - optInd(p, result) - while p.tok.tokType notin {tkCurlyDotRi, tkCurlyRi, tkEof}: - var a = exprColonEqExpr(p) - addSon(result, a) - if p.tok.tokType == tkComma: - getTok(p) - skipComment(p, a) - optPar(p) - if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p) - else: parMessage(p, errTokenExpected, ".}") - dec p.inPragma - -proc identVis(p: var TParser; allowDot=false): PNode = - #| identVis = symbol opr? # postfix position - #| identVisDot = symbol '.' optInd symbol opr? - var a = parseSymbol(p) - if p.tok.tokType == tkOpr: - result = newNodeP(nkPostfix, p) - addSon(result, newIdentNodeP(p.tok.ident, p)) - addSon(result, a) - getTok(p) - elif p.tok.tokType == tkDot and allowDot: - result = dotExpr(p, a) - else: - result = a - -proc identWithPragma(p: var TParser; allowDot=false): PNode = - #| identWithPragma = identVis pragma? - #| identWithPragmaDot = identVisDot pragma? - var a = identVis(p, allowDot) - if p.tok.tokType == tkCurlyDotLe or isAt(p.tok): - result = newNodeP(nkPragmaExpr, p) - addSon(result, a) - addSon(result, parsePragma(p)) - else: - result = a - -type - TDeclaredIdentFlag = enum - withPragma, # identifier may have pragma - withBothOptional # both ':' and '=' parts are optional - TDeclaredIdentFlags = set[TDeclaredIdentFlag] - -proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode = - #| declColonEquals = identWithPragma (comma identWithPragma)* comma? - #| (':' optInd typeDesc)? ('=' optInd expr)? - #| identColonEquals = ident (comma ident)* comma? - #| (':' optInd typeDesc)? ('=' optInd expr)?) - var a: PNode - result = newNodeP(nkIdentDefs, p) - while true: - case p.tok.tokType - of tkSymbol, tkAccent: - if withPragma in flags: a = identWithPragma(p) - else: a = parseSymbol(p) - if a.kind == nkEmpty: return - else: break - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, a) - if p.tok.tokType == tkColon: - getTok(p) - optInd(p, result) - addSon(result, parseTypeDesc(p)) - else: - addSon(result, ast.emptyNode) - if p.tok.tokType != tkEquals and withBothOptional notin flags: - parMessage(p, errColonOrEqualsExpected, p.tok) - if p.tok.tokType == tkEquals: - getTok(p) - optInd(p, result) - addSon(result, parseExpr(p)) - else: - addSon(result, ast.emptyNode) - -proc parseTuple(p: var TParser): PNode = - result = newNodeP(nkTupleTy, p) - getTok(p) - if p.tok.tokType in {tkBracketLe, tkCurlyLe}: - let usedCurly = p.tok.tokType == tkCurlyLe - getTok(p) - optInd(p, result) - while p.tok.tokType in {tkSymbol, tkAccent}: - var a = parseIdentColonEquals(p, {}) - addSon(result, a) - if p.tok.tokType notin {tkComma, tkSemiColon}: break - getTok(p) - skipComment(p, a) - optPar(p) - if usedCurly: eat(p, tkCurlyRi) - else: eat(p, tkBracketRi) - else: - result = newNodeP(nkTupleClassTy, p) - -proc parseParamList(p: var TParser, retColon = true): PNode = - #| paramList = '(' declColonEquals ^* (comma/semicolon) ')' - #| paramListArrow = paramList? ('->' optInd typeDesc)? - #| paramListColon = paramList? (':' optInd typeDesc)? - var a: PNode - result = newNodeP(nkFormalParams, p) - addSon(result, ast.emptyNode) # return type - let hasParLe = p.tok.tokType == tkParLe and p.tok.indent < 0 - if hasParLe: - getTok(p) - optInd(p, result) - while true: - case p.tok.tokType - of tkSymbol, tkAccent: - a = parseIdentColonEquals(p, {withBothOptional, withPragma}) - of tkParRi: - break - else: - parMessage(p, errTokenExpected, ")") - break - addSon(result, a) - if p.tok.tokType notin {tkComma, tkSemiColon}: break - getTok(p) - skipComment(p, a) - optPar(p) - eat(p, tkParRi) - let hasRet = if retColon: p.tok.tokType == tkColon - else: p.tok.tokType == tkOpr and p.tok.ident.s == "->" - if hasRet and p.tok.indent < 0: - getTok(p) - optInd(p, result) - result.sons[0] = parseTypeDesc(p) - elif not retColon and not hasParle: - # Mark as "not there" in order to mark for deprecation in the semantic pass: - result = ast.emptyNode - -proc optPragmas(p: var TParser): PNode = - if p.tok.tokType == tkCurlyDotLe or isAt(p.tok): - result = parsePragma(p) - else: - result = ast.emptyNode - -proc parseDoBlock(p: var TParser): PNode = - #| doBlock = 'do' paramListArrow pragmas? colcom stmt - let info = parLineInfo(p) - getTok(p) - let params = parseParamList(p, retColon=false) - let pragmas = optPragmas(p) - colcom(p, result) - result = newProcNode(nkDo, info, parseStmt(p), - params = params, - pragmas = pragmas) - -proc parseDoBlocks(p: var TParser, call: PNode) = - #| doBlocks = doBlock ^* IND{=} - while p.tok.tokType == tkDo: - addSon(call, parseDoBlock(p)) - -proc parseCurlyStmt(p: var TParser): PNode = - result = newNodeP(nkStmtList, p) - eat(p, tkCurlyLe) - result.add parseStmt(p) - while p.tok.tokType notin {tkEof, tkCurlyRi}: - if p.tok.tokType == tkSemicolon: getTok(p) - elif p.tok.indent < 0: break - result.add parseStmt(p) - eat(p, tkCurlyRi) - -proc parseProcExpr(p: var TParser, isExpr: bool): PNode = - #| procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)? - # either a proc type or a anonymous proc - let info = parLineInfo(p) - getTok(p) - let hasSignature = p.tok.tokType in {tkParLe, tkColon} and p.tok.indent < 0 - let params = parseParamList(p) - let pragmas = optPragmas(p) - if p.tok.tokType == tkCurlyLe and isExpr: - result = newProcNode(nkLambda, info, parseCurlyStmt(p), - params = params, - pragmas = pragmas) - else: - result = newNodeI(nkProcTy, info) - if hasSignature: - addSon(result, params) - addSon(result, pragmas) - -proc isExprStart(p: TParser): bool = - case p.tok.tokType - of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, - tkProc, tkIterator, tkBind, tkAddr, - tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr, - tkTuple, tkObject, tkType, tkWhen, tkCase, tkOut: - result = true - else: result = false - -proc parseSymbolList(p: var TParser, result: PNode, allowNil = false) = - while true: - var s = parseSymbol(p, allowNil) - if s.kind == nkEmpty: break - addSon(result, s) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, s) - -proc parseTypeDescKAux(p: var TParser, kind: TNodeKind, - mode: TPrimaryMode): PNode = - #| distinct = 'distinct' optInd typeDesc - result = newNodeP(kind, p) - getTok(p) - optInd(p, result) - if not isOperator(p.tok) and isExprStart(p): - addSon(result, primary(p, mode)) - if kind == nkDistinctTy and p.tok.tokType == tkSymbol: - var nodeKind: TNodeKind - if p.tok.ident.s == "with": - nodeKind = nkWith - elif p.tok.ident.s == "without": - nodeKind = nkWithout - else: - return result - getTok(p) - let list = newNodeP(nodeKind, p) - result.addSon list - parseSymbolList(p, list, allowNil = true) - -proc parseExpr(p: var TParser): PNode = - #| expr = (ifExpr - #| | whenExpr - #| | caseExpr - #| | tryExpr) - #| / simpleExpr - case p.tok.tokType: - of tkIf: result = parseIfExpr(p, nkIfExpr) - of tkWhen: result = parseIfExpr(p, nkWhenExpr) - of tkCase: result = parseCase(p) - of tkTry: result = parseTry(p) - else: result = simpleExpr(p) - -proc parseEnum(p: var TParser): PNode -proc parseObject(p: var TParser): PNode -proc parseTypeClass(p: var TParser): PNode - -proc primary(p: var TParser, mode: TPrimaryMode): PNode = - #| typeKeyw = 'var' | 'out' | 'ref' | 'ptr' | 'shared' | 'tuple' - #| | 'proc' | 'iterator' | 'distinct' | 'object' | 'enum' - #| primary = typeKeyw typeDescK - #| / prefixOperator* identOrLiteral primarySuffix* - #| / 'static' primary - #| / 'bind' primary - if isOperator(p.tok): - let isSigil = isSigilLike(p.tok) - result = newNodeP(nkPrefix, p) - var a = newIdentNodeP(p.tok.ident, p) - addSon(result, a) - getTok(p) - optInd(p, a) - if isSigil: - #XXX prefix operators - addSon(result, primary(p, pmSkipSuffix)) - result = primarySuffix(p, result) - else: - addSon(result, primary(p, pmNormal)) - return - - case p.tok.tokType: - of tkTuple: result = parseTuple(p) - of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}) - of tkIterator: - result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}) - if result.kind == nkLambda: result.kind = nkIteratorDef - else: result.kind = nkIteratorTy - of tkEnum: - if mode == pmTypeDef: - result = parseEnum(p) - else: - result = newNodeP(nkEnumTy, p) - getTok(p) - of tkObject: - if mode == pmTypeDef: - result = parseObject(p) - else: - result = newNodeP(nkObjectTy, p) - getTok(p) - of tkConcept: - if mode == pmTypeDef: - result = parseTypeClass(p) - else: - parMessage(p, errInvalidToken, p.tok) - of tkStatic: - let info = parLineInfo(p) - getTokNoInd(p) - let next = primary(p, pmNormal) - if next.kind == nkBracket and next.sonsLen == 1: - result = newNode(nkStaticTy, info, @[next.sons[0]]) - else: - result = newNode(nkStaticExpr, info, @[next]) - of tkBind: - result = newNodeP(nkBind, p) - getTok(p) - optInd(p, result) - addSon(result, primary(p, pmNormal)) - of tkVar: result = parseTypeDescKAux(p, nkVarTy, mode) - of tkOut: result = parseTypeDescKAux(p, nkVarTy, mode) - of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode) - of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode) - of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, mode) - else: - result = identOrLiteral(p, mode) - if mode != pmSkipSuffix: - result = primarySuffix(p, result) - -proc parseTypeDesc(p: var TParser): PNode = - #| typeDesc = simpleExpr - result = simpleExpr(p, pmTypeDesc) - -proc parseTypeDefAux(p: var TParser): PNode = - #| typeDefAux = simpleExpr - #| | 'concept' typeClass - result = simpleExpr(p, pmTypeDef) - -proc makeCall(n: PNode): PNode = - ## Creates a call if the given node isn't already a call. - if n.kind in nkCallKinds: - result = n - else: - result = newNodeI(nkCall, n.info) - result.add n - -proc parseMacroColon(p: var TParser, x: PNode): PNode = - #| macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt - #| | IND{=} 'elif' expr ':' stmt - #| | IND{=} 'except' exprList ':' stmt - #| | IND{=} 'else' ':' stmt )* - result = x - if p.tok.tokType == tkColon and p.tok.indent < 0: - result = makeCall(result) - getTok(p) - skipComment(p, result) - let stmtList = newNodeP(nkStmtList, p) - if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}: - let body = parseStmt(p) - stmtList.add body - #addSon(result, makeStmtList(body)) - while true: - var b: PNode - case p.tok.tokType - of tkOf: - b = newNodeP(nkOfBranch, p) - exprList(p, tkCurlyLe, b) - of tkElif: - b = newNodeP(nkElifBranch, p) - getTok(p) - optInd(p, b) - addSon(b, parseExpr(p)) - of tkExcept: - b = newNodeP(nkExceptBranch, p) - exprList(p, tkCurlyLe, b) - of tkElse: - b = newNodeP(nkElse, p) - getTok(p) - else: break - addSon(b, parseCurlyStmt(p)) - addSon(stmtList, b) - if b.kind == nkElse: break - if stmtList.len == 1 and stmtList[0].kind == nkStmtList: - # to keep backwards compatibility (see tests/vm/tstringnil) - result.add stmtList[0] - else: - result.add stmtList - -proc parseExprStmt(p: var TParser): PNode = - #| exprStmt = simpleExpr - #| (( '=' optInd expr ) - #| / ( expr ^+ comma - #| doBlocks - #| / macroColon - #| ))? - var a = simpleExpr(p) - if p.tok.tokType == tkEquals: - getTok(p) - optInd(p, result) - var b = parseExpr(p) - result = newNodeI(nkAsgn, a.info) - addSon(result, a) - addSon(result, b) - else: - # simpleExpr parsed 'p a' from 'p a, b'? - if p.tok.indent < 0 and p.tok.tokType == tkComma and a.kind == nkCommand: - result = a - while true: - getTok(p) - optInd(p, result) - var e = parseExpr(p) - addSon(result, e) - if p.tok.tokType != tkComma: break - elif p.tok.indent < 0 and isExprStart(p): - if a.kind == nkCommand: - result = a - else: - result = newNode(nkCommand, a.info, @[a]) - while true: - var e = parseExpr(p) - addSon(result, e) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, result) - else: - result = a - if p.tok.tokType == tkDo and p.tok.indent < 0: - result = makeCall(result) - parseDoBlocks(p, result) - return result - result = parseMacroColon(p, result) - -proc parseModuleName(p: var TParser, kind: TNodeKind): PNode = - result = parseExpr(p) - -proc parseImport(p: var TParser, kind: TNodeKind): PNode = - #| importStmt = 'import' optInd expr - #| ((comma expr)* - #| / 'except' optInd (expr ^+ comma)) - result = newNodeP(kind, p) - getTok(p) # skip `import` or `export` - optInd(p, result) - var a = parseModuleName(p, kind) - addSon(result, a) - if p.tok.tokType in {tkComma, tkExcept}: - if p.tok.tokType == tkExcept: - result.kind = succ(kind) - getTok(p) - optInd(p, result) - while true: - # was: while p.tok.tokType notin {tkEof, tkSad, tkDed}: - a = parseModuleName(p, kind) - if a.kind == nkEmpty: break - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, a) - #expectNl(p) - -proc parseIncludeStmt(p: var TParser): PNode = - #| includeStmt = 'include' optInd expr ^+ comma - result = newNodeP(nkIncludeStmt, p) - getTok(p) # skip `import` or `include` - optInd(p, result) - while true: - # was: while p.tok.tokType notin {tkEof, tkSad, tkDed}: - var a = parseExpr(p) - if a.kind == nkEmpty: break - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, a) - #expectNl(p) - -proc parseFromStmt(p: var TParser): PNode = - #| fromStmt = 'from' moduleName 'import' optInd expr (comma expr)* - result = newNodeP(nkFromStmt, p) - getTok(p) # skip `from` - optInd(p, result) - var a = parseModuleName(p, nkImportStmt) - addSon(result, a) #optInd(p, a); - eat(p, tkImport) - optInd(p, result) - while true: - # p.tok.tokType notin {tkEof, tkSad, tkDed}: - a = parseExpr(p) - if a.kind == nkEmpty: break - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, a) - #expectNl(p) - -proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode = - #| returnStmt = 'return' optInd expr? - #| raiseStmt = 'raise' optInd expr? - #| yieldStmt = 'yield' optInd expr? - #| discardStmt = 'discard' optInd expr? - #| breakStmt = 'break' optInd expr? - #| continueStmt = 'break' optInd expr? - result = newNodeP(kind, p) - getTok(p) - if p.tok.tokType == tkComment: - skipComment(p, result) - addSon(result, ast.emptyNode) - elif p.tok.indent >= 0 or not isExprStart(p): - # NL terminates: - addSon(result, ast.emptyNode) - else: - addSon(result, parseExpr(p)) - -proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode = - #| condStmt = expr colcom stmt COMMENT? - #| (IND{=} 'elif' expr colcom stmt)* - #| (IND{=} 'else' colcom stmt)? - #| ifStmt = 'if' condStmt - #| whenStmt = 'when' condStmt - result = newNodeP(kind, p) - while true: - getTok(p) # skip `if`, `when`, `elif` - var branch = newNodeP(nkElifBranch, p) - optInd(p, branch) - addSon(branch, parseExpr(p)) - colcom(p, branch) - addSon(branch, parseCurlyStmt(p)) - skipComment(p, branch) - addSon(result, branch) - if p.tok.tokType != tkElif: break - if p.tok.tokType == tkElse: - var branch = newNodeP(nkElse, p) - eat(p, tkElse) - addSon(branch, parseCurlyStmt(p)) - addSon(result, branch) - -proc parseWhile(p: var TParser): PNode = - #| whileStmt = 'while' expr colcom stmt - result = newNodeP(nkWhileStmt, p) - getTok(p) - optInd(p, result) - addSon(result, parseExpr(p)) - colcom(p, result) - addSon(result, parseCurlyStmt(p)) - -proc parseCase(p: var TParser): PNode = - #| ofBranch = 'of' exprList colcom stmt - #| ofBranches = ofBranch (IND{=} ofBranch)* - #| (IND{=} 'elif' expr colcom stmt)* - #| (IND{=} 'else' colcom stmt)? - #| caseStmt = 'case' expr ':'? COMMENT? - #| (IND{>} ofBranches DED - #| | IND{=} ofBranches) - var - b: PNode - inElif= false - result = newNodeP(nkCaseStmt, p) - getTok(p) - addSon(result, parseExpr(p)) - eat(p, tkCurlyLe) - skipComment(p, result) - - while true: - case p.tok.tokType - of tkOf: - if inElif: break - b = newNodeP(nkOfBranch, p) - exprList(p, tkCurlyLe, b) - of tkElif: - inElif = true - b = newNodeP(nkElifBranch, p) - getTok(p) - optInd(p, b) - addSon(b, parseExpr(p)) - of tkElse: - b = newNodeP(nkElse, p) - getTok(p) - else: break - skipComment(p, b) - addSon(b, parseCurlyStmt(p)) - addSon(result, b) - if b.kind == nkElse: break - eat(p, tkCurlyRi) - -proc parseTry(p: var TParser): PNode = - #| tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally') - #| (IND{=}? 'except' exprList colcom stmt)* - #| (IND{=}? 'finally' colcom stmt)? - #| tryExpr = 'try' colcom stmt &(optInd 'except'|'finally') - #| (optInd 'except' exprList colcom stmt)* - #| (optInd 'finally' colcom stmt)? - result = newNodeP(nkTryStmt, p) - getTok(p) - colcom(p, result) - addSon(result, parseCurlyStmt(p)) - var b: PNode = nil - while true: - case p.tok.tokType - of tkExcept: - b = newNodeP(nkExceptBranch, p) - exprList(p, tkCurlyLe, b) - of tkFinally: - b = newNodeP(nkFinally, p) - getTok(p) - else: break - skipComment(p, b) - addSon(b, parseCurlyStmt(p)) - addSon(result, b) - if b.kind == nkFinally: break - if b == nil: parMessage(p, errTokenExpected, "except") - -proc parseFor(p: var TParser): PNode = - #| forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt - result = newNodeP(nkForStmt, p) - getTokNoInd(p) - var a = identWithPragma(p) - addSon(result, a) - while p.tok.tokType == tkComma: - getTok(p) - optInd(p, a) - a = identWithPragma(p) - addSon(result, a) - eat(p, tkIn) - addSon(result, parseExpr(p)) - colcom(p, result) - addSon(result, parseCurlyStmt(p)) - -proc parseBlock(p: var TParser): PNode = - #| blockStmt = 'block' symbol? colcom stmt - result = newNodeP(nkBlockStmt, p) - getTokNoInd(p) - if p.tok.tokType == tkCurlyLe: addSon(result, ast.emptyNode) - else: addSon(result, parseSymbol(p)) - colcom(p, result) - addSon(result, parseCurlyStmt(p)) - -proc parseStaticOrDefer(p: var TParser; k: TNodeKind): PNode = - #| staticStmt = 'static' colcom stmt - #| deferStmt = 'defer' colcom stmt - result = newNodeP(k, p) - getTok(p) - colcom(p, result) - addSon(result, parseCurlyStmt(p)) - -proc parseAsm(p: var TParser): PNode = - #| asmStmt = 'asm' pragma? (STR_LIT | RSTR_LIT | TRIPLE_STR_LIT) - result = newNodeP(nkAsmStmt, p) - getTokNoInd(p) - if p.tok.tokType == tkCurlyDotLe or isAt(p.tok): addSon(result, parsePragma(p)) - else: addSon(result, ast.emptyNode) - case p.tok.tokType - of tkStrLit: addSon(result, newStrNodeP(nkStrLit, p.tok.literal, p)) - of tkRStrLit: addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p)) - of tkTripleStrLit: addSon(result, - newStrNodeP(nkTripleStrLit, p.tok.literal, p)) - else: - parMessage(p, errStringLiteralExpected) - addSon(result, ast.emptyNode) - return - getTok(p) - -proc parseGenericParam(p: var TParser): PNode = - #| genericParam = symbol (comma symbol)* (colon expr)? ('=' optInd expr)? - var a: PNode - result = newNodeP(nkIdentDefs, p) - while true: - case p.tok.tokType - of tkIn, tkOut: - let t = p.tok.tokType - getTok(p) - expectIdent(p) - a = parseSymbol(p) - of tkSymbol, tkAccent: - a = parseSymbol(p) - if a.kind == nkEmpty: return - else: break - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, a) - if p.tok.tokType == tkColon: - getTok(p) - optInd(p, result) - addSon(result, parseExpr(p)) - else: - addSon(result, ast.emptyNode) - if p.tok.tokType == tkEquals: - getTok(p) - optInd(p, result) - addSon(result, parseExpr(p)) - else: - addSon(result, ast.emptyNode) - -proc parseGenericParamList(p: var TParser): PNode = - #| genericParamList = '[' optInd - #| genericParam ^* (comma/semicolon) optPar ']' - result = newNodeP(nkGenericParams, p) - getTok(p) - optInd(p, result) - while p.tok.tokType in {tkSymbol, tkAccent}: - var a = parseGenericParam(p) - addSon(result, a) - if p.tok.tokType notin {tkComma, tkSemiColon}: break - getTok(p) - skipComment(p, a) - optPar(p) - eat(p, tkBracketRi) - -proc parsePattern(p: var TParser): PNode = - eat(p, tkBracketDotLe) - result = parseStmt(p) - eat(p, tkBracketDotRi) - -proc validInd(p: TParser): bool = p.tok.indent < 0 - -proc parseRoutine(p: var TParser, kind: TNodeKind): PNode = - #| indAndComment = (IND{>} COMMENT)? | COMMENT? - #| routine = optInd identVis pattern? genericParamList? - #| paramListColon pragma? ('=' COMMENT? stmt)? indAndComment - result = newNodeP(kind, p) - getTok(p) - optInd(p, result) - addSon(result, identVis(p)) - if p.tok.tokType == tkBracketDotLe and p.validInd: - addSon(result, p.parsePattern) - else: - addSon(result, ast.emptyNode) - if p.tok.tokType == tkBracketLe and p.validInd: - result.add(p.parseGenericParamList) - else: - addSon(result, ast.emptyNode) - addSon(result, p.parseParamList) - if (p.tok.tokType == tkCurlyDotLe or isAt(p.tok)) and p.validInd: - addSon(result, p.parsePragma) - else: - addSon(result, ast.emptyNode) - # empty exception tracking: - addSon(result, ast.emptyNode) - if p.tok.tokType == tkCurlyLe: - addSon(result, parseCurlyStmt(p)) - else: - addSon(result, ast.emptyNode) - indAndComment(p, result) - -proc newCommentStmt(p: var TParser): PNode = - #| commentStmt = COMMENT - result = newNodeP(nkCommentStmt, p) - result.comment = p.tok.literal - getTok(p) - -type - TDefParser = proc (p: var TParser): PNode {.nimcall.} - -proc parseSection(p: var TParser, kind: TNodeKind, - defparser: TDefParser): PNode = - #| section(p) = COMMENT? p / (IND{>} (p / COMMENT)^+IND{=} DED) - result = newNodeP(kind, p) - if kind != nkTypeSection: getTok(p) - skipComment(p, result) - if p.tok.tokType == tkParLe: - getTok(p) - skipComment(p, result) - while true: - case p.tok.tokType - of tkSymbol, tkAccent, tkParLe: - var a = defparser(p) - skipComment(p, a) - addSon(result, a) - of tkComment: - var a = newCommentStmt(p) - addSon(result, a) - of tkParRi: break - else: - parMessage(p, errIdentifierExpected, p.tok) - break - eat(p, tkParRi) - if result.len == 0: parMessage(p, errIdentifierExpected, p.tok) - elif p.tok.tokType in {tkSymbol, tkAccent, tkBracketLe}: - # tkBracketLe is allowed for ``var [x, y] = ...`` tuple parsing - addSon(result, defparser(p)) - else: - parMessage(p, errIdentifierExpected, p.tok) - -proc parseConstant(p: var TParser): PNode = - #| constant = identWithPragma (colon typedesc)? '=' optInd expr indAndComment - result = newNodeP(nkConstDef, p) - addSon(result, identWithPragma(p)) - if p.tok.tokType == tkColon: - getTok(p) - optInd(p, result) - addSon(result, parseTypeDesc(p)) - else: - addSon(result, ast.emptyNode) - eat(p, tkEquals) - optInd(p, result) - addSon(result, parseExpr(p)) - indAndComment(p, result) - -proc parseEnum(p: var TParser): PNode = - #| enum = 'enum' optInd (symbol optInd ('=' optInd expr COMMENT?)? comma?)+ - result = newNodeP(nkEnumTy, p) - getTok(p) - addSon(result, ast.emptyNode) - optInd(p, result) - flexComment(p, result) - eat(p, tkCurlyLe) - optInd(p, result) - while p.tok.tokType notin {tkEof, tkCurlyRi}: - var a = parseSymbol(p) - if a.kind == nkEmpty: return - if p.tok.tokType == tkEquals: - getTok(p) - optInd(p, a) - var b = a - a = newNodeP(nkEnumFieldDef, p) - addSon(a, b) - addSon(a, parseExpr(p)) - if p.tok.indent < 0: - rawSkipComment(p, a) - if p.tok.tokType == tkComma: - getTok(p) - rawSkipComment(p, a) - addSon(result, a) - eat(p, tkCurlyRi) - if result.len <= 1: - lexMessageTok(p.lex, errIdentifierExpected, p.tok, prettyTok(p.tok)) - -proc parseObjectPart(p: var TParser; needsCurly: bool): PNode -proc parseObjectWhen(p: var TParser): PNode = - result = newNodeP(nkRecWhen, p) - while true: - getTok(p) # skip `when`, `elif` - var branch = newNodeP(nkElifBranch, p) - optInd(p, branch) - addSon(branch, parseExpr(p)) - colcom(p, branch) - addSon(branch, parseObjectPart(p, true)) - flexComment(p, branch) - addSon(result, branch) - if p.tok.tokType != tkElif: break - if p.tok.tokType == tkElse: - var branch = newNodeP(nkElse, p) - eat(p, tkElse) - colcom(p, branch) - addSon(branch, parseObjectPart(p, true)) - flexComment(p, branch) - addSon(result, branch) - -proc parseObjectCase(p: var TParser): PNode = - result = newNodeP(nkRecCase, p) - getTokNoInd(p) - var a = newNodeP(nkIdentDefs, p) - addSon(a, identWithPragma(p)) - eat(p, tkColon) - addSon(a, parseTypeDesc(p)) - addSon(a, ast.emptyNode) - addSon(result, a) - eat(p, tkCurlyLe) - flexComment(p, result) - while true: - var b: PNode - case p.tok.tokType - of tkOf: - b = newNodeP(nkOfBranch, p) - exprList(p, tkColon, b) - of tkElse: - b = newNodeP(nkElse, p) - getTok(p) - else: break - colcom(p, b) - var fields = parseObjectPart(p, true) - if fields.kind == nkEmpty: - parMessage(p, errIdentifierExpected, p.tok) - fields = newNodeP(nkNilLit, p) # don't break further semantic checking - addSon(b, fields) - addSon(result, b) - if b.kind == nkElse: break - eat(p, tkCurlyRi) - -proc parseObjectPart(p: var TParser; needsCurly: bool): PNode = - if p.tok.tokType == tkCurlyLe: - result = newNodeP(nkRecList, p) - getTok(p) - rawSkipComment(p, result) - while true: - case p.tok.tokType - of tkCase, tkWhen, tkSymbol, tkAccent, tkNil, tkDiscard: - addSon(result, parseObjectPart(p, false)) - of tkCurlyRi: break - else: - parMessage(p, errIdentifierExpected, p.tok) - break - eat(p, tkCurlyRi) - else: - if needsCurly: - parMessage(p, errTokenExpected, "{") - case p.tok.tokType - of tkWhen: - result = parseObjectWhen(p) - of tkCase: - result = parseObjectCase(p) - of tkSymbol, tkAccent: - result = parseIdentColonEquals(p, {withPragma}) - if p.tok.indent < 0: rawSkipComment(p, result) - of tkNil, tkDiscard: - result = newNodeP(nkNilLit, p) - getTok(p) - else: - result = ast.emptyNode - -proc parseObject(p: var TParser): PNode = - result = newNodeP(nkObjectTy, p) - getTok(p) - if (p.tok.tokType == tkCurlyDotLe or isAt(p.tok)) and p.validInd: - addSon(result, parsePragma(p)) - else: - addSon(result, ast.emptyNode) - if p.tok.tokType == tkOf and p.tok.indent < 0: - var a = newNodeP(nkOfInherit, p) - getTok(p) - addSon(a, parseTypeDesc(p)) - addSon(result, a) - else: - addSon(result, ast.emptyNode) - skipComment(p, result) - # an initial IND{>} HAS to follow: - addSon(result, parseObjectPart(p, true)) - -proc parseTypeClassParam(p: var TParser): PNode = - if p.tok.tokType in {tkOut, tkVar}: - result = newNodeP(nkVarTy, p) - getTok(p) - result.addSon(p.parseSymbol) - else: - result = p.parseSymbol - -proc parseTypeClass(p: var TParser): PNode = - #| typeClassParam = ('var' | 'out')? symbol - #| typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')? - #| &IND{>} stmt - result = newNodeP(nkTypeClassTy, p) - getTok(p) - var args = newNodeP(nkArgList, p) - addSon(result, args) - addSon(args, p.parseTypeClassParam) - while p.tok.tokType == tkComma: - getTok(p) - addSon(args, p.parseTypeClassParam) - if (p.tok.tokType == tkCurlyDotLe or isAt(p.tok)) and p.validInd: - addSon(result, parsePragma(p)) - else: - addSon(result, ast.emptyNode) - if p.tok.tokType == tkOf and p.tok.indent < 0: - var a = newNodeP(nkOfInherit, p) - getTok(p) - while true: - addSon(a, parseTypeDesc(p)) - if p.tok.tokType != tkComma: break - getTok(p) - addSon(result, a) - else: - addSon(result, ast.emptyNode) - if p.tok.tokType == tkComment: - skipComment(p, result) - addSon(result, parseCurlyStmt(p)) - -proc parseTypeDef(p: var TParser): PNode = - #| - #| typeDef = identWithPragmaDot genericParamList? '=' optInd typeDefAux - #| indAndComment? - result = newNodeP(nkTypeDef, p) - addSon(result, identWithPragma(p, allowDot=true)) - if p.tok.tokType == tkBracketLe and p.validInd: - addSon(result, parseGenericParamList(p)) - else: - addSon(result, ast.emptyNode) - if p.tok.tokType == tkEquals: - getTok(p) - optInd(p, result) - addSon(result, parseTypeDefAux(p)) - else: - addSon(result, ast.emptyNode) - indAndComment(p, result) # special extension! - -proc parseVarTuple(p: var TParser): PNode = - #| varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr - result = newNodeP(nkVarTuple, p) - getTok(p) # skip '(' - optInd(p, result) - while p.tok.tokType in {tkSymbol, tkAccent}: - var a = identWithPragma(p) - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - skipComment(p, a) - addSon(result, ast.emptyNode) # no type desc - optPar(p) - eat(p, tkBracketRi) - eat(p, tkEquals) - optInd(p, result) - addSon(result, parseExpr(p)) - -proc parseVariable(p: var TParser): PNode = - #| variable = (varTuple / identColonEquals) indAndComment - if p.tok.tokType == tkBracketLe: result = parseVarTuple(p) - else: result = parseIdentColonEquals(p, {withPragma}) - indAndComment(p, result) - -proc parseBind(p: var TParser, k: TNodeKind): PNode = - #| bindStmt = 'bind' optInd qualifiedIdent ^+ comma - #| mixinStmt = 'mixin' optInd qualifiedIdent ^+ comma - result = newNodeP(k, p) - getTok(p) - optInd(p, result) - while true: - var a = qualifiedIdent(p) - addSon(result, a) - if p.tok.tokType != tkComma: break - getTok(p) - optInd(p, a) - -proc parseStmtPragma(p: var TParser): PNode = - result = parsePragma(p) - if p.tok.tokType == tkCurlyLe: - let a = result - result = newNodeI(nkPragmaBlock, a.info) - getTok(p) - skipComment(p, result) - result.add a - result.add parseStmt(p) - eat(p, tkCurlyRi) - -proc simpleStmt(p: var TParser): PNode = - case p.tok.tokType - of tkReturn: result = parseReturnOrRaise(p, nkReturnStmt) - of tkRaise: result = parseReturnOrRaise(p, nkRaiseStmt) - of tkYield: result = parseReturnOrRaise(p, nkYieldStmt) - of tkDiscard: result = parseReturnOrRaise(p, nkDiscardStmt) - of tkBreak: result = parseReturnOrRaise(p, nkBreakStmt) - of tkContinue: result = parseReturnOrRaise(p, nkContinueStmt) - of tkCurlyDotLe: result = parseStmtPragma(p) - of tkImport: result = parseImport(p, nkImportStmt) - of tkExport: result = parseImport(p, nkExportStmt) - of tkFrom: result = parseFromStmt(p) - of tkInclude: result = parseIncludeStmt(p) - of tkComment: result = newCommentStmt(p) - else: - if isExprStart(p): result = parseExprStmt(p) - else: result = ast.emptyNode - if result.kind notin {nkEmpty, nkCommentStmt}: skipComment(p, result) - -proc complexOrSimpleStmt(p: var TParser): PNode = - case p.tok.tokType - of tkIf: result = parseIfOrWhen(p, nkIfStmt) - of tkWhile: result = parseWhile(p) - of tkCase: result = parseCase(p) - of tkTry: result = parseTry(p) - of tkFor: result = parseFor(p) - of tkBlock: result = parseBlock(p) - of tkStatic: result = parseStaticOrDefer(p, nkStaticStmt) - of tkDefer: result = parseStaticOrDefer(p, nkDefer) - of tkAsm: result = parseAsm(p) - of tkProc: result = parseRoutine(p, nkProcDef) - of tkMethod: result = parseRoutine(p, nkMethodDef) - of tkIterator: result = parseRoutine(p, nkIteratorDef) - of tkMacro: result = parseRoutine(p, nkMacroDef) - of tkTemplate: result = parseRoutine(p, nkTemplateDef) - of tkConverter: result = parseRoutine(p, nkConverterDef) - of tkType: - getTok(p) - if p.tok.tokType == tkBracketLe: - getTok(p) - result = newNodeP(nkTypeOfExpr, p) - result.addSon(primary(p, pmTypeDesc)) - eat(p, tkBracketRi) - result = parseOperators(p, result, -1, pmNormal) - else: - result = parseSection(p, nkTypeSection, parseTypeDef) - of tkConst: result = parseSection(p, nkConstSection, parseConstant) - of tkLet: result = parseSection(p, nkLetSection, parseVariable) - of tkWhen: result = parseIfOrWhen(p, nkWhenStmt) - of tkVar: result = parseSection(p, nkVarSection, parseVariable) - of tkBind: result = parseBind(p, nkBindStmt) - of tkMixin: result = parseBind(p, nkMixinStmt) - of tkUsing: result = parseSection(p, nkUsingStmt, parseVariable) - else: result = simpleStmt(p) - -proc parseStmt(p: var TParser): PNode = - result = complexOrSimpleStmt(p) - -proc parseAll*(p: var TParser): PNode = - ## Parses the rest of the input stream held by the parser into a PNode. - result = newNodeP(nkStmtList, p) - while p.tok.tokType != tkEof: - var a = complexOrSimpleStmt(p) - if a.kind != nkEmpty: - addSon(result, a) - else: - parMessage(p, errExprExpected, p.tok) - # bugfix: consume a token here to prevent an endless loop: - getTok(p) - -proc parseTopLevelStmt*(p: var TParser): PNode = - ## Implements an iterator which, when called repeatedly, returns the next - ## top-level statement or emptyNode if end of stream. - result = ast.emptyNode - while true: - case p.tok.tokType - of tkSemiColon: getTok(p) - of tkEof: break - else: - result = complexOrSimpleStmt(p) - if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok) - break diff --git a/compiler/reorder.nim b/compiler/reorder.nim index 56d8d5886..2542a08ea 100644 --- a/compiler/reorder.nim +++ b/compiler/reorder.nim @@ -137,7 +137,7 @@ proc hasIncludes(n:PNode): bool = proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex; cache: IdentCache): PNode {.procvar.} = - result = syntaxes.parseFile(fileIdx, cache) + result = syntaxes.parseFile(fileIdx, cache, graph.config) graph.addDep(s, fileIdx) graph.addIncludeDep(FileIndex s.position, fileIdx) @@ -273,9 +273,9 @@ proc hasCommand(n: PNode): bool = of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse, nkStaticStmt, nkLetSection, nkConstSection, nkVarSection, nkIdentDefs: - for a in n: - if a.hasCommand: - return true + for a in n: + if a.hasCommand: + return true else: return false diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index c533f4cb4..6ef42f15e 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -28,7 +28,7 @@ proc listDirs(a: VmArgs, filter: set[PathComponent]) = proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; config: ConfigRef): PEvalContext = # For Nimble we need to export 'setupVM'. - result = newCtx(module, cache) + result = newCtx(module, cache, config) result.mode = emRepl registerAdditionalOps(result) diff --git a/compiler/sem.nim b/compiler/sem.nim index 52282d0e4..d8e5b7f20 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -313,7 +313,7 @@ proc tryConstExpr(c: PContext, n: PNode): PNode = msgs.gErrorMax = high(int) try: - result = evalConstExpr(c.module, c.cache, e) + result = evalConstExpr(c.module, c.cache, c.graph.config, e) if result == nil or result.kind == nkEmpty: result = nil else: @@ -334,7 +334,7 @@ proc semConstExpr(c: PContext, n: PNode): PNode = result = getConstExpr(c.module, e) if result == nil: #if e.kind == nkEmpty: globalError(n.info, errConstExprExpected) - result = evalConstExpr(c.module, c.cache, e) + result = evalConstExpr(c.module, c.cache, c.graph.config, e) if result == nil or result.kind == nkEmpty: if e.info != n.info: pushInfoContext(n.info) @@ -439,7 +439,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, #if c.evalContext == nil: # c.evalContext = c.createEvalContext(emStatic) - result = evalMacroCall(c.module, c.cache, n, nOrig, sym) + result = evalMacroCall(c.module, c.cache, c.graph.config, n, nOrig, sym) if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, sym, flags) result = wrapInComesFrom(nOrig.info, sym, result) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index feca087fc..4a3672aa0 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -605,12 +605,12 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = call.add(a) #echo "NOW evaluating at compile time: ", call.renderTree if sfCompileTime in callee.flags: - result = evalStaticExpr(c.module, c.cache, call, c.p.owner) + result = evalStaticExpr(c.module, c.cache, c.graph.config, call, c.p.owner) if result.isNil: localError(n.info, errCannotInterpretNodeX, renderTree(call)) else: result = fixupTypeAfterEval(c, result, n) else: - result = evalConstExpr(c.module, c.cache, call) + result = evalConstExpr(c.module, c.cache, c.graph.config, call) if result.isNil: result = n else: result = fixupTypeAfterEval(c, result, n) #if result != n: @@ -619,7 +619,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = proc semStaticExpr(c: PContext, n: PNode): PNode = let a = semExpr(c, n.sons[0]) if a.findUnresolvedStatic != nil: return a - result = evalStaticExpr(c.module, c.cache, a, c.p.owner) + result = evalStaticExpr(c.module, c.cache, c.graph.config, a, c.p.owner) if result.isNil: localError(n.info, errCannotInterpretNodeX, renderTree(n)) result = emptyNode diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f5fdc3445..b0bd4e0f6 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -545,7 +545,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = b.sons[j] = newSymNode(v) checkNilable(v) if sfCompileTime in v.flags: hasCompileTime = true - if hasCompileTime: vm.setupCompileTimeVar(c.module, c.cache, result) + if hasCompileTime: + vm.setupCompileTimeVar(c.module, c.cache, c.graph.config, result) proc semConst(c: PContext, n: PNode): PNode = result = copyNode(n) @@ -1755,7 +1756,7 @@ proc semStaticStmt(c: PContext, n: PNode): PNode = #writeStackTrace() let a = semStmt(c, n.sons[0]) n.sons[0] = a - evalStaticStmt(c.module, c.cache, a, c.p.owner) + evalStaticStmt(c.module, c.cache, c.graph.config, a, c.p.owner) result = newNodeI(nkDiscardStmt, n.info, 1) result.sons[0] = emptyNode diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index 5413565e6..974df50fb 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -11,17 +11,17 @@ import strutils, llstream, ast, astalgo, idents, lexer, options, msgs, parser, - pbraces, filters, filter_tmpl, renderer + filters, filter_tmpl, renderer type TFilterKind* = enum filtNone, filtTemplate, filtReplace, filtStrip TParserKind* = enum - skinStandard, skinStrongSpaces, skinBraces, skinEndX + skinStandard, skinStrongSpaces, skinEndX const parserNames*: array[TParserKind, string] = ["standard", "strongspaces", - "braces", "endx"] + "endx"] filterNames*: array[TFilterKind, string] = ["none", "stdtmpl", "replace", "strip"] @@ -34,8 +34,6 @@ proc parseAll*(p: var TParsers): PNode = case p.skin of skinStandard, skinStrongSpaces: result = parser.parseAll(p.parser) - of skinBraces: - result = pbraces.parseAll(p.parser) of skinEndX: internalError("parser to implement") result = ast.emptyNode @@ -44,8 +42,6 @@ proc parseTopLevelStmt*(p: var TParsers): PNode = case p.skin of skinStandard, skinStrongSpaces: result = parser.parseTopLevelStmt(p.parser) - of skinBraces: - result = pbraces.parseTopLevelStmt(p.parser) of skinEndX: internalError("parser to implement") result = ast.emptyNode @@ -62,7 +58,8 @@ proc containsShebang(s: string, i: int): bool = while j < s.len and s[j] in Whitespace: inc(j) result = s[j] == '/' -proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache): PNode = +proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache; + config: ConfigRef): PNode = result = ast.emptyNode var s = llStreamOpen(filename, fmRead) if s != nil: @@ -78,7 +75,7 @@ proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache): PNo inc(i, 2) while i < line.len and line[i] in Whitespace: inc(i) var q: TParser - parser.openParser(q, filename, llStreamOpen(substr(line, i)), cache) + parser.openParser(q, filename, llStreamOpen(substr(line, i)), cache, config) result = parser.parseAll(q) parser.closeParser(q) llStreamClose(s) @@ -139,23 +136,23 @@ proc evalPipe(p: var TParsers, n: PNode, filename: string, result = applyFilter(p, n, filename, result) proc openParsers*(p: var TParsers, fileIdx: FileIndex, inputstream: PLLStream; - cache: IdentCache) = + cache: IdentCache; config: ConfigRef) = var s: PLLStream p.skin = skinStandard let filename = fileIdx.toFullPathConsiderDirty - var pipe = parsePipe(filename, inputstream, cache) + var pipe = parsePipe(filename, inputstream, cache, config) if pipe != nil: s = evalPipe(p, pipe, filename, inputstream) else: s = inputstream case p.skin - of skinStandard, skinBraces, skinEndX: - parser.openParser(p.parser, fileIdx, s, cache, false) + of skinStandard, skinEndX: + parser.openParser(p.parser, fileIdx, s, cache, config, false) of skinStrongSpaces: - parser.openParser(p.parser, fileIdx, s, cache, true) + parser.openParser(p.parser, fileIdx, s, cache, config, true) proc closeParsers*(p: var TParsers) = parser.closeParser(p.parser) -proc parseFile*(fileIdx: FileIndex; cache: IdentCache): PNode {.procvar.} = +proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode {.procvar.} = var p: TParsers f: File @@ -163,6 +160,6 @@ proc parseFile*(fileIdx: FileIndex; cache: IdentCache): PNode {.procvar.} = if not open(f, filename): rawMessage(errCannotOpenFile, filename) return - openParsers(p, fileIdx, llStreamOpen(f), cache) + openParsers(p, fileIdx, llStreamOpen(f), cache, config) result = parseAll(p) closeParsers(p) diff --git a/compiler/vm.nim b/compiler/vm.nim index 32db8f378..6c36a1458 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1341,8 +1341,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = decodeB(rkNode) # c.debug[pc].line.int - countLines(regs[rb].strVal) ? var error: string - let ast = parseString(regs[rb].node.strVal, c.cache, c.debug[pc].toFullPath, - c.debug[pc].line.int, + let ast = parseString(regs[rb].node.strVal, c.cache, c.config, + c.debug[pc].toFullPath, c.debug[pc].line.int, proc (info: TLineInfo; msg: TMsgKind; arg: string) = if error.isNil and msg <= msgs.errMax: error = formatMsg(info, msg, arg)) @@ -1355,8 +1355,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcParseStmtToAst: decodeB(rkNode) var error: string - let ast = parseString(regs[rb].node.strVal, c.cache, c.debug[pc].toFullPath, - c.debug[pc].line.int, + let ast = parseString(regs[rb].node.strVal, c.cache, c.config, + c.debug[pc].toFullPath, c.debug[pc].line.int, proc (info: TLineInfo; msg: TMsgKind; arg: string) = if error.isNil and msg <= msgs.errMax: error = formatMsg(info, msg, arg)) @@ -1643,9 +1643,9 @@ include vmops var globalCtx*: PCtx -proc setupGlobalCtx(module: PSym; cache: IdentCache) = +proc setupGlobalCtx(module: PSym; cache: IdentCache; config: ConfigRef) = if globalCtx.isNil: - globalCtx = newCtx(module, cache) + globalCtx = newCtx(module, cache, config) registerAdditionalOps(globalCtx) else: refresh(globalCtx, module) @@ -1656,7 +1656,7 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = #pushStackFrame(c, newStackFrame()) # XXX produce a new 'globals' environment here: - setupGlobalCtx(module, cache) + setupGlobalCtx(module, cache, graph.config) result = globalCtx when hasFFI: globalCtx.features = {allowFFI, allowCast} @@ -1677,10 +1677,11 @@ proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode = const evalPass* = makePass(myOpen, nil, myProcess, myClose) -proc evalConstExprAux(module: PSym; cache: IdentCache; prc: PSym, n: PNode, +proc evalConstExprAux(module: PSym; cache: IdentCache; + config: ConfigRef; prc: PSym, n: PNode, mode: TEvalMode): PNode = let n = transformExpr(module, n) - setupGlobalCtx(module, cache) + setupGlobalCtx(module, cache, config) var c = globalCtx let oldMode = c.mode defer: c.mode = oldMode @@ -1695,17 +1696,17 @@ proc evalConstExprAux(module: PSym; cache: IdentCache; prc: PSym, n: PNode, result = rawExecute(c, start, tos).regToNode if result.info.col < 0: result.info = n.info -proc evalConstExpr*(module: PSym; cache: IdentCache, e: PNode): PNode = - result = evalConstExprAux(module, cache, nil, e, emConst) +proc evalConstExpr*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode): PNode = + result = evalConstExprAux(module, cache, config, nil, e, emConst) -proc evalStaticExpr*(module: PSym; cache: IdentCache, e: PNode, prc: PSym): PNode = - result = evalConstExprAux(module, cache, prc, e, emStaticExpr) +proc evalStaticExpr*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode, prc: PSym): PNode = + result = evalConstExprAux(module, cache, config, prc, e, emStaticExpr) -proc evalStaticStmt*(module: PSym; cache: IdentCache, e: PNode, prc: PSym) = - discard evalConstExprAux(module, cache, prc, e, emStaticStmt) +proc evalStaticStmt*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode, prc: PSym) = + discard evalConstExprAux(module, cache, config, prc, e, emStaticStmt) -proc setupCompileTimeVar*(module: PSym; cache: IdentCache, n: PNode) = - discard evalConstExprAux(module, cache, nil, n, emStaticStmt) +proc setupCompileTimeVar*(module: PSym; cache: IdentCache, config: ConfigRef; n: PNode) = + discard evalConstExprAux(module, cache, config, nil, n, emStaticStmt) proc setupMacroParam(x: PNode, typ: PType): TFullReg = case typ.kind @@ -1733,8 +1734,8 @@ iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) = const evalMacroLimit = 1000 var evalMacroCounter: int -proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode, - sym: PSym): PNode = +proc evalMacroCall*(module: PSym; cache: IdentCache; config: ConfigRef; + n, nOrig: PNode, sym: PSym): PNode = # XXX globalError() is ugly here, but I don't know a better solution for now inc(evalMacroCounter) if evalMacroCounter > evalMacroLimit: @@ -1746,7 +1747,7 @@ proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode, globalError(n.info, "in call '$#' got $#, but expected $# argument(s)" % [ n.renderTree, $(n.safeLen-1), $(sym.typ.len-1)]) - setupGlobalCtx(module, cache) + setupGlobalCtx(module, cache, config) var c = globalCtx c.comesFromHeuristic.line = 0'u16 diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 66bc8dfd2..b0a559d2c 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -10,7 +10,7 @@ ## This module contains the type definitions for the new evaluation engine. ## An instruction is 1-3 int32s in memory, it is a register based VM. -import ast, passes, msgs, idents, intsets +import ast, passes, msgs, idents, intsets, options const byteExcess* = 128 # we use excess-K for immediates @@ -206,17 +206,19 @@ type callbacks*: seq[tuple[key: string, value: VmCallback]] errorFlag*: string cache*: IdentCache + config*: ConfigRef TPosition* = distinct int PEvalContext* = PCtx -proc newCtx*(module: PSym; cache: IdentCache): PCtx = +proc newCtx*(module: PSym; cache: IdentCache; config: ConfigRef = nil): PCtx = + let conf = if config != nil: config else: newConfigRef() PCtx(code: @[], debug: @[], globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[], prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations, comesFromHeuristic: unknownLineInfo(), callbacks: @[], errorFlag: "", - cache: cache) + cache: cache, config: conf) proc refresh*(c: PCtx, module: PSym) = c.module = module -- cgit 1.4.1-2-gfad0 From fedc136985948a5b011a74ef49f97e43f2a3fe72 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 12 May 2018 09:38:41 +0200 Subject: transf and vmgen compile again --- compiler/destroyer.nim | 49 ++++++------ compiler/dfa.nim | 14 ++-- compiler/gorgeimpl.nim | 4 +- compiler/liftlocals.nim | 6 +- compiler/transf.nim | 89 +++++++++++---------- compiler/vmdef.nim | 8 +- compiler/vmdeps.nim | 10 +-- compiler/vmgen.nim | 204 ++++++++++++++++++++++++------------------------ compiler/vmmarshal.nim | 73 +++++++++-------- 9 files changed, 234 insertions(+), 223 deletions(-) (limited to 'compiler/vmdef.nim') diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim index cd16469de..31c735794 100644 --- a/compiler/destroyer.nim +++ b/compiler/destroyer.nim @@ -116,7 +116,8 @@ Remarks: Rule 1.2 is not yet implemented because ``sink`` is currently import intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, - strutils, options, dfa, lowerings, rodread, tables + strutils, options, dfa, lowerings, rodread, tables, modulegraphs, + configuration const InterestingSyms = {skVar, skResult, skLet} @@ -130,6 +131,7 @@ type tmp: PSym destroys, topLevelVars: PNode toDropBit: Table[int, PSym] + graph: ModuleGraph proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode = # XXX why are temps fields in an object here? @@ -222,21 +224,21 @@ proc patchHead(s: PSym) = template genOp(opr, opname) = let op = opr if op == nil: - globalError(dest.info, "internal error: '" & opname & "' operator not found for type " & typeToString(t)) + globalError(c.graph.config, dest.info, "internal error: '" & opname & "' operator not found for type " & typeToString(t)) elif op.ast[genericParamsPos].kind != nkEmpty: - globalError(dest.info, "internal error: '" & opname & "' operator is generic") + globalError(c.graph.config, dest.info, "internal error: '" & opname & "' operator is generic") patchHead op result = newTree(nkCall, newSymNode(op), newTree(nkHiddenAddr, dest)) -proc genSink(t: PType; dest: PNode): PNode = +proc genSink(c: Con; t: PType; dest: PNode): PNode = let t = t.skipTypes({tyGenericInst, tyAlias, tySink}) genOp(if t.sink != nil: t.sink else: t.assignment, "=sink") -proc genCopy(t: PType; dest: PNode): PNode = +proc genCopy(c: Con; t: PType; dest: PNode): PNode = let t = t.skipTypes({tyGenericInst, tyAlias, tySink}) genOp(t.assignment, "=") -proc genDestroy(t: PType; dest: PNode): PNode = +proc genDestroy(c: Con; t: PType; dest: PNode): PNode = let t = t.skipTypes({tyGenericInst, tyAlias, tySink}) genOp(t.destructor, "=destroy") @@ -249,14 +251,14 @@ proc dropBit(c: var Con; s: PSym): PSym = proc registerDropBit(c: var Con; s: PSym) = let result = newSym(skTemp, getIdent(s.name.s & "_AliveBit"), c.owner, s.info) - result.typ = getSysType(tyBool) + result.typ = getSysType(c.graph, s.info, tyBool) let trueVal = newIntTypeNode(nkIntLit, 1, result.typ) c.topLevelVars.add newTree(nkIdentDefs, newSymNode result, emptyNode, trueVal) c.toDropBit[s.id] = result # generate: # if not sinkParam_AliveBit: `=destroy`(sinkParam) c.destroys.add newTree(nkIfStmt, - newTree(nkElifBranch, newSymNode result, genDestroy(s.typ, newSymNode s))) + newTree(nkElifBranch, newSymNode result, genDestroy(c, s.typ, newSymNode s))) proc p(n: PNode; c: var Con): PNode @@ -274,36 +276,36 @@ proc destructiveMoveSink(n: PNode; c: var Con): PNode = result = newNodeIT(nkStmtListExpr, n.info, n.typ) let bit = newSymNode dropBit(c, n.sym) if optMoveCheck in c.owner.options: - result.add callCodegenProc("chckMove", bit) + result.add callCodegenProc(c.graph, "chckMove", bit) result.add newTree(nkAsgn, bit, - newIntTypeNode(nkIntLit, 0, getSysType(tyBool))) + newIntTypeNode(nkIntLit, 0, getSysType(c.graph, n.info, tyBool))) result.add n proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = if ri.kind in constrExprs: - result = genSink(ri.typ, dest) + result = genSink(c, ri.typ, dest) # watch out and no not transform 'ri' twice if it's a call: let ri2 = copyNode(ri) recurse(ri, ri2) result.add ri2 elif ri.kind == nkSym and isHarmlessVar(ri.sym, c): - result = genSink(ri.typ, dest) + result = genSink(c, ri.typ, dest) result.add p(ri, c) elif ri.kind == nkSym and isSinkParam(ri.sym): - result = genSink(ri.typ, dest) + result = genSink(c, ri.typ, dest) result.add destructiveMoveSink(ri, c) else: - result = genCopy(ri.typ, dest) + result = genCopy(c, ri.typ, dest) result.add p(ri, c) proc passCopyToSink(n: PNode; c: var Con): PNode = result = newNodeIT(nkStmtListExpr, n.info, n.typ) let tmp = getTemp(c, n.typ, n.info) if hasDestructor(n.typ): - var m = genCopy(n.typ, tmp) + var m = genCopy(c, n.typ, tmp) m.add p(n, c) result.add m - message(n.info, hintPerformance, + message(c.graph.config, n.info, hintPerformance, "passing '$1' to a sink parameter introduces an implicit copy; " & "use 'move($1)' to prevent it" % $n) else: @@ -312,7 +314,7 @@ proc passCopyToSink(n: PNode; c: var Con): PNode = proc genReset(n: PNode; c: var Con): PNode = result = newNodeI(nkCall, n.info) - result.add(newSymNode(createMagic("reset", mReset))) + result.add(newSymNode(createMagic(c.graph, "reset", mReset))) # The mReset builtin does not take the address: result.add n @@ -345,7 +347,7 @@ proc p(n: PNode; c: var Con): PNode = let L = it.len-1 let ri = it[L] if it.kind == nkVarTuple and hasDestructor(ri.typ): - let x = lowerTupleUnpacking(it, c.owner) + let x = lowerTupleUnpacking(c.graph, it, c.owner) result.add p(x, c) elif it.kind == nkIdentDefs and hasDestructor(it[0].typ): for j in 0..L-2: @@ -354,7 +356,7 @@ proc p(n: PNode; c: var Con): PNode = # move the variable declaration to the top of the frame: c.addTopVar v # make sure it's destroyed at the end of the proc: - c.destroys.add genDestroy(v.typ, v) + c.destroys.add genDestroy(c, v.typ, v) if ri.kind != nkEmpty: let r = moveOrCopy(v, ri, c) result.add r @@ -400,11 +402,11 @@ proc p(n: PNode; c: var Con): PNode = discard "produce temp creation" result = newNodeIT(nkStmtListExpr, n.info, n.typ) let tmp = getTemp(c, n.typ, n.info) - var sinkExpr = genSink(n.typ, tmp) + var sinkExpr = genSink(c, n.typ, tmp) sinkExpr.add n result.add sinkExpr result.add tmp - c.destroys.add genDestroy(n.typ, tmp) + c.destroys.add genDestroy(c, n.typ, tmp) else: result = n of nkAsgn, nkFastAsgn: @@ -420,17 +422,18 @@ proc p(n: PNode; c: var Con): PNode = result = copyNode(n) recurse(n, result) -proc injectDestructorCalls*(owner: PSym; n: PNode): PNode = +proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode = when defined(nimDebugDestroys): echo "injecting into ", n var c: Con c.owner = owner c.tmp = newSym(skTemp, getIdent":d", owner, n.info) - c.tmpObj = createObj(owner, n.info) + c.tmpObj = createObj(g, owner, n.info) c.tmp.typ = c.tmpObj c.destroys = newNodeI(nkStmtList, n.info) c.topLevelVars = newNodeI(nkVarSection, n.info) c.toDropBit = initTable[int, PSym]() + c.graph = g let cfg = constructCfg(owner, n) shallowCopy(c.g, cfg) c.jumpTargets = initIntSet() diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 0784151af..0fd706178 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -23,7 +23,7 @@ ## "A Graph–Free Approach to Data–Flow Analysis" by Markus Mohnen. ## https://link.springer.com/content/pdf/10.1007/3-540-45937-5_6.pdf -import ast, astalgo, types, intsets, tables, msgs +import ast, astalgo, types, intsets, tables, msgs, options type InstrKind* = enum @@ -160,7 +160,7 @@ proc genBreak(c: var Con; n: PNode) = if c.blocks[i].label == n.sons[0].sym: c.blocks[i].fixups.add L1 return - globalError(n.info, errGenerated, "VM problem: cannot find 'break' target") + #globalError(n.info, "VM problem: cannot find 'break' target") else: c.blocks[c.blocks.high].fixups.add L1 @@ -334,7 +334,7 @@ proc gen(c: var Con; n: PNode) = of nkVarSection, nkLetSection: genVarSection(c, n) else: discard -proc dfa(code: seq[Instr]) = +proc dfa(code: seq[Instr]; conf: ConfigRef) = var u = newSeq[IntSet](code.len) # usages var d = newSeq[IntSet](code.len) # defs var c = newSeq[IntSet](code.len) # consumed @@ -426,17 +426,17 @@ proc dfa(code: seq[Instr]) = of use, useWithinCall: let s = code[i].sym if s.id notin d[i]: - localError(code[i].n.info, "usage of uninitialized variable: " & s.name.s) + localError(conf, code[i].n.info, "usage of uninitialized variable: " & s.name.s) if s.id in c[i]: - localError(code[i].n.info, "usage of an already consumed variable: " & s.name.s) + localError(conf, code[i].n.info, "usage of an already consumed variable: " & s.name.s) else: discard -proc dataflowAnalysis*(s: PSym; body: PNode) = +proc dataflowAnalysis*(s: PSym; body: PNode; conf: ConfigRef) = var c = Con(code: @[], blocks: @[]) gen(c, body) when defined(useDfa) and defined(debugDfa): echoCfg(c.code) - dfa(c.code) + dfa(c.code, conf) proc constructCfg*(s: PSym; body: PNode): ControlFlowGraph = ## constructs a control flow graph for ``body``. diff --git a/compiler/gorgeimpl.nim b/compiler/gorgeimpl.nim index 80302b4b5..44c7651bc 100644 --- a/compiler/gorgeimpl.nim +++ b/compiler/gorgeimpl.nim @@ -21,11 +21,11 @@ proc readOutput(p: Process): (string, int) = result[0].setLen(result[0].len - "\n".len) result[1] = p.waitForExit -proc opGorge*(cmd, input, cache: string, info: TLineInfo): (string, int) = +proc opGorge*(cmd, input, cache: string, info: TLineInfo; conf: ConfigRef): (string, int) = let workingDir = parentDir(info.toFullPath) if cache.len > 0:# and optForceFullMake notin gGlobalOptions: let h = secureHash(cmd & "\t" & input & "\t" & cache) - let filename = options.toGeneratedFile("gorge_" & $h, "txt") + let filename = options.toGeneratedFile(conf, "gorge_" & $h, "txt") var f: File if open(f, filename): result = (f.readAll, 0) diff --git a/compiler/liftlocals.nim b/compiler/liftlocals.nim index 3610a1486..4603d357b 100644 --- a/compiler/liftlocals.nim +++ b/compiler/liftlocals.nim @@ -52,17 +52,17 @@ proc lookupParam(params, dest: PNode): PSym = if params[i].kind == nkSym and params[i].sym.name.id == dest.ident.id: return params[i].sym -proc liftLocalsIfRequested*(prc: PSym; n: PNode): PNode = +proc liftLocalsIfRequested*(prc: PSym; n: PNode; conf: ConfigRef): PNode = let liftDest = getPragmaVal(prc.ast, wLiftLocals) if liftDest == nil: return n let partialParam = lookupParam(prc.typ.n, liftDest) if partialParam.isNil: - localError(liftDest.info, "'$1' is not a parameter of '$2'" % + localError(conf, liftDest.info, "'$1' is not a parameter of '$2'" % [$liftDest, prc.name.s]) return n let objType = partialParam.typ.skipTypes(abstractPtrs) if objType.kind != tyObject or tfPartial notin objType.flags: - localError(liftDest.info, "parameter '$1' is not a pointer to a partial object" % $liftDest) + localError(conf, liftDest.info, "parameter '$1' is not a pointer to a partial object" % $liftDest) return n var c = Ctx(partialParam: partialParam, objType: objType) let w = newTree(nkStmtList, n) diff --git a/compiler/transf.nim b/compiler/transf.nim index f7ec6c97f..e49d51b11 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -21,7 +21,8 @@ import intsets, strutils, options, ast, astalgo, trees, treetab, msgs, os, idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread, - lambdalifting, sempass2, lowerings, lookups, destroyer, liftlocals + lambdalifting, sempass2, lowerings, lookups, destroyer, liftlocals, + modulegraphs type PTransNode* = distinct PNode @@ -44,6 +45,7 @@ type nestedProcs: int # > 0 if we are in a nested proc contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break' deferDetected, tooEarly, needsDestroyPass: bool + graph: ModuleGraph PTransf = ref TTransfContext proc newTransNode(a: PNode): PTransNode {.inline.} = @@ -84,7 +86,7 @@ proc pushTransCon(c: PTransf, t: PTransCon) = c.transCon = t proc popTransCon(c: PTransf) = - if (c.transCon == nil): internalError("popTransCon") + if (c.transCon == nil): internalError(c.graph.config, "popTransCon") c.transCon = c.transCon.next proc getCurrOwner(c: PTransf): PSym = @@ -97,7 +99,7 @@ proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode = incl(r.flags, sfFromGeneric) let owner = getCurrOwner(c) if owner.isIterator and not c.tooEarly: - result = freshVarForClosureIter(r, owner) + result = freshVarForClosureIter(c.graph, r, owner) else: result = newSymNode(r) @@ -118,10 +120,10 @@ proc transformSymAux(c: PTransf, n: PNode): PNode = if s.typ != nil and s.typ.callConv == ccClosure: if s.kind == skIterator: if c.tooEarly: return n - else: return liftIterSym(n, getCurrOwner(c)) + else: return liftIterSym(c.graph, n, getCurrOwner(c)) elif s.kind in {skProc, skFunc, skConverter, skMethod} and not c.tooEarly: # top level .closure procs are still somewhat supported for 'Nake': - return makeClosure(s, nil, n.info) + return makeClosure(c.graph, s, nil, n.info) #elif n.sym.kind in {skVar, skLet} and n.sym.typ.callConv == ccClosure: # echo n.info, " come heer for ", c.tooEarly # if not c.tooEarly: @@ -130,7 +132,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode = if sfBorrow in s.flags and s.kind in routineKinds: # simply exchange the symbol: b = s.getBody - if b.kind != nkSym: internalError(n.info, "wrong AST for borrowed symbol") + if b.kind != nkSym: internalError(c.graph.config, n.info, "wrong AST for borrowed symbol") b = newSymNode(b.sym, n.info) else: b = n @@ -151,7 +153,7 @@ proc transformSym(c: PTransf, n: PNode): PTransNode = proc freshVar(c: PTransf; v: PSym): PNode = let owner = getCurrOwner(c) if owner.isIterator and not c.tooEarly: - result = freshVarForClosureIter(v, owner) + result = freshVarForClosureIter(c.graph, v, owner) else: var newVar = copySym(v) incl(newVar.flags, sfFromGeneric) @@ -166,11 +168,11 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode = result[i] = PTransNode(it) elif it.kind == nkIdentDefs: if it.sons[0].kind == nkSym: - internalAssert(it.len == 3) + internalAssert(c.graph.config, it.len == 3) let x = freshVar(c, it.sons[0].sym) idNodeTablePut(c.transCon.mapping, it.sons[0].sym, x) var defs = newTransNode(nkIdentDefs, it.info, 3) - if importantComments(): + if importantComments(c.graph.config): # keep documentation information: PNode(defs).comment = it.comment defs[0] = x.PTransNode @@ -184,7 +186,7 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode = result[i] = transform(c, it) else: if it.kind != nkVarTuple: - internalError(it.info, "transformVarSection: not nkVarTuple") + internalError(c.graph.config, it.info, "transformVarSection: not nkVarTuple") var L = sonsLen(it) var defs = newTransNode(it.kind, it.info, L) for j in countup(0, L-3): @@ -203,9 +205,9 @@ proc transformConstSection(c: PTransf, v: PNode): PTransNode = if it.kind == nkCommentStmt: result[i] = PTransNode(it) else: - if it.kind != nkConstDef: internalError(it.info, "transformConstSection") + if it.kind != nkConstDef: internalError(c.graph.config, it.info, "transformConstSection") if it.sons[0].kind != nkSym: - internalError(it.info, "transformConstSection") + internalError(c.graph.config, it.info, "transformConstSection") result[i] = PTransNode(it) @@ -301,7 +303,7 @@ proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) = # XXX: BUG: what if `n` is an expression with side-effects? for i in countup(0, sonsLen(c.transCon.forStmt) - 3): add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i], - transform(c, newTupleAccess(n, i)))) + transform(c, newTupleAccess(c.graph, n, i)))) proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode = case n.kind @@ -382,7 +384,7 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode = if n.typ.skipTypes(abstractVar).kind != tyOpenArray: PNode(result).typ = n.typ -proc generateThunk(prc: PNode, dest: PType): PNode = +proc generateThunk(c: PTransf; prc: PNode, dest: PType): PNode = ## Converts 'prc' into '(thunk, nil)' so that it's compatible with ## a closure. @@ -394,9 +396,9 @@ proc generateThunk(prc: PNode, dest: PType): PNode = conv.add(emptyNode) conv.add(prc) if prc.kind == nkClosure: - internalError(prc.info, "closure to closure created") + internalError(c.graph.config, prc.info, "closure to closure created") result.add(conv) - result.add(newNodeIT(nkNilLit, prc.info, getSysType(tyNil))) + result.add(newNodeIT(nkNilLit, prc.info, getSysType(c.graph, prc.info, tyNil))) proc transformConv(c: PTransf, n: PNode): PTransNode = # numeric types need range checks: @@ -481,7 +483,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode = of tyProc: result = transformSons(c, n) if dest.callConv == ccClosure and source.callConv == ccDefault: - result = generateThunk(result[1].PNode, dest).PTransNode + result = generateThunk(c, result[1].PNode, dest).PTransNode else: result = transformSons(c, n) @@ -513,7 +515,7 @@ proc findWrongOwners(c: PTransf, n: PNode) = if n.kind == nkVarSection: let x = n.sons[0].sons[0] if x.kind == nkSym and x.sym.owner != getCurrOwner(c): - internalError(x.info, "bah " & x.sym.name.s & " " & + internalError(c.graph.config, x.info, "bah " & x.sym.name.s & " " & x.sym.owner.name.s & " " & getCurrOwner(c).name.s) else: for i in 0 ..< safeLen(n): findWrongOwners(c, n.sons[i]) @@ -521,7 +523,7 @@ proc findWrongOwners(c: PTransf, n: PNode) = proc transformFor(c: PTransf, n: PNode): PTransNode = # generate access statements for the parameters (unless they are constant) # put mapping from formal parameters to actual parameters - if n.kind != nkForStmt: internalError(n.info, "transformFor") + if n.kind != nkForStmt: internalError(c.graph.config, n.info, "transformFor") var length = sonsLen(n) var call = n.sons[length - 2] @@ -539,7 +541,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode = n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode if not c.tooEarly: n.sons[length-2] = transform(c, n.sons[length-2]).PNode - result[1] = lambdalifting.liftForLoop(n, getCurrOwner(c)).PTransNode + result[1] = lambdalifting.liftForLoop(c.graph, n, getCurrOwner(c)).PTransNode else: result[1] = newNode(nkEmpty).PTransNode discard c.breakSyms.pop @@ -689,7 +691,7 @@ proc transformCall(c: PTransf, n: PNode): PTransNode = while (j < sonsLen(n)): let b = transform(c, n.sons[j]).PNode if not isConstExpr(b): break - a = evalOp(op.magic, n, a, b, nil) + a = evalOp(op.magic, n, a, b, nil, c.graph) inc(j) add(result, a.PTransNode) if len(result) == 2: result = result[1] @@ -708,7 +710,7 @@ proc transformCall(c: PTransf, n: PNode): PTransNode = let t = lastSon(s.sons[0].sym.ast) if t.kind != nkSym or sfDispatcher notin t.sym.flags: methodDef(s.sons[0].sym, false) - result = methodCall(s).PTransNode + result = methodCall(s, c.graph.config).PTransNode else: result = s.PTransNode @@ -719,7 +721,7 @@ proc transformExceptBranch(c: PTransf, n: PNode): PTransNode = let actions = newTransNode(nkStmtListExpr, n[1], 2) # Generating `let exc = (excType)(getCurrentException())` # -> getCurrentException() - let excCall = PTransNode(callCodegenProc("getCurrentException", ast.emptyNode)) + let excCall = PTransNode(callCodegenProc(c.graph, "getCurrentException", ast.emptyNode)) # -> (excType) let convNode = newTransNode(nkHiddenSubConv, n[1].info, 2) convNode[0] = PTransNode(ast.emptyNode) @@ -748,10 +750,10 @@ proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} = result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkTupleConstr, nkBracket} and cnst.len != 0 -proc commonOptimizations*(c: PSym, n: PNode): PNode = +proc commonOptimizations*(g: ModuleGraph; c: PSym, n: PNode): PNode = result = n for i in 0 ..< n.safeLen: - result.sons[i] = commonOptimizations(c, n.sons[i]) + result.sons[i] = commonOptimizations(g, c, n.sons[i]) var op = getMergeOp(n) if (op != nil) and (op.magic != mNone) and (sonsLen(n) >= 3): result = newNodeIT(nkCall, n.info, n.typ) @@ -766,12 +768,12 @@ proc commonOptimizations*(c: PSym, n: PNode): PNode = while j < sonsLen(args): let b = args.sons[j] if not isConstExpr(b): break - a = evalOp(op.magic, result, a, b, nil) + a = evalOp(op.magic, result, a, b, nil, g) inc(j) add(result, a) if len(result) == 2: result = result[1] else: - var cnst = getConstExpr(c, n) + var cnst = getConstExpr(c, n, g) # we inline constants if they are not complex constants: if cnst != nil and not dontInlineConstant(n, cnst): result = cnst @@ -888,7 +890,7 @@ proc transform(c: PTransf, n: PNode): PTransNode = let L = n.len-1 result[L] = transform(c, n.sons[L]) # XXX comment handling really sucks: - if importantComments(): + if importantComments(c.graph.config): PNode(result).comment = n.comment of nkClosure: # it can happen that for-loop-inlining produced a fresh @@ -905,7 +907,7 @@ proc transform(c: PTransf, n: PNode): PTransNode = when false: if oldDeferAnchor != nil: c.deferAnchor = oldDeferAnchor - var cnst = getConstExpr(c.module, PNode(result)) + var cnst = getConstExpr(c.module, PNode(result), c.graph) # we inline constants if they are not complex constants: if cnst != nil and not dontInlineConstant(n, cnst): result = PTransNode(cnst) # do not miss an optimization @@ -920,11 +922,12 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode = popTransCon(c) incl(result.flags, nfTransf) -proc openTransf(module: PSym, filename: string): PTransf = +proc openTransf(g: ModuleGraph; module: PSym, filename: string): PTransf = new(result) result.contSyms = @[] result.breakSyms = @[] result.module = module + result.graph = g proc flattenStmts(n: PNode) = var goOn = true @@ -967,46 +970,46 @@ template liftDefer(c, root) = if c.deferDetected: liftDeferAux(root) -proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode = +proc transformBody*(g: ModuleGraph; module: PSym, n: PNode, prc: PSym): PNode = if nfTransf in n.flags or prc.kind in {skTemplate}: result = n else: - var c = openTransf(module, "") - result = liftLambdas(prc, n, c.tooEarly) + var c = openTransf(g, module, "") + result = liftLambdas(g, prc, n, c.tooEarly) #result = n result = processTransf(c, result, prc) liftDefer(c, result) #result = liftLambdas(prc, result) - when useEffectSystem: trackProc(prc, result) - result = liftLocalsIfRequested(prc, result) + when useEffectSystem: trackProc(g, prc, result) + result = liftLocalsIfRequested(prc, result, g.config) if c.needsDestroyPass: #and newDestructors: - result = injectDestructorCalls(prc, result) + result = injectDestructorCalls(g, prc, result) incl(result.flags, nfTransf) #if prc.name.s == "testbody": # echo renderTree(result) -proc transformStmt*(module: PSym, n: PNode): PNode = +proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode = if nfTransf in n.flags: result = n else: - var c = openTransf(module, "") + var c = openTransf(g, module, "") result = processTransf(c, n, module) liftDefer(c, result) #result = liftLambdasForTopLevel(module, result) - when useEffectSystem: trackTopLevelStmt(module, result) + when useEffectSystem: trackTopLevelStmt(g, module, result) #if n.info ?? "temp.nim": # echo renderTree(result, {renderIds}) if c.needsDestroyPass: - result = injectDestructorCalls(module, result) + result = injectDestructorCalls(g, module, result) incl(result.flags, nfTransf) -proc transformExpr*(module: PSym, n: PNode): PNode = +proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode = if nfTransf in n.flags: result = n else: - var c = openTransf(module, "") + var c = openTransf(g, module, "") result = processTransf(c, n, module) liftDefer(c, result) if c.needsDestroyPass: - result = injectDestructorCalls(module, result) + result = injectDestructorCalls(g, module, result) incl(result.flags, nfTransf) diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index b0a559d2c..56ee45b6c 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -10,7 +10,7 @@ ## This module contains the type definitions for the new evaluation engine. ## An instruction is 1-3 int32s in memory, it is a register based VM. -import ast, passes, msgs, idents, intsets, options +import ast, passes, msgs, idents, intsets, options, modulegraphs const byteExcess* = 128 # we use excess-K for immediates @@ -207,18 +207,18 @@ type errorFlag*: string cache*: IdentCache config*: ConfigRef + graph*: ModuleGraph TPosition* = distinct int PEvalContext* = PCtx -proc newCtx*(module: PSym; cache: IdentCache; config: ConfigRef = nil): PCtx = - let conf = if config != nil: config else: newConfigRef() +proc newCtx*(module: PSym; cache: IdentCache; g: ModuleGraph): PCtx = PCtx(code: @[], debug: @[], globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[], prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations, comesFromHeuristic: unknownLineInfo(), callbacks: @[], errorFlag: "", - cache: cache, config: conf) + cache: cache, config: g.config, graph: g) proc refresh*(c: PCtx, module: PSym) = c.module = module diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index ba37237e8..2c92348a6 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -9,18 +9,18 @@ import ast, types, msgs, os, streams, options, idents -proc opSlurp*(file: string, info: TLineInfo, module: PSym): string = +proc opSlurp*(file: string, info: TLineInfo, module: PSym; conf: ConfigRef): string = try: var filename = parentDir(info.toFullPath) / file if not fileExists(filename): - filename = file.findFile + filename = findFile(conf, file) result = readFile(filename) # we produce a fake include statement for every slurped filename, so that # the module dependencies are accurate: appendToModule(module, newNode(nkIncludeStmt, info, @[ newStrNode(nkStrLit, filename)])) except IOError: - localError(info, errCannotOpenFile, file) + localError(conf, info, "cannot open file: " & file) result = "" proc atomicTypeX(name: string; m: TMagic; t: PType; info: TLineInfo): PNode = @@ -271,7 +271,7 @@ proc mapTypeToAstX(t: PType; info: TLineInfo; of tyOr: result = mapTypeToBracket("or", mOr, t, info) of tyNot: result = mapTypeToBracket("not", mNot, t, info) of tyAnything: result = atomicType("anything", mNone) - of tyInferred: internalAssert false + of tyInferred: assert false of tyStatic, tyFromExpr: if inst: if t.n != nil: result = t.n.copyTree @@ -281,7 +281,7 @@ proc mapTypeToAstX(t: PType; info: TLineInfo; result.add atomicType("static", mNone) if t.n != nil: result.add t.n.copyTree - of tyUnused, tyOptAsRef: internalError("mapTypeToAstX") + of tyUnused, tyOptAsRef: assert(false, "mapTypeToAstX") proc opMapTypeToAst*(t: PType; info: TLineInfo): PNode = result = mapTypeToAstX(t, info, false, true) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 7f91e63db..7ac3b5cf7 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -120,7 +120,7 @@ proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) = c.code.add(ins) c.debug.add(n.info) else: - localError(n.info, errGenerated, + localError(c.config, n.info, "VM: immediate value does not fit into an int8") proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) = @@ -137,7 +137,7 @@ proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) = c.code.add(ins) c.debug.add(n.info) else: - localError(n.info, errGenerated, + localError(c.config, n.info, "VM: immediate value does not fit into an int16") proc xjmp(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0): TPosition = @@ -151,7 +151,7 @@ proc genLabel(c: PCtx): TPosition = proc jmpBack(c: PCtx, n: PNode, p = TPosition(0)) = let dist = p.int - c.code.len - internalAssert(-0x7fff < dist and dist < 0x7fff) + internalAssert(c.config, -0x7fff < dist and dist < 0x7fff) gABx(c, n, opcJmpBack, 0, dist) proc patch(c: PCtx, p: TPosition) = @@ -159,7 +159,7 @@ proc patch(c: PCtx, p: TPosition) = let p = p.int let diff = c.code.len - p #c.jumpTargets.incl(c.code.len) - internalAssert(-0x7fff < diff and diff < 0x7fff) + internalAssert(c.config, -0x7fff < diff and diff < 0x7fff) let oldInstr = c.code[p] # opcode and regA stay the same: c.code[p] = ((oldInstr.uint32 and 0xffff'u32).uint32 or @@ -201,7 +201,7 @@ proc getTemp(cc: PCtx; tt: PType): TRegister = c.slots[i] = (inUse: true, kind: k) return TRegister(i) if c.maxSlots >= high(TRegister): - globalError(cc.bestEffort, "VM problem: too many registers required") + globalError(cc.config, cc.bestEffort, "VM problem: too many registers required") result = TRegister(c.maxSlots) c.slots[c.maxSlots] = (inUse: true, kind: k) inc c.maxSlots @@ -223,7 +223,7 @@ proc getTempRange(cc: PCtx; n: int; kind: TSlotKind): TRegister = for k in result .. result+n-1: c.slots[k] = (inUse: true, kind: kind) return if c.maxSlots+n >= high(TRegister): - globalError(cc.bestEffort, "VM problem: too many registers required") + globalError(cc.config, cc.bestEffort, "VM problem: too many registers required") result = TRegister(c.maxSlots) inc c.maxSlots, n for k in result .. result+n-1: c.slots[k] = (inUse: true, kind: kind) @@ -251,7 +251,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) proc gen(c: PCtx; n: PNode; dest: TRegister; flags: TGenFlags = {}) = var d: TDest = dest gen(c, n, d, flags) - #internalAssert d == dest # issue #7407 + #internalAssert c.config, d == dest # issue #7407 proc gen(c: PCtx; n: PNode; flags: TGenFlags = {}) = var tmp: TDest = -1 @@ -261,7 +261,7 @@ proc gen(c: PCtx; n: PNode; flags: TGenFlags = {}) = proc genx(c: PCtx; n: PNode; flags: TGenFlags = {}): TRegister = var tmp: TDest = -1 gen(c, n, tmp, flags) - #internalAssert tmp >= 0 # 'nim check' does not like this internalAssert. + #internalAssert c.config, tmp >= 0 # 'nim check' does not like this internalAssert. if tmp >= 0: result = TRegister(tmp) @@ -320,7 +320,7 @@ proc genBreak(c: PCtx; n: PNode) = if c.prc.blocks[i].label == n.sons[0].sym: c.prc.blocks[i].fixups.add L1 return - globalError(n.info, errGenerated, "VM problem: cannot find 'break' target") + globalError(c.config, n.info, "VM problem: cannot find 'break' target") else: c.prc.blocks[c.prc.blocks.high].fixups.add L1 @@ -378,7 +378,7 @@ proc rawGenLiteral(c: PCtx; n: PNode): int = #assert(n.kind != nkCall) n.flags.incl nfAllConst c.constants.add n.canonValue - internalAssert result < 0x7fff + internalAssert c.config, result < 0x7fff proc sameConstant*(a, b: PNode): bool = result = false @@ -405,10 +405,10 @@ proc genLiteral(c: PCtx; n: PNode): int = if sameConstant(c.constants[i], n): return i result = rawGenLiteral(c, n) -proc unused(n: PNode; x: TDest) {.inline.} = +proc unused(c: PCtx; n: PNode; x: TDest) {.inline.} = if x >= 0: #debug(n) - globalError(n.info, "not unused") + globalError(c.config, n.info, "not unused") proc genCase(c: PCtx; n: PNode; dest: var TDest) = # if (!expr1) goto L1; @@ -424,7 +424,7 @@ proc genCase(c: PCtx; n: PNode; dest: var TDest) = if not isEmptyType(n.typ): if dest < 0: dest = getTemp(c, n.typ) else: - unused(n, dest) + unused(c, n, dest) var endings: seq[TPosition] = @[] withTemp(tmp, n.sons[0].typ): c.gen(n.sons[0], tmp) @@ -451,7 +451,7 @@ proc genType(c: PCtx; typ: PType): int = if sameType(t, typ): return i result = c.types.len c.types.add(typ) - internalAssert(result <= 0x7fff) + internalAssert(c.config, result <= 0x7fff) proc genTry(c: PCtx; n: PNode; dest: var TDest) = if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ) @@ -525,7 +525,7 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) = var r: TRegister = x+i c.gen(n.sons[i], r) if i >= fntyp.len: - internalAssert tfVarargs in fntyp.flags + internalAssert c.config, tfVarargs in fntyp.flags c.gABx(n, opcSetType, r, c.genType(n.sons[i].typ)) if dest < 0: c.gABC(n, opcIndCall, 0, x, n.len) @@ -540,12 +540,12 @@ proc needsAsgnPatch(n: PNode): bool = n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr, nkDerefExpr, nkHiddenDeref} or (n.kind == nkSym and n.sym.isGlobal) -proc genField(n: PNode): TRegister = +proc genField(c: PCtx; n: PNode): TRegister = if n.kind != nkSym or n.sym.kind != skField: - globalError(n.info, "no field symbol") + globalError(c.config, n.info, "no field symbol") let s = n.sym if s.position > high(result): - globalError(n.info, + globalError(c.config, n.info, "too large offset! cannot generate code for: " & s.name.s) result = s.position @@ -572,7 +572,7 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) = # XXX field checks here let left = if le.kind == nkDotExpr: le else: le.sons[0] let dest = c.genx(left.sons[0], {gfAddrOf, gfFieldAccess}) - let idx = genField(left.sons[1]) + let idx = genField(c, left.sons[1]) c.gABC(left, opcWrObj, dest, idx, value) c.freeTemp(dest) of nkDerefExpr, nkHiddenDeref: @@ -779,7 +779,7 @@ proc genIntCast(c: PCtx; n: PNode; dest: var TDest) = let tmp3 = c.getTemp(n.sons[1].typ) if dest < 0: dest = c.getTemp(n[0].typ) proc mkIntLit(ival: int): int = - result = genLiteral(c, newIntTypeNode(nkIntLit, ival, getSysType(tyInt))) + result = genLiteral(c, newIntTypeNode(nkIntLit, ival, getSysType(c.graph, n.info, tyInt))) if src.kind in unsignedIntegers and dst.kind in signedIntegers: # cast unsigned to signed integer of same size # signedVal = (unsignedVal xor offset) -% offset @@ -802,7 +802,7 @@ proc genIntCast(c: PCtx; n: PNode; dest: var TDest) = c.freeTemp(tmp2) c.freeTemp(tmp3) else: - globalError(n.info, errGenerated, "VM is only allowed to 'cast' between integers of same size") + globalError(c.config, n.info, "VM is only allowed to 'cast' between integers of same size") proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = case m @@ -818,7 +818,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mSucc, mAddI: c.genAddSubInt(n, dest, opcAddInt) of mInc, mDec: - unused(n, dest) + unused(c, n, dest) let opc = if m == mInc: opcAddInt else: opcSubInt let d = c.genx(n.sons[1]) if n.sons[2].isInt8Lit: @@ -832,10 +832,10 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = c.freeTemp(d) of mOrd, mChr, mArrToSeq: c.gen(n.sons[1], dest) of mNew, mNewFinalize: - unused(n, dest) + unused(c, n, dest) c.genNew(n) of mNewSeq: - unused(n, dest) + unused(c, n, dest) c.genNewSeq(n) of mNewSeqOfCap: c.genNewSeqOfCap(n, dest) of mNewString: @@ -855,7 +855,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mLengthStr, mXLenStr: genUnaryABI(c, n, dest, opcLenStr) of mIncl, mExcl: - unused(n, dest) + unused(c, n, dest) var d = c.genx(n.sons[1]) var tmp = c.genx(n.sons[2]) c.genSetType(n.sons[1], d) @@ -952,19 +952,19 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mInSet: genBinarySet(c, n, dest, opcContainsSet) of mRepr: genUnaryABC(c, n, dest, opcRepr) of mExit: - unused(n, dest) + unused(c, n, dest) var tmp = c.genx(n.sons[1]) c.gABC(n, opcQuit, tmp) c.freeTemp(tmp) of mSetLengthStr, mSetLengthSeq: - unused(n, dest) + unused(c, n, dest) var d = c.genx(n.sons[1]) var tmp = c.genx(n.sons[2]) c.gABC(n, if m == mSetLengthStr: opcSetLenStr else: opcSetLenSeq, d, tmp) c.genAsgnPatch(n.sons[1], d) c.freeTemp(tmp) of mSwap: - unused(n, dest) + unused(c, n, dest) c.gen(lowerSwap(n, if c.prc == nil: c.module else: c.prc.sym)) of mIsNil: genUnaryABC(c, n, dest, opcIsNil) of mCopyStr: @@ -996,7 +996,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = # skip 'nkHiddenAddr': let d2AsNode = n.sons[2].sons[0] if needsAsgnPatch(d2AsNode): - d2 = c.getTemp(getSysType(tyFloat)) + d2 = c.getTemp(getSysType(c.graph, n.info, tyFloat)) else: d2 = c.genx(d2AsNode) var @@ -1009,13 +1009,13 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = c.genAsgnPatch(d2AsNode, d2) c.freeTemp(d2) of mReset: - unused(n, dest) + unused(c, n, dest) var d = c.genx(n.sons[1]) c.gABC(n, opcReset, d) of mOf, mIs: if dest < 0: dest = c.getTemp(n.typ) var tmp = c.genx(n.sons[1]) - var idx = c.getTemp(getSysType(tyInt)) + var idx = c.getTemp(getSysType(c.graph, n.info, tyInt)) var typ = n.sons[2].typ if m == mOf: typ = typ.skipTypes(abstractPtrs-{tyTypeDesc}) c.gABx(n, opcLdImmInt, idx, c.genType(typ)) @@ -1023,7 +1023,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = c.freeTemp(tmp) c.freeTemp(idx) of mSizeOf: - globalError(n.info, errCannotInterpretNodeX, renderTree(n)) + globalError(c.config, n.info, "cannot run in the VM: " & renderTree(n)) of mHigh: if dest < 0: dest = c.getTemp(n.typ) let tmp = c.genx(n.sons[1]) @@ -1034,23 +1034,23 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = c.gABI(n, opcLenSeq, dest, tmp, 1) c.freeTemp(tmp) of mEcho: - unused(n, dest) + unused(c, n, dest) let n = n[1].skipConv let x = c.getTempRange(n.len, slotTempUnknown) - internalAssert n.kind == nkBracket + internalAssert c.config, n.kind == nkBracket for i in 0..= high(TRegister): - globalError(v.info, "cannot generate code; too many registers required") + globalError(c.config, v.info, "cannot generate code; too many registers required") v.position = c.prc.maxSlots c.prc.slots[v.position] = (inUse: true, kind: if v.kind == skLet: slotFixedLet else: slotFixedVar) inc c.prc.maxSlots -proc cannotEval(n: PNode) {.noinline.} = - globalError(n.info, errGenerated, "cannot evaluate at compile time: " & +proc cannotEval(c: PCtx; n: PNode) {.noinline.} = + globalError(c.config, n.info, "cannot evaluate at compile time: " & n.renderTree) proc isOwnedBy(a, b: PSym): bool = @@ -1333,10 +1333,10 @@ proc checkCanEval(c: PCtx; n: PNode) = if {sfCompileTime, sfGlobal} <= s.flags: return if s.kind in {skVar, skTemp, skLet, skParam, skResult} and not s.isOwnedBy(c.prc.sym) and s.owner != c.module and c.mode != emRepl: - cannotEval(n) + cannotEval(c, n) elif s.kind in {skProc, skFunc, skConverter, skMethod, skIterator} and sfForward in s.flags: - cannotEval(n) + cannotEval(c, n) proc isTemp(c: PCtx; dest: TDest): bool = result = dest >= 0 and c.prc.slots[dest].kind >= slotTempUnknown @@ -1378,7 +1378,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) = # XXX field checks here let left = if le.kind == nkDotExpr: le else: le.sons[0] let dest = c.genx(left.sons[0], {gfAddrOf, gfFieldAccess}) - let idx = genField(left.sons[1]) + let idx = genField(c, left.sons[1]) let tmp = c.genx(ri) c.preventFalseAlias(left, opcWrObj, dest, idx, tmp) c.freeTemp(tmp) @@ -1398,7 +1398,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) = c.freeTemp(val) else: if s.kind == skForVar: c.setSlot s - internalAssert s.position > 0 or (s.position == 0 and + internalAssert c.config, s.position > 0 or (s.position == 0 and s.kind in {skParam,skResult}) var dest: TRegister = s.position + ord(s.kind == skParam) assert le.typ != nil @@ -1424,15 +1424,15 @@ proc importcSym(c: PCtx; info: TLineInfo; s: PSym) = c.globals.add(importcSymbol(s)) s.position = c.globals.len else: - localError(info, errGenerated, "VM is not allowed to 'importc'") + localError(c.config, info, "VM is not allowed to 'importc'") else: - localError(info, errGenerated, + localError(c.config, info, "cannot 'importc' variable at compile time") -proc getNullValue*(typ: PType, info: TLineInfo): PNode +proc getNullValue*(typ: PType, info: TLineInfo; conf: ConfigRef): PNode proc genGlobalInit(c: PCtx; n: PNode; s: PSym) = - c.globals.add(getNullValue(s.typ, n.info)) + c.globals.add(getNullValue(s.typ, n.info, c.config)) s.position = c.globals.len # This is rather hard to support, due to the laziness of the VM code # generator. See tests/compile/tmacro2 for why this is necessary: @@ -1451,7 +1451,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = if sfCompileTime in s.flags or c.mode == emRepl: discard elif s.position == 0: - cannotEval(n) + cannotEval(c, n) if s.position == 0: if sfImportc in s.flags: c.importcSym(n.info, s) else: genGlobalInit(c, n, s) @@ -1472,13 +1472,13 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = s.kind in {skParam,skResult}): if dest < 0: dest = s.position + ord(s.kind == skParam) - internalAssert(c.prc.slots[dest].kind < slotSomeTemp) + internalAssert(c.config, c.prc.slots[dest].kind < slotSomeTemp) else: # we need to generate an assignment: genAsgn(c, dest, n, c.prc.slots[dest].kind >= slotSomeTemp) else: # see tests/t99bott for an example that triggers it: - cannotEval(n) + cannotEval(c, n) template needsRegLoad(): untyped = gfAddrOf notin flags and fitsRegister(n.typ.skipTypes({tyVar, tyLent})) @@ -1502,7 +1502,7 @@ proc genArrAccess2(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; proc genObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = let a = c.genx(n.sons[0], flags) - let b = genField(n.sons[1]) + let b = genField(c, n.sons[1]) if dest < 0: dest = c.getTemp(n.typ) if needsRegLoad(): var cc = c.getTemp(n.typ) @@ -1526,22 +1526,22 @@ proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = else: genArrAccess2(c, n, dest, opcLdArr, flags) -proc getNullValueAux(obj: PNode, result: PNode) = +proc getNullValueAux(obj: PNode, result: PNode; conf: ConfigRef) = case obj.kind of nkRecList: - for i in countup(0, sonsLen(obj) - 1): getNullValueAux(obj.sons[i], result) + for i in countup(0, sonsLen(obj) - 1): getNullValueAux(obj.sons[i], result, conf) of nkRecCase: - getNullValueAux(obj.sons[0], result) + getNullValueAux(obj.sons[0], result, conf) for i in countup(1, sonsLen(obj) - 1): - getNullValueAux(lastSon(obj.sons[i]), result) + getNullValueAux(lastSon(obj.sons[i]), result, conf) of nkSym: let field = newNodeI(nkExprColonExpr, result.info) field.add(obj) - field.add(getNullValue(obj.sym.typ, result.info)) + field.add(getNullValue(obj.sym.typ, result.info, conf)) addSon(result, field) - else: globalError(result.info, "cannot create null element for: " & $obj) + else: globalError(conf, result.info, "cannot create null element for: " & $obj) -proc getNullValue(typ: PType, info: TLineInfo): PNode = +proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode = var t = skipTypes(typ, abstractRange-{tyTypeDesc}) result = emptyNode case t.kind @@ -1570,17 +1570,17 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode = # initialize inherited fields: var base = t.sons[0] while base != nil: - getNullValueAux(skipTypes(base, skipPtrs).n, result) + getNullValueAux(skipTypes(base, skipPtrs).n, result, conf) base = base.sons[0] - getNullValueAux(t.n, result) + getNullValueAux(t.n, result, conf) of tyArray: result = newNodeIT(nkBracket, info, t) for i in countup(0, int(lengthOrd(t)) - 1): - addSon(result, getNullValue(elemType(t), info)) + addSon(result, getNullValue(elemType(t), info, conf)) of tyTuple: result = newNodeIT(nkTupleConstr, info, t) for i in countup(0, sonsLen(t) - 1): - addSon(result, getNullValue(t.sons[i], info)) + addSon(result, getNullValue(t.sons[i], info, conf)) of tySet: result = newNodeIT(nkCurly, info, t) of tyOpt: @@ -1588,7 +1588,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode = of tySequence: result = newNodeIT(nkBracket, info, t) else: - globalError(info, "cannot create null element for: " & $t.kind) + globalError(conf, info, "cannot create null element for: " & $t.kind) proc ldNullOpcode(t: PType): TOpcode = assert t != nil @@ -1602,7 +1602,7 @@ proc genVarSection(c: PCtx; n: PNode) = for i in 0 .. a.len-3: if not a[i].sym.isGlobal: setSlot(c, a[i].sym) checkCanEval(c, a[i]) - c.gen(lowerTupleUnpacking(a, c.getOwner)) + c.gen(lowerTupleUnpacking(c.graph, a, c.getOwner)) elif a.sons[0].kind == nkSym: let s = a.sons[0].sym checkCanEval(c, a.sons[0]) @@ -1610,7 +1610,7 @@ proc genVarSection(c: PCtx; n: PNode) = if s.position == 0: if sfImportc in s.flags: c.importcSym(a.info, s) else: - let sa = getNullValue(s.typ, a.info) + let sa = getNullValue(s.typ, a.info, c.config) #if s.ast.isNil: getNullValue(s.typ, a.info) #else: canonValue(s.ast) assert sa.kind != nkCall @@ -1652,7 +1652,7 @@ proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) = if dest < 0: dest = c.getTemp(n.typ) c.gABx(n, opcLdNull, dest, c.genType(n.typ)) - let intType = getSysType(tyInt) + let intType = getSysType(c.graph, n.info, tyInt) let seqType = n.typ.skipTypes(abstractVar-{tyTypeDesc}) if seqType.kind == tySequence: var tmp = c.getTemp(intType) @@ -1696,13 +1696,13 @@ proc genObjConstr(c: PCtx, n: PNode, dest: var TDest) = for i in 1..= 0: - globalError(n.info, errGenerated, "VM problem: dest register is set") + globalError(c.config, n.info, "VM problem: dest register is set") proc genExpr*(c: PCtx; n: PNode, requiresValue = true): int = c.removeLastEof @@ -1924,7 +1924,7 @@ proc genExpr*(c: PCtx; n: PNode, requiresValue = true): int = c.gen(n, d) if d < 0: if requiresValue: - globalError(n.info, errGenerated, "VM problem: dest register is not set") + globalError(c.config, n.info, "VM problem: dest register is not set") d = 0 c.gABC(n, opcEof, d) @@ -1939,7 +1939,7 @@ proc genParams(c: PCtx; params: PNode) = c.prc.maxSlots = max(params.len, 1) proc finalJumpTarget(c: PCtx; pc, diff: int) = - internalAssert(-0x7fff < diff and diff < 0x7fff) + internalAssert(c.config, -0x7fff < diff and diff < 0x7fff) let oldInstr = c.code[pc] # opcode and regA stay the same: c.code[pc] = ((oldInstr.uint32 and 0xffff'u32).uint32 or diff --git a/compiler/vmmarshal.nim b/compiler/vmmarshal.nim index d76909443..f38be7c29 100644 --- a/compiler/vmmarshal.nim +++ b/compiler/vmmarshal.nim @@ -9,7 +9,8 @@ ## Implements marshaling for the VM. -import streams, json, intsets, tables, ast, astalgo, idents, types, msgs +import streams, json, intsets, tables, ast, astalgo, idents, types, msgs, + options proc ptrToInt(x: PNode): int {.inline.} = result = cast[int](x) # don't skip alignment @@ -28,37 +29,38 @@ proc getField(n: PNode; position: int): PSym = of nkOfBranch, nkElse: result = getField(lastSon(n.sons[i]), position) if result != nil: return - else: internalError(n.info, "getField(record case branch)") + else: discard 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 storeAny(s: var string; t: PType; a: PNode; stored: var IntSet; conf: ConfigRef) -proc storeObj(s: var string; typ: PType; x: PNode; stored: var IntSet) = - internalAssert x.kind == nkObjConstr +proc storeObj(s: var string; typ: PType; x: PNode; stored: var IntSet; conf: ConfigRef) = + assert x.kind == nkObjConstr let start = 1 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) + if 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, conf) elif typ.n != nil: let field = getField(typ.n, i) s.add(escapeJson(field.name.s)) s.add(": ") - storeAny(s, field.typ, it, stored) + storeAny(s, field.typ, it, stored, conf) 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) = +proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet; + conf: ConfigRef) = case t.kind of tyNone: assert false of tyBool: s.add($(a.intVal != 0)) @@ -74,7 +76,7 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) = s.add("[") for i in 0 .. a.len-1: if i > 0: s.add(", ") - storeAny(s, t.elemType, a[i], stored) + storeAny(s, t.elemType, a[i], stored, conf) s.add("]") of tyTuple: s.add("{") @@ -82,11 +84,11 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) = if i > 0: s.add(", ") s.add("\"Field" & $i) s.add("\": ") - storeAny(s, t.sons[i], a[i].skipColon, stored) + storeAny(s, t.sons[i], a[i].skipColon, stored, conf) s.add("}") of tyObject: s.add("{") - storeObj(s, t, a, stored) + storeObj(s, t, a, stored, conf) s.add("}") of tySet: s.add("[") @@ -94,15 +96,16 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) = if i > 0: s.add(", ") if a[i].kind == nkRange: var x = copyNode(a[i][0]) - storeAny(s, t.lastSon, x, stored) + storeAny(s, t.lastSon, x, stored, conf) while x.intVal+1 <= a[i][1].intVal: s.add(", ") - storeAny(s, t.lastSon, x, stored) + storeAny(s, t.lastSon, x, stored, conf) inc x.intVal else: - storeAny(s, t.lastSon, a[i], stored) + storeAny(s, t.lastSon, a[i], stored, conf) s.add("]") - of tyRange, tyGenericInst, tyAlias, tySink: storeAny(s, t.lastSon, a, stored) + of tyRange, tyGenericInst, tyAlias, tySink: + storeAny(s, t.lastSon, a, stored, conf) of tyEnum: # we need a slow linear search because of enums with holes: for e in items(t.n): @@ -121,7 +124,7 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) = s.add("[") s.add($x.ptrToInt) s.add(", ") - storeAny(s, t.lastSon, a, stored) + storeAny(s, t.lastSon, a, stored, conf) s.add("]") of tyString, tyCString: if a.kind == nkNilLit or a.strVal.isNil: s.add("null") @@ -129,14 +132,15 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) = 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 + internalError conf, a.info, "cannot marshal at compile-time " & t.typeToString -proc storeAny*(s: var string; t: PType; a: PNode) = +proc storeAny*(s: var string; t: PType; a: PNode; conf: ConfigRef) = var stored = initIntSet() - storeAny(s, t, a, stored) + storeAny(s, t, a, stored, conf) proc loadAny(p: var JsonParser, t: PType, - tab: var Table[BiggestInt, PNode]): PNode = + tab: var Table[BiggestInt, PNode]; + conf: ConfigRef): PNode = case t.kind of tyNone: assert false of tyBool: @@ -170,7 +174,7 @@ proc loadAny(p: var JsonParser, t: PType, next(p) result = newNode(nkBracket) while p.kind != jsonArrayEnd and p.kind != jsonEof: - result.add loadAny(p, t.elemType, tab) + result.add loadAny(p, t.elemType, tab, conf) if p.kind == jsonArrayEnd: next(p) else: raiseParseErr(p, "']' end of array expected") of tySequence: @@ -182,7 +186,7 @@ proc loadAny(p: var JsonParser, t: PType, next(p) result = newNode(nkBracket) while p.kind != jsonArrayEnd and p.kind != jsonEof: - result.add loadAny(p, t.elemType, tab) + result.add loadAny(p, t.elemType, tab, conf) if p.kind == jsonArrayEnd: next(p) else: raiseParseErr(p, "") else: @@ -198,7 +202,7 @@ proc loadAny(p: var JsonParser, t: PType, next(p) if i >= t.len: raiseParseErr(p, "too many fields to tuple type " & typeToString(t)) - result.add loadAny(p, t.sons[i], tab) + result.add loadAny(p, t.sons[i], tab, conf) inc i if p.kind == jsonObjectEnd: next(p) else: raiseParseErr(p, "'}' end of object expected") @@ -220,7 +224,7 @@ proc loadAny(p: var JsonParser, t: PType, setLen(result.sons, pos + 1) let fieldNode = newNode(nkExprColonExpr) fieldNode.addSon(newSymNode(newSym(skField, ident, nil, unknownLineInfo()))) - fieldNode.addSon(loadAny(p, field.typ, tab)) + fieldNode.addSon(loadAny(p, field.typ, tab, conf)) result.sons[pos] = fieldNode if p.kind == jsonObjectEnd: next(p) else: raiseParseErr(p, "'}' end of object expected") @@ -229,7 +233,7 @@ proc loadAny(p: var JsonParser, t: PType, next(p) result = newNode(nkCurly) while p.kind != jsonArrayEnd and p.kind != jsonEof: - result.add loadAny(p, t.lastSon, tab) + result.add loadAny(p, t.lastSon, tab, conf) next(p) if p.kind == jsonArrayEnd: next(p) else: raiseParseErr(p, "']' end of array expected") @@ -248,7 +252,7 @@ proc loadAny(p: var JsonParser, t: PType, if p.kind == jsonInt: let idx = p.getInt next(p) - result = loadAny(p, t.lastSon, tab) + result = loadAny(p, t.lastSon, tab, conf) tab[idx] = result else: raiseParseErr(p, "index for ref type expected") if p.kind == jsonArrayEnd: next(p) @@ -275,14 +279,15 @@ proc loadAny(p: var JsonParser, t: PType, next(p) return raiseParseErr(p, "float expected") - of tyRange, tyGenericInst, tyAlias, tySink: result = loadAny(p, t.lastSon, tab) + of tyRange, tyGenericInst, tyAlias, tySink: + result = loadAny(p, t.lastSon, tab, conf) else: - internalError "cannot marshal at compile-time " & t.typeToString + internalError conf, "cannot marshal at compile-time " & t.typeToString -proc loadAny*(s: string; t: PType): PNode = +proc loadAny*(s: string; t: PType; conf: ConfigRef): PNode = var tab = initTable[BiggestInt, PNode]() var p: JsonParser open(p, newStringStream(s), "unknown file") next(p) - result = loadAny(p, t, tab) + result = loadAny(p, t, tab, conf) close(p) -- cgit 1.4.1-2-gfad0 From 05724645f815bea56a65bd78a9f2228811573413 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 12 May 2018 11:58:44 +0200 Subject: more modules compile again --- compiler/aliases.nim | 4 +- compiler/evaltempl.nim | 28 ++++-- compiler/guards.nim | 4 +- compiler/hlo.nim | 2 +- compiler/patterns.nim | 4 +- compiler/plugins/itersgen.nim | 10 +- compiler/sem.nim | 51 +++++----- compiler/semmacrosanity.nim | 36 ++++---- compiler/semparallel.nim | 128 ++++++++++++------------- compiler/vm.nim | 210 ++++++++++++++++++++++-------------------- compiler/vmdef.nim | 1 + compiler/vmops.nim | 16 ++-- 12 files changed, 259 insertions(+), 235 deletions(-) (limited to 'compiler/vmdef.nim') diff --git a/compiler/aliases.nim b/compiler/aliases.nim index 490ac987a..f79210dd7 100644 --- a/compiler/aliases.nim +++ b/compiler/aliases.nim @@ -34,10 +34,10 @@ proc isPartOfAux(n: PNode, b: PType, marker: var IntSet): TAnalysisResult = of nkOfBranch, nkElse: result = isPartOfAux(lastSon(n.sons[i]), b, marker) if result == arYes: return - else: internalError("isPartOfAux(record case branch)") + else: discard "isPartOfAux(record case branch)" of nkSym: result = isPartOfAux(n.sym.typ, b, marker) - else: internalError(n.info, "isPartOfAux()") + else: discard proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult = result = arNo diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index fbb7eb2e6..2133701e6 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -14,11 +14,12 @@ import rodread type - TemplCtx {.pure, final.} = object + TemplCtx = object owner, genSymOwner: PSym instLines: bool # use the instantiation lines numbers mapping: TIdTable # every gensym'ed symbol needs to be mapped to some # new symbol + config: ConfigRef proc copyNode(ctx: TemplCtx, a, b: PNode): PNode = result = copyNode(a) @@ -42,7 +43,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) = s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam: handleParam actual.sons[s.owner.typ.len + s.position - 1] else: - internalAssert sfGenSym in s.flags or s.kind == skType + internalAssert c.config, sfGenSym in s.flags or s.kind == skType var x = PSym(idTableGet(c.mapping, s)) if x == nil: x = copySym(s, false) @@ -59,7 +60,12 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) = evalTemplateAux(templ.sons[i], actual, c, res) result.add res -proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode = +const + errWrongNumberOfArguments = "wrong number of arguments" + errMissingGenericParamsForTemplate = "'$1' has unspecified generic parameters" + errTemplateInstantiationTooNested = "template instantiation too nested" + +proc evalTemplateArgs(n: PNode, s: PSym; conf: ConfigRef; fromHlo: bool): PNode = # if the template has zero arguments, it can be called without ``()`` # `n` is then a nkSym or something similar var totalParams = case n.kind @@ -82,10 +88,10 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode = if givenRegularParams < 0: givenRegularParams = 0 if totalParams > expectedRegularParams + genericParams: - globalError(n.info, errWrongNumberOfArguments) + globalError(conf, n.info, errWrongNumberOfArguments) if totalParams < genericParams: - globalError(n.info, errMissingGenericParamsForTemplate, + globalError(conf, n.info, errMissingGenericParamsForTemplate % n.renderTree) result = newNodeI(nkArgList, n.info) @@ -97,7 +103,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode = for i in givenRegularParams+1 .. expectedRegularParams: let default = s.typ.n.sons[i].sym.ast if default.isNil or default.kind == nkEmpty: - localError(n.info, errWrongNumberOfArguments) + localError(conf, n.info, errWrongNumberOfArguments) addSon(result, ast.emptyNode) else: addSon(result, default.copyTree) @@ -132,17 +138,19 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode = result.add res result.typ = res.typ -proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode = +proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; + conf: ConfigRef; fromHlo=false): PNode = inc(evalTemplateCounter) if evalTemplateCounter > evalTemplateLimit: - globalError(n.info, errTemplateInstantiationTooNested) + globalError(conf, n.info, errTemplateInstantiationTooNested) result = n # replace each param by the corresponding node: - var args = evalTemplateArgs(n, tmpl, fromHlo) + var args = evalTemplateArgs(n, tmpl, conf, fromHlo) var ctx: TemplCtx ctx.owner = tmpl ctx.genSymOwner = genSymOwner + ctx.config = conf initIdTable(ctx.mapping) let body = tmpl.getBody @@ -151,7 +159,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode = evalTemplateAux(body, args, ctx, result) if result.len == 1: result = result.sons[0] else: - localError(result.info, errIllFormedAstX, + localError(conf, result.info, "illformed AST: " & renderTree(result, {renderNoComments})) else: result = copyNode(body) diff --git a/compiler/guards.nim b/compiler/guards.nim index 68f979a9f..d39ea799b 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -330,8 +330,8 @@ proc canon*(n: PNode; o: Operators): PNode = result.sons[2] = y[1] else: discard -#proc `+@`*(a: PNode; b: BiggestInt): PNode = -# canon(if b != 0: opAdd.buildCall(a, nkIntLit.newIntNode(b)) else: a) +proc buildAdd*(a: PNode; b: BiggestInt; o: Operators): PNode = + canon(if b != 0: o.opAdd.buildCall(a, nkIntLit.newIntNode(b)) else: a, o) proc usefulFact(n: PNode; o: Operators): PNode = case n.getMagic diff --git a/compiler/hlo.nim b/compiler/hlo.nim index c4288c362..3e19be6e9 100644 --- a/compiler/hlo.nim +++ b/compiler/hlo.nim @@ -12,7 +12,7 @@ proc hlo(c: PContext, n: PNode): PNode proc evalPattern(c: PContext, n, orig: PNode): PNode = - internalAssert n.kind == nkCall and n.sons[0].kind == nkSym + internalAssert c.config, n.kind == nkCall and n.sons[0].kind == nkSym # we need to ensure that the resulting AST is semchecked. However, it's # aweful to semcheck before macro invocation, so we don't and treat # templates and macros as immediate in this context. diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 31b76743e..5409a4811 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -150,7 +150,7 @@ proc matches(c: PPatternContext, p, n: PNode): bool = of "*": result = matchNested(c, p, n, rpn=false) of "**": result = matchNested(c, p, n, rpn=true) of "~": result = not matches(c, p.sons[1], n) - else: internalError(p.info, "invalid pattern") + else: doAssert(false, "invalid pattern") # template {add(a, `&` * b)}(a: string{noalias}, b: varargs[string]) = # add(a, b) elif p.kind == nkCurlyExpr: @@ -289,7 +289,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode = # constraint not fulfilled: if not ok: return nil - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) if ctx.subMatch: assert m.len == 3 m.sons[1] = result diff --git a/compiler/plugins/itersgen.nim b/compiler/plugins/itersgen.nim index dbc47e11e..ebb65dd4a 100644 --- a/compiler/plugins/itersgen.nim +++ b/compiler/plugins/itersgen.nim @@ -17,21 +17,21 @@ proc iterToProcImpl(c: PContext, n: PNode): PNode = result = newNodeI(nkStmtList, n.info) let iter = n[1] if iter.kind != nkSym or iter.sym.kind != skIterator: - localError(iter.info, "first argument needs to be an iterator") + localError(c.config, iter.info, "first argument needs to be an iterator") return if n[2].typ.isNil: - localError(n[2].info, "second argument needs to be a type") + localError(c.config, n[2].info, "second argument needs to be a type") return if n[3].kind != nkIdent: - localError(n[3].info, "third argument needs to be an identifier") + localError(c.config, n[3].info, "third argument needs to be an identifier") return let t = n[2].typ.skipTypes({tyTypeDesc, tyGenericInst}) if t.kind notin {tyRef, tyPtr} or t.lastSon.kind != tyObject: - localError(n[2].info, + localError(c.config, n[2].info, "type must be a non-generic ref|ptr to object with state field") return - let body = liftIterToProc(iter.sym, iter.sym.getBody, t) + let body = liftIterToProc(c.graph, iter.sym, iter.sym.getBody, t) let prc = newSym(skProc, n[3].ident, iter.sym.owner, iter.sym.info) prc.typ = copyType(iter.sym.typ, prc, false) diff --git a/compiler/sem.nim b/compiler/sem.nim index d8e5b7f20..ae32ecb8a 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -71,7 +71,7 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode; proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode = if arg.typ.isNil: - localError(arg.info, errExprXHasNoType, + localError(c.config, arg.info, "expression has no type: " & renderTree(arg, {renderNoComments})) # error correction: result = copyTree(arg) @@ -79,7 +79,7 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode = else: result = indexTypesMatch(c, formal, arg.typ, arg) if result == nil: - typeMismatch(info, formal, arg.typ) + typeMismatch(c.config, info, formal, arg.typ) # error correction: result = copyTree(arg) result.typ = formal @@ -180,7 +180,7 @@ proc commonType*(x: PType, y: PNode): PType = commonType(x, y.typ) proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = - result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info) + result = newSym(kind, considerQuotedIdent(c.config, n), getCurrOwner(c), n.info) when defined(nimsuggest): suggestDecl(c, n, result) @@ -192,7 +192,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = # and sfGenSym in n.sym.flags: result = n.sym if result.kind != kind: - localError(n.info, "cannot use symbol of kind '" & + localError(c.config, n.info, "cannot use symbol of kind '" & $result.kind & "' as a '" & $kind & "'") if sfGenSym in result.flags and result.kind notin {skTemplate, skMacro, skParam}: # declarative context, so produce a fresh gensym: @@ -204,7 +204,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = # template; we must fix it here: see #909 result.owner = getCurrOwner(c) else: - result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info) + result = newSym(kind, considerQuotedIdent(c.config, n), getCurrOwner(c), n.info) #if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule: # incl(result.flags, sfGlobal) when defined(nimsuggest): @@ -216,20 +216,20 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode, allowed: TSymFlags): PSym -proc typeAllowedCheck(info: TLineInfo; typ: PType; kind: TSymKind; +proc typeAllowedCheck(conf: ConfigRef; info: TLineInfo; typ: PType; kind: TSymKind; flags: TTypeAllowedFlags = {}) = let t = typeAllowed(typ, kind, flags) if t != nil: if t == typ: - localError(info, "invalid type: '" & typeToString(typ) & + localError(conf, info, "invalid type: '" & typeToString(typ) & "' for " & substr($kind, 2).toLowerAscii) else: - localError(info, "invalid type: '" & typeToString(t) & + localError(conf, info, "invalid type: '" & typeToString(t) & "' in this context: '" & typeToString(typ) & "' for " & substr($kind, 2).toLowerAscii) proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} = - typeAllowedCheck(typ.n.info, typ, skProc) + typeAllowedCheck(c.config, typ.n.info, typ, skProc) proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode @@ -282,10 +282,10 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode = result = evaluated let expectedType = eOrig.typ.skipTypes({tyStatic}) if hasCycle(result): - globalError(eOrig.info, "the resulting AST is cyclic and cannot be processed further") + globalError(c.config, eOrig.info, "the resulting AST is cyclic and cannot be processed further") result = errorNode(c, eOrig) else: - semmacrosanity.annotateType(result, expectedType) + semmacrosanity.annotateType(result, expectedType, c.config) else: result = semExprWithType(c, evaluated) #result = fitNode(c, e.typ, result) inlined with special case: @@ -302,18 +302,18 @@ proc tryConstExpr(c: PContext, n: PNode): PNode = var e = semExprWithType(c, n) if e == nil: return - result = getConstExpr(c.module, e) + result = getConstExpr(c.module, e, c.graph) if result != nil: return - let oldErrorCount = msgs.gErrorCounter - let oldErrorMax = msgs.gErrorMax + let oldErrorCount = c.config.errorCounter + let oldErrorMax = c.config.errorMax let oldErrorOutputs = errorOutputs errorOutputs = {} - msgs.gErrorMax = high(int) + c.config.errorMax = high(int) try: - result = evalConstExpr(c.module, c.cache, c.graph.config, e) + result = evalConstExpr(c.module, c.cache, c.graph, e) if result == nil or result.kind == nkEmpty: result = nil else: @@ -322,26 +322,29 @@ proc tryConstExpr(c: PContext, n: PNode): PNode = except ERecoverableError: result = nil - msgs.gErrorCounter = oldErrorCount - msgs.gErrorMax = oldErrorMax + c.config.errorCounter = oldErrorCount + c.config.errorMax = oldErrorMax errorOutputs = oldErrorOutputs +const + errConstExprExpected = "constant expression expected" + proc semConstExpr(c: PContext, n: PNode): PNode = var e = semExprWithType(c, n) if e == nil: - localError(n.info, errConstExprExpected) + localError(c.config, n.info, errConstExprExpected) return n - result = getConstExpr(c.module, e) + result = getConstExpr(c.module, e, c.graph) if result == nil: #if e.kind == nkEmpty: globalError(n.info, errConstExprExpected) - result = evalConstExpr(c.module, c.cache, c.graph.config, e) + result = evalConstExpr(c.module, c.cache, c.graph, e) if result == nil or result.kind == nkEmpty: if e.info != n.info: pushInfoContext(n.info) - localError(e.info, errConstExprExpected) + localError(c.config, e.info, errConstExprExpected) popInfoContext() else: - localError(e.info, errConstExprExpected) + localError(c.config, e.info, errConstExprExpected) # error correction: result = e else: @@ -356,7 +359,7 @@ proc semExprFlagDispatched(c: PContext, n: PNode, flags: TExprFlags): PNode = else: result = semExprWithType(c, n, flags) if efPreferStatic in flags: - var evaluated = getConstExpr(c.module, result) + var evaluated = getConstExpr(c.module, result, c.graph) if evaluated != nil: return evaluated evaluated = evalAtCompileTime(c, result) if evaluated != nil: return evaluated diff --git a/compiler/semmacrosanity.nim b/compiler/semmacrosanity.nim index f6df67441..02c56c035 100644 --- a/compiler/semmacrosanity.nim +++ b/compiler/semmacrosanity.nim @@ -10,7 +10,7 @@ ## Implements type sanity checking for ASTs resulting from macros. Lots of ## room for improvement here. -import ast, astalgo, msgs, types +import ast, astalgo, msgs, types, options proc ithField(n: PNode, field: var int): PSym = result = nil @@ -20,7 +20,7 @@ proc ithField(n: PNode, field: var int): PSym = result = ithField(n.sons[i], field) if result != nil: return of nkRecCase: - if n.sons[0].kind != nkSym: internalError(n.info, "ithField") + if n.sons[0].kind != nkSym: return result = ithField(n.sons[0], field) if result != nil: return for i in countup(1, sonsLen(n) - 1): @@ -28,13 +28,13 @@ proc ithField(n: PNode, field: var int): PSym = of nkOfBranch, nkElse: result = ithField(lastSon(n.sons[i]), field) if result != nil: return - else: internalError(n.info, "ithField(record case branch)") + else: discard of nkSym: if field == 0: result = n.sym else: dec(field) else: discard -proc annotateType*(n: PNode, t: PType) = +proc annotateType*(n: PNode, t: PType; conf: ConfigRef) = 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 @@ -46,50 +46,50 @@ proc annotateType*(n: PNode, t: PType) = var j = i-1 let field = x.n.ithField(j) if field.isNil: - globalError n.info, "invalid field at index " & $i + globalError conf, n.info, "invalid field at index " & $i else: - internalAssert(n.sons[i].kind == nkExprColonExpr) - annotateType(n.sons[i].sons[1], field.typ) + internalAssert(conf, n.sons[i].kind == nkExprColonExpr) + annotateType(n.sons[i].sons[1], field.typ, conf) of nkPar, nkTupleConstr: if x.kind == tyTuple: n.typ = t for i in 0 ..< n.len: - if i >= x.len: globalError n.info, "invalid field at index " & $i - else: annotateType(n.sons[i], x.sons[i]) + if i >= x.len: globalError conf, n.info, "invalid field at index " & $i + else: annotateType(n.sons[i], x.sons[i], conf) elif x.kind == tyProc and x.callConv == ccClosure: n.typ = t else: - globalError(n.info, "() must have a tuple type") + globalError(conf, n.info, "() must have a tuple type") of nkBracket: if x.kind in {tyArray, tySequence, tyOpenArray}: n.typ = t - for m in n: annotateType(m, x.elemType) + for m in n: annotateType(m, x.elemType, conf) else: - globalError(n.info, "[] must have some form of array type") + globalError(conf, n.info, "[] must have some form of array type") of nkCurly: if x.kind in {tySet}: n.typ = t - for m in n: annotateType(m, x.elemType) + for m in n: annotateType(m, x.elemType, conf) else: - globalError(n.info, "{} must have the set type") + globalError(conf, n.info, "{} must have the set type") of nkFloatLit..nkFloat128Lit: if x.kind in {tyFloat..tyFloat128}: n.typ = t else: - globalError(n.info, "float literal must have some float type") + globalError(conf, n.info, "float literal must have some float type") of nkCharLit..nkUInt64Lit: if x.kind in {tyInt..tyUInt64, tyBool, tyChar, tyEnum}: n.typ = t else: - globalError(n.info, "integer literal must have some int type") + globalError(conf, n.info, "integer literal must have some int type") of nkStrLit..nkTripleStrLit: if x.kind in {tyString, tyCString}: n.typ = t else: - globalError(n.info, "string literal must be of some string type") + globalError(conf, n.info, "string literal must be of some string type") of nkNilLit: if x.kind in NilableTypes: n.typ = t else: - globalError(n.info, "nil literal must be of some pointer type") + globalError(conf, n.info, "nil literal must be of some pointer type") else: discard diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim index e12fd84bb..ea5aab628 100644 --- a/compiler/semparallel.nim +++ b/compiler/semparallel.nim @@ -23,7 +23,8 @@ import ast, astalgo, idents, lowerings, magicsys, guards, sempass2, msgs, - renderer, types + renderer, types, modulegraphs, options + from trees import getMagic from strutils import `%` @@ -73,12 +74,15 @@ type # the 'parallel' section currentSpawnId: int inLoop: int + graph: ModuleGraph -proc initAnalysisCtx(): AnalysisCtx = +proc initAnalysisCtx(g: ModuleGraph): AnalysisCtx = result.locals = @[] result.slices = @[] result.args = @[] - result.guards = @[] + result.guards.s = @[] + result.guards.o = initOperators(g) + result.graph = g proc lookupSlot(c: AnalysisCtx; s: PSym): int = for i in 0..= 0 and c.locals[s].stride != nil: - localError(n.info, "invalid usage of counter after increment") + localError(c.graph.config, n.info, "invalid usage of counter after increment") else: for i in 0 ..< n.safeLen: checkLocal(c, n.sons[i]) @@ -126,14 +130,14 @@ template `?`(x): untyped = x.renderTree proc checkLe(c: AnalysisCtx; a, b: PNode) = case proveLe(c.guards, a, b) of impUnknown: - localError(a.info, "cannot prove: " & ?a & " <= " & ?b & " (bounds check)") + localError(c.graph.config, a.info, "cannot prove: " & ?a & " <= " & ?b & " (bounds check)") of impYes: discard of impNo: - localError(a.info, "can prove: " & ?a & " > " & ?b & " (bounds check)") + localError(c.graph.config, a.info, "can prove: " & ?a & " > " & ?b & " (bounds check)") proc checkBounds(c: AnalysisCtx; arr, idx: PNode) = checkLe(c, arr.lowBound, idx) - checkLe(c, idx, arr.highBound) + checkLe(c, idx, arr.highBound(c.guards.o)) proc addLowerBoundAsFacts(c: var AnalysisCtx) = for v in c.locals: @@ -142,34 +146,34 @@ proc addLowerBoundAsFacts(c: var AnalysisCtx) = proc addSlice(c: var AnalysisCtx; n: PNode; x, le, ri: PNode) = checkLocal(c, n) - let le = le.canon - let ri = ri.canon + let le = le.canon(c.guards.o) + let ri = ri.canon(c.guards.o) # perform static bounds checking here; and not later! - let oldState = c.guards.len + let oldState = c.guards.s.len addLowerBoundAsFacts(c) c.checkBounds(x, le) c.checkBounds(x, ri) - c.guards.setLen(oldState) + c.guards.s.setLen(oldState) c.slices.add((x, le, ri, c.currentSpawnId, c.inLoop > 0)) -proc overlap(m: TModel; x,y,c,d: PNode) = +proc overlap(m: TModel; conf: ConfigRef; x,y,c,d: PNode) = # X..Y and C..D overlap iff (X <= D and C <= Y) case proveLe(m, c, y) of impUnknown: case proveLe(m, x, d) of impNo: discard of impUnknown, impYes: - localError(x.info, + localError(conf, x.info, "cannot prove: $# > $#; required for ($#)..($#) disjoint from ($#)..($#)" % [?c, ?y, ?x, ?y, ?c, ?d]) of impYes: case proveLe(m, x, d) of impUnknown: - localError(x.info, + localError(conf, x.info, "cannot prove: $# > $#; required for ($#)..($#) disjoint from ($#)..($#)" % [?x, ?d, ?x, ?y, ?c, ?d]) of impYes: - localError(x.info, "($#)..($#) not disjoint from ($#)..($#)" % + localError(conf, x.info, "($#)..($#) not disjoint from ($#)..($#)" % [?c, ?y, ?x, ?y, ?c, ?d]) of impNo: discard of impNo: discard @@ -187,7 +191,7 @@ proc subStride(c: AnalysisCtx; n: PNode): PNode = if isLocal(n): let s = c.lookupSlot(n.sym) if s >= 0 and c.locals[s].stride != nil: - result = n +@ c.locals[s].stride.intVal + result = buildAdd(n, c.locals[s].stride.intVal, c.guards.o) else: result = n elif n.safeLen > 0: @@ -203,7 +207,7 @@ proc checkSlicesAreDisjoint(c: var AnalysisCtx) = addLowerBoundAsFacts(c) # Every slice used in a loop needs to be disjoint with itself: for x,a,b,id,inLoop in items(c.slices): - if inLoop: overlap(c.guards, a,b, c.subStride(a), c.subStride(b)) + if inLoop: overlap(c.guards, c.graph.config, a,b, c.subStride(a), c.subStride(b)) # Another tricky example is: # while true: # spawn f(a[i]) @@ -231,21 +235,21 @@ proc checkSlicesAreDisjoint(c: var AnalysisCtx) = # XXX strictly speaking, 'or' is not correct here and it needs to # be 'and'. However this prevents too many obviously correct programs # like f(a[0..x]); for i in x+1 .. a.high: f(a[i]) - overlap(c.guards, x.a, x.b, y.a, y.b) + overlap(c.guards, c.graph.config, x.a, x.b, y.a, y.b) elif (let k = simpleSlice(x.a, x.b); let m = simpleSlice(y.a, y.b); k >= 0 and m >= 0): # ah I cannot resist the temptation and add another sweet heuristic: # if both slices have the form (i+k)..(i+k) and (i+m)..(i+m) we # check they are disjoint and k < stride and m < stride: - overlap(c.guards, x.a, x.b, y.a, y.b) + overlap(c.guards, c.graph.config, x.a, x.b, y.a, y.b) let stride = min(c.stride(x.a), c.stride(y.a)) if k < stride and m < stride: discard else: - localError(x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" % + localError(c.graph.config, x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" % [?x.a, ?x.b, ?y.a, ?y.b]) else: - localError(x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" % + localError(c.graph.config, x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" % [?x.a, ?x.b, ?y.a, ?y.b]) proc analyse(c: var AnalysisCtx; n: PNode) @@ -292,31 +296,31 @@ proc analyseCall(c: var AnalysisCtx; n: PNode; op: PSym) = proc analyseCase(c: var AnalysisCtx; n: PNode) = analyse(c, n.sons[0]) - let oldFacts = c.guards.len + let oldFacts = c.guards.s.len for i in 1.. 1: - addFact(c.guards, canon(branch.sons[0])) + addFact(c.guards, canon(branch.sons[0], c.guards.o)) for i in 0 ..< branch.len: analyse(c, branch.sons[i]) - setLen(c.guards, oldFacts) + setLen(c.guards.s, oldFacts) proc analyse(c: var AnalysisCtx; n: PNode) = case n.kind @@ -349,7 +353,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) = c.addSlice(n, n[0], n[1], n[1]) analyseSons(c, n) of nkReturnStmt, nkRaiseStmt, nkTryStmt: - localError(n.info, "invalid control flow for 'parallel'") + localError(c.graph.config, n.info, "invalid control flow for 'parallel'") # 'break' that leaves the 'parallel' section is not valid either # or maybe we should generate a 'try' XXX of nkVarSection, nkLetSection: @@ -365,7 +369,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) = if it[j].isLocal: let slot = c.getSlot(it[j].sym) if slot.lower.isNil: slot.lower = value - else: internalError(it.info, "slot already has a lower bound") + else: internalError(c.graph.config, it.info, "slot already has a lower bound") if not isSpawned: analyse(c, value) of nkCaseStmt: analyseCase(c, n) of nkWhen, nkIfStmt, nkIfExpr: analyseIf(c, n) @@ -378,14 +382,14 @@ proc analyse(c: var AnalysisCtx; n: PNode) = else: # loop may never execute: let oldState = c.locals.len - let oldFacts = c.guards.len - addFact(c.guards, canon(n.sons[0])) + let oldFacts = c.guards.s.len + addFact(c.guards, canon(n.sons[0], c.guards.o)) analyse(c, n.sons[1]) setLen(c.locals, oldState) - setLen(c.guards, oldFacts) + setLen(c.guards.s, oldFacts) # we know after the loop the negation holds: if not hasSubnodeWith(n.sons[1], nkBreakStmt): - addFactNeg(c.guards, canon(n.sons[0])) + addFactNeg(c.guards, canon(n.sons[0], c.guards.o)) dec c.inLoop of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkConstSection, nkPragma, nkFuncDef: @@ -393,13 +397,13 @@ proc analyse(c: var AnalysisCtx; n: PNode) = else: analyseSons(c, n) -proc transformSlices(n: PNode): PNode = +proc transformSlices(g: ModuleGraph; n: PNode): PNode = if n.kind in nkCallKinds and n[0].kind == nkSym: let op = n[0].sym if op.name.s == "[]" and op.fromSystem: result = copyNode(n) - let opSlice = newSymNode(createMagic("slice", mSlice)) - opSlice.typ = getSysType(tyInt) + let opSlice = newSymNode(createMagic(g, "slice", mSlice)) + opSlice.typ = getSysType(g, n.info, tyInt) result.add opSlice result.add n[1] let slice = n[2].skipStmtList @@ -409,49 +413,49 @@ proc transformSlices(n: PNode): PNode = if n.safeLen > 0: result = shallowCopy(n) for i in 0 ..< n.len: - result.sons[i] = transformSlices(n.sons[i]) + result.sons[i] = transformSlices(g, n.sons[i]) else: result = n -proc transformSpawn(owner: PSym; n, barrier: PNode): PNode -proc transformSpawnSons(owner: PSym; n, barrier: PNode): PNode = +proc transformSpawn(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode +proc transformSpawnSons(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode = result = shallowCopy(n) for i in 0 ..< n.len: - result.sons[i] = transformSpawn(owner, n.sons[i], barrier) + result.sons[i] = transformSpawn(g, owner, n.sons[i], barrier) -proc transformSpawn(owner: PSym; n, barrier: PNode): PNode = +proc transformSpawn(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode = case n.kind of nkVarSection, nkLetSection: result = nil for it in n: let b = it.lastSon if getMagic(b) == mSpawn: - if it.len != 3: localError(it.info, "invalid context for 'spawn'") - let m = transformSlices(b) + if it.len != 3: localError(g.config, it.info, "invalid context for 'spawn'") + let m = transformSlices(g, b) if result.isNil: result = newNodeI(nkStmtList, n.info) result.add n let t = b[1][0].typ.sons[0] if spawnResult(t, true) == srByVar: - result.add wrapProcForSpawn(owner, m, b.typ, barrier, it[0]) + result.add wrapProcForSpawn(g, owner, m, b.typ, barrier, it[0]) it.sons[it.len-1] = emptyNode else: - it.sons[it.len-1] = wrapProcForSpawn(owner, m, b.typ, barrier, nil) + it.sons[it.len-1] = wrapProcForSpawn(g, owner, m, b.typ, barrier, nil) if result.isNil: result = n of nkAsgn, nkFastAsgn: let b = n[1] if getMagic(b) == mSpawn and (let t = b[1][0].typ.sons[0]; spawnResult(t, true) == srByVar): - let m = transformSlices(b) - return wrapProcForSpawn(owner, m, b.typ, barrier, n[0]) - result = transformSpawnSons(owner, n, barrier) + let m = transformSlices(g, b) + return wrapProcForSpawn(g, owner, m, b.typ, barrier, n[0]) + result = transformSpawnSons(g, owner, n, barrier) of nkCallKinds: if getMagic(n) == mSpawn: - result = transformSlices(n) - return wrapProcForSpawn(owner, result, n.typ, barrier, nil) - result = transformSpawnSons(owner, n, barrier) + result = transformSlices(g, n) + return wrapProcForSpawn(g, owner, result, n.typ, barrier, nil) + result = transformSpawnSons(g, owner, n, barrier) elif n.safeLen > 0: - result = transformSpawnSons(owner, n, barrier) + result = transformSpawnSons(g, owner, n, barrier) else: result = n @@ -461,7 +465,7 @@ proc checkArgs(a: var AnalysisCtx; n: PNode) = proc generateAliasChecks(a: AnalysisCtx; result: PNode) = discard "too implement" -proc liftParallel*(owner: PSym; n: PNode): PNode = +proc liftParallel*(g: ModuleGraph; owner: PSym; n: PNode): PNode = # this needs to be called after the 'for' loop elimination # first pass: @@ -470,17 +474,17 @@ proc liftParallel*(owner: PSym; n: PNode): PNode = # - detect used arguments #echo "PAR ", renderTree(n) - var a = initAnalysisCtx() + var a = initAnalysisCtx(g) let body = n.lastSon analyse(a, body) if a.spawns == 0: - localError(n.info, "'parallel' section without 'spawn'") + localError(g.config, n.info, "'parallel' section without 'spawn'") checkSlicesAreDisjoint(a) checkArgs(a, body) var varSection = newNodeI(nkVarSection, n.info) var temp = newSym(skTemp, getIdent"barrier", owner, n.info) - temp.typ = magicsys.getCompilerProc("Barrier").typ + temp.typ = magicsys.getCompilerProc(g, "Barrier").typ incl(temp.flags, sfFromGeneric) let tempNode = newSymNode(temp) varSection.addVar tempNode @@ -489,6 +493,6 @@ proc liftParallel*(owner: PSym; n: PNode): PNode = result = newNodeI(nkStmtList, n.info) generateAliasChecks(a, result) result.add varSection - result.add callCodegenProc("openBarrier", barrier) - result.add transformSpawn(owner, body, barrier) - result.add callCodegenProc("closeBarrier", barrier) + result.add callCodegenProc(g, "openBarrier", barrier) + result.add transformSpawn(g, owner, body, barrier) + result.add callCodegenProc(g, "closeBarrier", barrier) diff --git a/compiler/vm.nim b/compiler/vm.nim index 6c36a1458..84057e656 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -19,7 +19,7 @@ import ast except getstr import strutils, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, parser, vmdeps, idents, trees, renderer, options, transf, parseutils, - vmmarshal, gorgeimpl + vmmarshal, gorgeimpl, configuration from semfold import leValueConv, ordinalValToString from evaltempl import evalTemplate @@ -81,16 +81,16 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) = msgWriteln(s) proc stackTrace(c: PCtx, tos: PStackFrame, pc: int, - msg: TMsgKind, arg = "", n: PNode = nil) = + msg: string, n: PNode = nil) = msgWriteln("stack trace: (most recent call last)") stackTraceAux(c, tos, pc) # XXX test if we want 'globalError' for every mode let lineInfo = if n == nil: c.debug[pc] else: n.info - if c.mode == emRepl: globalError(lineInfo, msg, arg) - else: localError(lineInfo, msg, arg) + if c.mode == emRepl: globalError(c.config, lineInfo, msg) + else: localError(c.config, lineInfo, msg) proc bailOut(c: PCtx; tos: PStackFrame) = - stackTrace(c, tos, c.exceptionInstr, errUnhandledExceptionX, + stackTrace(c, tos, c.exceptionInstr, "unhandled exception: " & c.currentExceptionA.sons[3].skipColon.strVal) when not defined(nimComputedGoto): @@ -308,7 +308,7 @@ proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int = return pc return -1 -proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool = +proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool = if desttyp.kind == tyString: if dest.kind != rkNode: myreset(dest) @@ -323,7 +323,7 @@ proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool = dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal else: for i in 0.. max: - stackTrace(c, tos, pc, errGenerated, - msgKindToString(errUnhandledExceptionX) % "value out of range") + stackTrace(c, tos, pc, "unhandled exception: value out of range") of opcNarrowU: decodeB(rkInt) regs[ra].intVal = regs[ra].intVal and ((1'i64 shl rb)-1) @@ -1217,7 +1227,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = if u.kind notin {nkEmpty..nkNilLit}: u.add(regs[rc].node) else: - stackTrace(c, tos, pc, errGenerated, "cannot add to node kind: " & $u.kind) + stackTrace(c, tos, pc, "cannot add to node kind: " & $u.kind) regs[ra].node = u of opcNAddMultiple: decodeBC(rkNode) @@ -1227,7 +1237,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = # XXX can be optimized: for i in 0.. ord(high(TNodeKind)): - internalError(c.debug[pc], + internalError(c.config, c.debug[pc], "request to create a NimNode of invalid kind") let cc = regs[rc].node @@ -1548,7 +1559,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let name = if regs[rc].node.strVal.len == 0: ":tmp" else: regs[rc].node.strVal if k < 0 or k > ord(high(TSymKind)): - internalError(c.debug[pc], "request to create symbol of invalid kind") + internalError(c.config, c.debug[pc], "request to create symbol of invalid kind") var sym = newSym(k.TSymKind, name.getIdent, c.module.owner, c.debug[pc]) incl(sym.flags, sfGenSym) regs[ra].node = newSymNode(sym) @@ -1557,7 +1568,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = # type trait operation decodeB(rkNode) var typ = regs[rb].node.typ - internalAssert typ != nil + internalAssert c.config, typ != nil while typ.kind == tyTypeDesc and typ.len > 0: typ = typ.sons[0] createStr regs[ra] regs[ra].node.strVal = typ.typeToString(preferExported) @@ -1566,14 +1577,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let rb = instr.regB inc pc let typ = c.types[c.code[pc].regBx - wordExcess] - putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ)) + putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ, c.config)) 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) + storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode, c.config) of opcToNarrowInt: decodeBC(rkInt) let mask = (1'i64 shl rc) - 1 # 0xFF @@ -1595,7 +1606,7 @@ proc execute(c: PCtx, start: int): PNode = proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode = if sym.kind in routineKinds: if sym.typ.len-1 != args.len: - localError(sym.info, + localError(c.config, sym.info, "NimScript: expected $# arguments, but got $#" % [ $(sym.typ.len-1), $args.len]) else: @@ -1607,18 +1618,18 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode = # setup parameters: if not isEmptyType(sym.typ.sons[0]) or sym.kind == skMacro: - putIntoReg(tos.slots[0], getNullValue(sym.typ.sons[0], sym.info)) + putIntoReg(tos.slots[0], getNullValue(sym.typ.sons[0], sym.info, c.config)) # XXX We could perform some type checking here. for i in 1.. evalMacroLimit: - globalError(n.info, errMacroInstantiationTooNested) + globalError(g.config, n.info, "macro instantiation too nested") # immediate macros can bypass any type and arity checking so we check the # arity here too: if sym.typ.len > n.safeLen and sym.typ.len > 1: - globalError(n.info, "in call '$#' got $#, but expected $# argument(s)" % [ + globalError(g.config, n.info, "in call '$#' got $#, but expected $# argument(s)" % [ n.renderTree, $(n.safeLen-1), $(sym.typ.len-1)]) - setupGlobalCtx(module, cache, config) + setupGlobalCtx(module, cache, g) var c = globalCtx c.comesFromHeuristic.line = 0'u16 @@ -1781,16 +1791,16 @@ proc evalMacroCall*(module: PSym; cache: IdentCache; config: ConfigRef; else: dec(evalMacroCounter) c.callsite = nil - localError(n.info, "expected " & $gp.len & + localError(c.config, n.info, "expected " & $gp.len & " generic parameter(s)") elif gp[i].sym.typ.kind in {tyStatic, tyTypeDesc}: dec(evalMacroCounter) c.callsite = nil - globalError(n.info, "static[T] or typedesc nor supported for .immediate macros") + globalError(c.config, n.info, "static[T] or typedesc nor supported for .immediate macros") # temporary storage: #for i in L ..< maxSlots: tos.slots[i] = newNode(nkEmpty) result = rawExecute(c, start, tos).regToNode if result.info.line < 0: result.info = n.info - if cyclicTree(result): globalError(n.info, errCyclicTree) + if cyclicTree(result): globalError(c.config, n.info, "macro produced a cyclic tree") dec(evalMacroCounter) c.callsite = nil diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 56ee45b6c..e10a62006 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -208,6 +208,7 @@ type cache*: IdentCache config*: ConfigRef graph*: ModuleGraph + oldErrorCount*: int TPosition* = distinct int diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 7f8bf06c1..617295b0d 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -15,8 +15,6 @@ from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin, from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir -from options import gProjectPath - template mathop(op) {.dirty.} = registerCallback(c, "stdlib.math." & astToStr(op), `op Wrapper`) @@ -77,15 +75,15 @@ proc staticWalkDirImpl(path: string, relative: bool): PNode = result.add newTree(nkTupleConstr, newIntNode(nkIntLit, k.ord), newStrNode(nkStrLit, f)) -proc gorgeExWrapper(a: VmArgs) {.nimcall.} = - let (s, e) = opGorge(getString(a, 0), getString(a, 1), getString(a, 2), - a.currentLineInfo) - setResult a, newTree(nkTupleConstr, newStrNode(nkStrLit, s), newIntNode(nkIntLit, e)) +proc registerAdditionalOps*(c: PCtx) = + proc gorgeExWrapper(a: VmArgs) = + let (s, e) = opGorge(getString(a, 0), getString(a, 1), getString(a, 2), + a.currentLineInfo, c.config) + setResult a, newTree(nkTupleConstr, newStrNode(nkStrLit, s), newIntNode(nkIntLit, e)) -proc getProjectPathWrapper(a: VmArgs) {.nimcall.} = - setResult a, gProjectPath + proc getProjectPathWrapper(a: VmArgs) = + setResult a, c.config.projectPath -proc registerAdditionalOps*(c: PCtx) = wrap1f_math(sqrt) wrap1f_math(ln) wrap1f_math(log10) -- cgit 1.4.1-2-gfad0