From 4da067691eb61554515197fa79392b1509c2e566 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 15 Mar 2012 00:28:28 +0100 Subject: [PATCH] implemented 'static'; macros do not work anymore --- compiler/ast.nim | 4 +++- compiler/lexer.nim | 6 ++++-- compiler/parser.nim | 21 +++++++++++++++++++-- compiler/renderer.nim | 16 ++++++++++++++++ compiler/semexprs.nim | 10 +++++++++- compiler/semstmts.nim | 8 ++++++++ doc/grammar.txt | 6 ++---- lib/core/macros.nim | 20 ++++++++++---------- todo.txt | 3 +-- web/news.txt | 1 + 10 files changed, 73 insertions(+), 22 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index e2b973c11..6b2681f2a 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -105,6 +105,7 @@ type nkHiddenCallConv, # an implicit type conversion via a type converter nkConv, # a type conversion nkCast, # a type cast + nkStaticExpr, # a static expr nkAddr, # a addr expression nkHiddenAddr, # implicit address operator nkHiddenDeref, # implicit ^ operator @@ -160,6 +161,7 @@ type nkBreakStmt, # a break statement nkContinueStmt, # a continue statement nkBlockStmt, # a block statement + nkStaticStmt, # a static statement nkDiscardStmt, # a discard statement nkStmtList, # a list of statements nkImportStmt, # an import statement @@ -384,7 +386,7 @@ type mOrdinal, mInt, mInt8, mInt16, mInt32, mInt64, mFloat, mFloat32, mFloat64, mBool, mChar, mString, mCstring, mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc, - mVoidType, + mVoidType, mPNimrodNode, mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor, mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mAppType, mNaN, mInf, mNegInf, diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 19a470ddd..496f7d2f1 100755 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -39,7 +39,8 @@ type tkGeneric, tkIf, tkImport, tkIn, tkInclude, tkIs, tkIsnot, tkIterator, tkLambda, tkLet, tkMacro, tkMethod, tkMod, tkNil, tkNot, tkNotin, tkObject, tkOf, tkOr, - tkOut, tkProc, tkPtr, tkRaise, tkRef, tkReturn, tkShl, tkShr, tkTemplate, + tkOut, tkProc, tkPtr, tkRaise, tkRef, tkReturn, tkShl, tkShr, tkStatic, + tkTemplate, tkTry, tkTuple, tkType, tkVar, tkWhen, tkWhile, tkWith, tkWithout, tkXor, tkYield, # end of keywords tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit, tkFloatLit, @@ -70,7 +71,8 @@ const "import", "in", "include", "is", "isnot", "iterator", "lambda", "let", "macro", "method", "mod", "nil", "not", "notin", "object", "of", "or", - "out", "proc", "ptr", "raise", "ref", "return", "shl", "shr", "template", + "out", "proc", "ptr", "raise", "ref", "return", "shl", "shr", "static", + "template", "try", "tuple", "type", "var", "when", "while", "with", "without", "xor", "yield", "tkIntLit", "tkInt8Lit", "tkInt16Lit", "tkInt32Lit", "tkInt64Lit", diff --git a/compiler/parser.nim b/compiler/parser.nim index 5d7a9a6e9..ba7107c42 100755 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -436,8 +436,6 @@ proc identOrLiteral(p: var TParser): PNode = tkColon) of tkCast: result = parseCast(p) - of tkAddr: - result = parseAddr(p) else: parMessage(p, errExprExpected, p.tok) getTok(p) # we must consume a token here to prevend endless loops! @@ -453,6 +451,16 @@ proc primary(p: var TParser): PNode = optInd(p, a) addSon(result, primary(p)) return + elif p.tok.tokType == tkAddr: + result = newNodeP(nkAddr, p) + getTok(p) + addSon(result, primary(p)) + return + elif p.tok.tokType == tkStatic: + result = newNodeP(nkStaticExpr, p) + getTok(p) + addSon(result, primary(p)) + return elif p.tok.tokType == tkBind: result = newNodeP(nkBind, p) getTok(p) @@ -980,6 +988,14 @@ proc parseBlock(p: var TParser): PNode = skipComment(p, result) addSon(result, parseStmt(p)) +proc parseStatic(p: var TParser): PNode = + result = newNodeP(nkStaticStmt, p) + getTok(p) + optInd(p, result) + eat(p, tkColon) + skipComment(p, result) + addSon(result, parseStmt(p)) + proc parseAsm(p: var TParser): PNode = result = newNodeP(nkAsmStmt, p) getTok(p) @@ -1379,6 +1395,7 @@ proc complexOrSimpleStmt(p: var TParser): PNode = of tkTry: result = parseTry(p) of tkFor: result = parseFor(p) of tkBlock: result = parseBlock(p) + of tkStatic: result = parseStatic(p) of tkAsm: result = parseAsm(p) of tkProc: result = parseRoutine(p, nkProcDef) of tkMethod: result = parseRoutine(p, nkMethodDef) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index f185b51d8..0be578a1a 100755 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -336,6 +336,7 @@ proc lsub(n: PNode): int = of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: result = lsub(n[1]) of nkCast: result = lsub(n.sons[0]) + lsub(n.sons[1]) + len("cast[]()") of nkAddr: result = lsub(n.sons[0]) + len("addr()") + of nkStaticExpr: result = lsub(n.sons[0]) + len("static_") of nkHiddenAddr, nkHiddenDeref: result = lsub(n.sons[0]) of nkCommand: result = lsub(n.sons[0]) + lcomma(n, 1) + 1 of nkExprEqExpr, nkAsgn, nkFastAsgn: result = lsons(n) + 3 @@ -640,6 +641,16 @@ proc gblock(g: var TSrcGen, n: PNode) = gstmts(g, n.sons[1], c) dedent(g) +proc gstaticStmt(g: var TSrcGen, n: PNode) = + var c: TContext + putWithSpace(g, tkStatic, "static") + putWithSpace(g, tkColon, ":") + initContext(c) + if longMode(n) or (lsub(n.sons[0]) + g.lineLen > maxLineLen): + incl(c.flags, rfLongMode) + gcoms(g) # a good place for comments + gstmts(g, n.sons[0], c) + proc gasm(g: var TSrcGen, n: PNode) = putWithSpace(g, tkAsm, "asm") gsub(g, n.sons[0]) @@ -711,6 +722,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkParLe, "(") gsub(g, n.sons[0]) put(g, tkParRi, ")") + of nkStaticExpr: + put(g, tkStatic, "static") + put(g, tkSpaces, space) + gsub(g, n.sons[0]) of nkBracketExpr: gsub(g, n.sons[0]) put(g, tkBracketLe, "[") @@ -951,6 +966,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = of nkTryStmt: gtry(g, n) of nkForStmt: gfor(g, n) of nkBlockStmt, nkBlockExpr: gblock(g, n) + of nkStaticStmt: gstaticStmt(g, n) of nkAsmStmt: gasm(g, n) of nkProcDef: putWithSpace(g, tkProc, "proc") diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index e45376ed9..d423acc17 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -483,7 +483,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = if {sfNoSideEffect, sfCompileTime} * callee.flags != {} and {sfForward, sfImportc} * callee.flags == {}: if sfCompileTime notin callee.flags and - optImplicitCompileTime notin gOptions: return + optImplicitStatic notin gOptions: return if callee.magic notin ctfeWhitelist: return if callee.kind notin {skProc, skConverter} or callee.isGenericRoutine: @@ -508,6 +508,12 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = #if result != n: # echo "SUCCESS evaluated at compile time: ", call.renderTree +proc semStaticExpr(c: PContext, n: PNode): PNode = + let a = semExpr(c, n.sons[0]) + result = evalStaticExpr(c.module, a) + if result.isNil: + LocalError(n.info, errCannotInterpretNodeX, renderTree(n)) + proc semDirectCallAnalyseEffects(c: PContext, n: PNode, flags: TExprFlags): PNode = if efWantIterator in flags: @@ -1342,6 +1348,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = semTableConstr(c, n) of nkSymChoice: GlobalError(n.info, errExprXAmbiguous, renderTree(n, {renderNoComments})) + of nkStaticExpr: + result = semStaticExpr(c, n) else: GlobalError(n.info, errInvalidExpressionX, renderTree(n, {renderNoComments})) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index bd69805b3..8b758d9f7 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -840,6 +840,12 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode = if whichPragma(pragmaList.sons[i]) == wLine: setLine(result, pragmaList.sons[i].info) +proc semStaticStmt(c: PContext, n: PNode): PNode = + let a = semStmt(c, n.sons[0]) + result = evalStaticExpr(c.module, a) + if result.isNil: + LocalError(n.info, errCannotInterpretNodeX, renderTree(n)) + proc SemStmt(c: PContext, n: PNode): PNode = const # must be last statements in a block: LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt} @@ -896,6 +902,8 @@ proc SemStmt(c: PContext, n: PNode): PNode = result = evalInclude(c, n) of nkPragmaBlock: result = semPragmaBlock(c, n) + of nkStaticStmt: + result = semStaticStmt(c, n) else: # in interactive mode, we embed the expression in an 'echo': if gCmd == cmdInteractive: diff --git a/doc/grammar.txt b/doc/grammar.txt index 4fb18024d..8a39c5abc 100755 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -4,7 +4,7 @@ comma ::= ',' [COMMENT] [IND] operator ::= OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9 | 'or' | 'xor' | 'and' | 'is' | 'isnot' | 'in' | 'notin' | 'of' - | 'div' | 'mod' | 'shl' | 'shr' | 'not' | '..' + | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'addr' | 'static' | '..' prefixOperator ::= operator @@ -25,8 +25,6 @@ dollarExpr ::= primary (OP9 optInd primary)* indexExpr ::= expr castExpr ::= 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')' -addrExpr ::= 'addr' '(' optInd expr optPar ')' -staticExpr ::= 'static' '(' optInd expr optPar ')' symbol ::= '`' (KEYWORD | IDENT | operator | '(' ')' | '[' ']' | '{' '}' | '=' | literal)+ '`' | IDENT @@ -38,7 +36,7 @@ primarySuffix ::= '.' optInd symbol [generalizedLit] | '{' optInd [indexExpr (comma indexExpr)* [comma]] optPar '}' primary ::= primaryPrefix* (symbol [generalizedLit] | - constructor | castExpr | addrExpr | staticExpr) + constructor | castExpr) primarySuffix* generalizedLit ::= GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 2e82e1375..b6b9174cd 100755 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -27,7 +27,7 @@ type nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkIfExpr, nnkElifExpr, nnkElseExpr, nnkLambda, nnkDo, nnkAccQuoted, nnkTableConstr, nnkBind, nnkSymChoice, nnkHiddenStdConv, - nnkHiddenSubConv, nnkHiddenCallConv, nnkConv, nnkCast, + nnkHiddenSubConv, nnkHiddenCallConv, nnkConv, nnkCast, nnkStaticExpr, nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv, nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange, nnkStringToCString, nnkCStringToString, nnkAsgn, @@ -40,7 +40,7 @@ type nnkTypeSection, nnkVarSection, nnkLetSection, nnkConstSection, nnkConstDef, nnkTypeDef, nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt, - nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, + nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkStaticStmt, nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt, nnkIncludeStmt, nnkBindStmt, nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr, @@ -88,7 +88,7 @@ type ## *ident*. TNimrodNode {.final.} = object - PNimrodNode* = ref TNimrodNode + PNimrodNode* {.magic: "PNimrodNode".} = ref TNimrodNode ## represents a Nimrod AST node. Macros operate on this type. const @@ -263,7 +263,7 @@ proc newCall*(theProc: string, proc nestList*(theProc: TNimrodIdent, x: PNimrodNode): PNimrodNode {.compileTime.} = ## nests the list `x` into a tree of call expressions: - ## ``[a, b, c]`` is transformed into ``theProc(a, theProc(c, d))`` + ## ``[a, b, c]`` is transformed into ``theProc(a, theProc(c, d))``. var L = x.len result = newCall(theProc, x[L-2], x[L-1]) var a = result @@ -271,9 +271,9 @@ proc nestList*(theProc: TNimrodIdent, a = newCall(theProc, x[i], copyNimTree(a)) proc treeRepr*(n: PNimrodNode): string {.compileTime.} = - ## Convert the AST `n` to a human-readable tree-like string + ## Convert the AST `n` to a human-readable tree-like string. ## - ## see also `repr` and `lispRepr` + ## See also `repr` and `lispRepr`. proc traverse(res: var string, level: int, n: PNimrodNode) = for i in 0..level-1: res.add " " @@ -300,9 +300,9 @@ proc treeRepr*(n: PNimrodNode): string {.compileTime.} = traverse(result, 0, n) proc lispRepr*(n: PNimrodNode): string {.compileTime.} = - ## Convert the AST `n` to a human-readable lisp-like string + ## Convert the AST `n` to a human-readable lisp-like string, ## - ## see also `repr` and `treeRepr` + ## See also `repr` and `treeRepr`. if n == nil: return "nil" @@ -331,11 +331,11 @@ macro dumpTree*(s: stmt): stmt = echo s[1].treeRepr ## ## You can use this as a tool to explore the Nimrod's abstract syntax ## tree and to discover what kind of nodes must be created to represent - ## a certain expression/statement + ## a certain expression/statement. macro dumpLisp*(s: stmt): stmt = echo s[1].lispRepr ## Accepts a block of nimrod code and prints the parsed abstract syntax ## tree using the `toLisp` function. ## - ## see `dumpTree` + ## See `dumpTree`. diff --git a/todo.txt b/todo.txt index 6c22d8554..47c2cf570 100755 --- a/todo.txt +++ b/todo.txt @@ -1,8 +1,7 @@ version 0.9.0 ============= -- implement 'static' vs. 'const'; - clear separation between tyExpr and PNimrodNode +- clean separation between tyExpr and PNimrodNode - ``=`` should be overloadable; requires specialization for ``=`` - fix remaining generics bugs diff --git a/web/news.txt b/web/news.txt index 3eda8ed65..de9624225 100755 --- a/web/news.txt +++ b/web/news.txt @@ -48,6 +48,7 @@ Language Additions ------------------ - Added explicit ``static`` sections for enforced compile time evaluation. +- ``addr`` is now treated like a prefix operator syntactically. 2012-02-09 Version 0.8.14 released