diff --git a/compiler/ast.nim b/compiler/ast.nim index cfcdb6ea69..e2b973c11d 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -396,6 +396,36 @@ type mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError, mInstantiationInfo, mGetTypeInfo +# things that we can evaluate safely at compile time, even if not asked for it: +const + ctfeWhitelist* = {mNone, mUnaryLt, mSucc, + mPred, mInc, mDec, mOrd, mLengthOpenArray, + mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, + mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64, + mDivI64, mModI64, mAddF64, mSubF64, mMulF64, mDivF64, + mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI, + mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64, + mMinF64, mMaxF64, mAddU, mSubU, mMulU, + mDivU, mModU, mAddU64, mSubU64, mMulU64, mDivU64, mModU64, mEqI, mLeI, + mLtI, + mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64, + mLeU, mLtU, mLeU64, mLtU64, + mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef, + mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI, + mUnaryMinusI64, mAbsI, mAbsI64, mNot, + mUnaryPlusI, mBitnotI, mUnaryPlusI64, + mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64, + mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32, + mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr, + mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr, + mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet, + mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT, + mConTArr, mConTT, mSlice, + mAppendStrCh, mAppendStrStr, mAppendSeqElem, + mInRange, mInSet, mRepr, + mRand, + mCopyStr, mCopyStrLast} + type PNode* = ref TNode TNodeSeq* = seq[PNode] diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index edda1997c1..c4a3dfd779 100755 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -22,6 +22,7 @@ proc genVarTuple(p: BProc, n: PNode) = var t = tup.t for i in countup(0, L-3): var v = n.sons[i].sym + if sfCompileTime in v.flags: continue if sfGlobal in v.flags and v.kind != skForVar: assignGlobalVar(p, v) genObjectInit(p, cpsInit, v.typ, v.loc, true) @@ -46,6 +47,7 @@ proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} = proc genSingleVar(p: BProc, a: PNode) = var v = a.sons[0].sym + if sfCompileTime in v.flags: return var immediateAsgn = a.sons[2].kind != nkEmpty if sfGlobal in v.flags and v.kind != skForVar: assignGlobalVar(p, v) diff --git a/compiler/commands.nim b/compiler/commands.nim index f4afd4ee36..347e7aa046 100755 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -183,6 +183,7 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool = of "threads": result = contains(gGlobalOptions, optThreads) of "taintmode": result = contains(gGlobalOptions, optTaintMode) of "tlsemulation": result = contains(gGlobalOptions, optTlsEmulation) + of "implicitstatic": result = contains(gOptions, optImplicitStatic) else: InvalidCmdLineOption(passCmd1, switch, info) proc processPath(path: string): string = @@ -312,6 +313,8 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) = of "threads": ProcessOnOffSwitchG({optThreads}, arg, pass, info) of "tlsemulation": ProcessOnOffSwitchG({optTlsEmulation}, arg, pass, info) of "taintmode": ProcessOnOffSwitchG({optTaintMode}, arg, pass, info) + of "implicitstatic": + ProcessOnOffSwitch({optImplicitStatic}, arg, pass, info) of "opt": expectArg(switch, arg, pass, info) case arg.normalize diff --git a/compiler/evals.nim b/compiler/evals.nim index 3519e2e4d4..72c37a5d9c 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -263,7 +263,8 @@ proc evalVar(c: PEvalContext, n: PNode): PNode = for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] if a.kind == nkCommentStmt: continue - assert(a.kind == nkIdentDefs) + if a.kind != nkIdentDefs: return raiseCannotEval(c, n.info) + # XXX var (x, y) = z support? #assert(a.sons[0].kind == nkSym) can happen for transformed vars if a.sons[2].kind != nkEmpty: result = evalAux(c, a.sons[2], {}) @@ -311,17 +312,18 @@ proc evalCall(c: PEvalContext, n: PNode): PNode = if isSpecial(result): return prc = result # bind the actual params to the local parameter of a new binding - if prc.kind == nkSym: - d.prc = prc.sym - if prc.sym.kind notin {skProc, skConverter}: - InternalError(n.info, "evalCall") + if prc.kind != nkSym: InternalError(n.info, "evalCall " & n.renderTree) + d.prc = prc.sym + if prc.sym.kind notin {skProc, skConverter, skMacro}: + InternalError(n.info, "evalCall") + for i in countup(1, sonsLen(n) - 1): result = evalAux(c, n.sons[i], {}) if isSpecial(result): return d.params[i] = result if n.typ != nil: d.params[0] = getNullValue(n.typ, n.info) pushStackFrame(c, d) - result = evalAux(c, prc, {}) + result = evalAux(c, prc.sym.getBody, {}) if result.kind == nkExceptBranch: return if n.typ != nil: result = d.params[0] popStackFrame(c) @@ -489,7 +491,8 @@ proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = var s = n.sym case s.kind of skProc, skConverter, skMacro: - result = s.getBody + result = n + #result = s.getBody of skVar, skLet, skForVar, skTemp, skResult: if sfGlobal notin s.flags: result = evalVariable(c.tos, s, flags) @@ -501,7 +504,7 @@ proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = of skConst: result = s.ast of skEnumField: result = newIntNodeT(s.position, n) else: result = nil - if result == nil or sfImportc in s.flags: + if result == nil or {sfImportc, sfForward} * s.flags != {}: result = raiseCannotEval(c, n.info) proc evalIncDec(c: PEvalContext, n: PNode, sign: biggestInt): PNode = @@ -532,10 +535,13 @@ proc evalEcho(c: PEvalContext, n: PNode): PNode = result = emptyNode proc evalExit(c: PEvalContext, n: PNode): PNode = - result = evalAux(c, n.sons[1], {}) - if isSpecial(result): return - Message(n.info, hintQuitCalled) - quit(int(getOrdValue(result))) + if c.mode in {emRepl, emStatic}: + result = evalAux(c, n.sons[1], {}) + if isSpecial(result): return + Message(n.info, hintQuitCalled) + quit(int(getOrdValue(result))) + else: + result = raiseCannotEval(c, n.info) proc evalOr(c: PEvalContext, n: PNode): PNode = result = evalAux(c, n.sons[1], {}) @@ -636,19 +642,22 @@ proc evalConvCStrToStr(c: PEvalContext, n: PNode): PNode = result.typ = n.typ proc evalRaise(c: PEvalContext, n: PNode): PNode = - if n.sons[0].kind != nkEmpty: - result = evalAux(c, n.sons[0], {}) - if isSpecial(result): return - var a = result - result = newNodeIT(nkExceptBranch, n.info, a.typ) - addSon(result, a) - c.lastException = result - elif c.lastException != nil: - result = c.lastException - else: - stackTrace(c, n, errExceptionAlreadyHandled) - result = newNodeIT(nkExceptBranch, n.info, nil) - addSon(result, ast.emptyNode) + if c.mode in {emRepl, emStatic}: + if n.sons[0].kind != nkEmpty: + result = evalAux(c, n.sons[0], {}) + if isSpecial(result): return + var a = result + result = newNodeIT(nkExceptBranch, n.info, a.typ) + addSon(result, a) + c.lastException = result + elif c.lastException != nil: + result = c.lastException + else: + stackTrace(c, n, errExceptionAlreadyHandled) + result = newNodeIT(nkExceptBranch, n.info, nil) + addSon(result, ast.emptyNode) + else: + result = raiseCannotEval(c, n.info) proc evalReturn(c: PEvalContext, n: PNode): PNode = if n.sons[0].kind != nkEmpty: @@ -1266,28 +1275,37 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = InternalError(n.info, "evalAux: returned nil " & $n.kind) inc(gNestedEvals) -proc eval*(c: PEvalContext, n: PNode): PNode = - ## eval never returns nil! This simplifies the code a lot and - ## makes it faster too. +proc tryEval(c: PEvalContext, n: PNode): PNode = var n = transform(c.module, n) gWhileCounter = evalMaxIterations gNestedEvals = evalMaxRecDepth result = evalAux(c, n, {}) + +proc eval*(c: PEvalContext, n: PNode): PNode = + ## eval never returns nil! This simplifies the code a lot and + ## makes it faster too. + result = tryEval(c, n) if result.kind == nkExceptBranch: if sonsLen(result) >= 1: stackTrace(c, n, errUnhandledExceptionX, typeToString(result.typ)) else: stackTrace(c, n, errCannotInterpretNodeX, renderTree(n)) -proc evalConstExpr*(module: PSym, e: PNode): PNode = - var p = newEvalContext(module, "", emConst) +proc evalConstExprAux(module: PSym, e: PNode, mode: TEvalMode): PNode = + var p = newEvalContext(module, "", mode) var s = newStackFrame() s.call = e pushStackFrame(p, s) - result = eval(p, e) + result = tryEval(p, e) if result != nil and result.kind == nkExceptBranch: result = nil popStackFrame(p) +proc evalConstExpr*(module: PSym, e: PNode): PNode = + result = evalConstExprAux(module, e, emConst) + +proc evalStaticExpr*(module: PSym, e: PNode): PNode = + result = evalConstExprAux(module, e, emStatic) + proc evalMacroCall*(c: PEvalContext, n: PNode, sym: PSym): PNode = # XXX GlobalError() is ugly here, but I don't know a better solution for now inc(evalTemplateCounter) diff --git a/compiler/options.nim b/compiler/options.nim index 18f8847968..ff51ad66c2 100755 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -25,7 +25,9 @@ type # please make sure we have under 32 options optEndb, # embedded debugger optByRef, # use pass by ref for objects # (for interfacing with C) - optProfiler # profiler turned on + optProfiler, # profiler turned on + optImplicitStatic # optimization: implicit at compile time + # evaluation TOptions* = set[TOption] TGlobalOption* = enum # **keep binary compatible** gloptNone, optForceFullMake, optBoehmGC, optRefcGC, optDeadCodeElim, diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 72356eafd4..99570aa126 100755 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -277,6 +277,7 @@ proc processOption(c: PContext, n: PNode) = excl(gOptions, optOptimizeSpeed) excl(gOptions, optOptimizeSize) else: LocalError(n.info, errNoneSpeedOrSizeExpected) + of wImplicitStatic: OnOff(c, n, {optImplicitStatic}) else: LocalError(n.info, errOptionExpected) proc processPush(c: PContext, n: PNode, start: int) = diff --git a/compiler/sem.nim b/compiler/sem.nim index 8bb8758b7d..1bc2cee098 100755 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -85,13 +85,6 @@ proc semConstExpr(c: PContext, n: PNode): PNode = result = evalConstExpr(c.module, e) if result == nil or result.kind == nkEmpty: GlobalError(n.info, errConstExprExpected) - when false: - result = semExprWithType(c, n) - if result == nil: - GlobalError(n.info, errConstExprExpected) - return - result = getConstExpr(c.module, result) - if result == nil: GlobalError(n.info, errConstExprExpected) proc semAndEvalConstExpr(c: PContext, n: PNode): PNode = result = semConstExpr(c, n) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index e6e1f5b11f..e45376ed97 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -475,6 +475,39 @@ proc expectStringArg(c: PContext, n: PNode, i: int): PNode = include semmagic +proc evalAtCompileTime(c: PContext, n: PNode): PNode = + result = n + if n.kind notin nkCallKinds or n.sons[0].kind != nkSym: return + var callee = n.sons[0].sym + + if {sfNoSideEffect, sfCompileTime} * callee.flags != {} and + {sfForward, sfImportc} * callee.flags == {}: + if sfCompileTime notin callee.flags and + optImplicitCompileTime notin gOptions: return + + if callee.magic notin ctfeWhitelist: return + if callee.kind notin {skProc, skConverter} or callee.isGenericRoutine: + return + + if n.typ != nil and not typeAllowed(n.typ, skConst): return + + var call = newNodeIT(nkCall, n.info, n.typ) + call.add(n.sons[0]) + for i in 1 .. < n.len: + let a = getConstExpr(c.module, n.sons[i]) + if a == nil: return n + call.add(a) + #echo "NOW evaluating at compile time: ", call.renderTree + if sfCompileTime in callee.flags: + result = evalStaticExpr(c.module, call) + if result.isNil: + LocalError(n.info, errCannotInterpretNodeX, renderTree(call)) + else: + result = evalConstExpr(c.module, call) + if result.isNil: result = n + #if result != n: + # echo "SUCCESS evaluated at compile time: ", call.renderTree + proc semDirectCallAnalyseEffects(c: PContext, n: PNode, flags: TExprFlags): PNode = if efWantIterator in flags: @@ -490,7 +523,7 @@ proc semDirectCallAnalyseEffects(c: PContext, n: PNode, var callee = result.sons[0].sym if (callee.kind == skIterator) and (callee.id == c.p.owner.id): GlobalError(n.info, errRecursiveDependencyX, callee.name.s) - if sfNoSideEffect notin callee.flags: + if sfNoSideEffect notin callee.flags: if {sfImportc, sfSideEffect} * callee.flags != {}: incl(c.p.owner.flags, sfSideEffect) @@ -544,6 +577,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = analyseIfAddressTakenInCall(c, result) if result.sons[0].kind == nkSym and result.sons[0].sym.magic != mNone: result = magicsAfterOverloadResolution(c, result, flags) + result = evalAtCompileTime(c, result) proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = # this seems to be a hotspot in the compiler! @@ -556,6 +590,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = analyseIfAddressTakenInCall(c, result) if result.sons[0].sym.magic != mNone: result = magicsAfterOverloadResolution(c, result, flags) + result = evalAtCompileTime(c, result) proc buildStringify(c: PContext, arg: PNode): PNode = if arg.typ != nil and skipTypes(arg.typ, abstractInst).kind == tyString: diff --git a/compiler/types.nim b/compiler/types.nim index d2359faaeb..5f7496fc0d 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -827,7 +827,8 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool = if ContainsOrIncl(marker, typ.id): return var t = skipTypes(typ, abstractInst) case t.kind - of tyVar: + of tyVar: + if kind == skConst: return false var t2 = skipTypes(t.sons[0], abstractInst) case t2.kind of tyVar: @@ -866,6 +867,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool = result = t.sons[1].kind == tyEmpty or typeAllowedAux(marker, t.sons[1], skVar) of tyPtr, tyRef: + if kind == skConst: return false result = typeAllowedAux(marker, t.sons[0], skVar) of tyArrayConstr, tyTuple, tySet, tyConst, tyMutable, tyIter, tyProxy: for i in countup(0, sonsLen(t) - 1): diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 76788a22e7..2d8f25db64 100755 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -30,8 +30,8 @@ type wInclude, wIs, wIsnot, wIterator, wLambda, wLet, wMacro, wMethod, wMod, wNil, wNot, wNotin, wObject, wOf, wOr, wOut, wProc, wPtr, wRaise, wRef, wReturn, - wShl, wShr, wTemplate, wTry, wTuple, wType, wVar, wWhen, wWhile, wWith, - wWithout, wXor, wYield, + wShl, wShr, wStatic, wTemplate, wTry, wTuple, wType, wVar, + wWhen, wWhile, wWith, wWithout, wXor, wYield, wColon, wColonColon, wEquals, wDot, wDotDot, wStar, wMinus, @@ -57,7 +57,8 @@ type wFieldChecks, wWatchPoint, wSubsChar, wAcyclic, wShallow, wUnroll, wLinearScanEnd, - wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wNoStackFrame + wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wNoStackFrame, + wImplicitStatic TSpecialWords* = set[TSpecialWord] @@ -75,8 +76,9 @@ 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", - "try", "tuple", "type", "var", "when", "while", "with", "without", "xor", + "out", "proc", "ptr", "raise", "ref", "return", "shl", "shr", "static", + "template", "try", "tuple", "type", "var", + "when", "while", "with", "without", "xor", "yield", ":", "::", "=", ".", "..", @@ -105,7 +107,7 @@ const "watchpoint", "subschar", "acyclic", "shallow", "unroll", "linearscanend", "write", "putenv", "prependenv", "appendenv", "threadvar", "emit", - "nostackframe"] + "nostackframe", "implicitstatic"] proc findStr*(a: openarray[string], s: string): int = for i in countup(low(a), high(a)): diff --git a/doc/advopt.txt b/doc/advopt.txt index b43e5e511f..876e049041 100755 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -51,6 +51,7 @@ Advanced options: --tlsEmulation:on|off turn thread local storage emulation on|off --taintMode:on|off turn taint mode on|off --symbolFiles:on|off turn symbol files on|off (experimental) + --implicitStatic:on|off turn implicit compile time evaluation on|off --skipCfg do not read the general configuration file --skipUserCfg do not read the user's configuration file --skipParentCfg do not read the parent dirs' configuration files diff --git a/doc/grammar.txt b/doc/grammar.txt index 325a29ad5a..4fb18024d1 100755 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -26,6 +26,7 @@ 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 @@ -37,7 +38,7 @@ primarySuffix ::= '.' optInd symbol [generalizedLit] | '{' optInd [indexExpr (comma indexExpr)* [comma]] optPar '}' primary ::= primaryPrefix* (symbol [generalizedLit] | - constructor | castExpr | addrExpr) + constructor | castExpr | addrExpr | staticExpr) primarySuffix* generalizedLit ::= GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT @@ -97,7 +98,7 @@ simpleStmt ::= returnStmt | includeStmt | exprStmt complexStmt ::= ifStmt | whileStmt | caseStmt | tryStmt | forStmt - | blockStmt | asmStmt + | blockStmt | staticStmt | asmStmt | procDecl | iteratorDecl | macroDecl | templateDecl | methodDecl | constSection | letSection | varSection | typeSection | whenStmt | bindStmt @@ -131,6 +132,7 @@ tryStmt ::= 'try' ':' stmt ['finally' ':' stmt] asmStmt ::= 'asm' [pragma] (STR_LIT | RSTR_LIT | TRIPLESTR_LIT) blockStmt ::= 'block' [symbol] ':' stmt +staticStmt ::= 'static' ':' stmt filename ::= symbol | STR_LIT | RSTR_LIT | TRIPLESTR_LIT importStmt ::= 'import' filename (comma filename)* includeStmt ::= 'include' filename (comma filename)* diff --git a/doc/keywords.txt b/doc/keywords.txt index c4e073417d..9638dc12ad 100755 --- a/doc/keywords.txt +++ b/doc/keywords.txt @@ -12,7 +12,7 @@ nil not notin object of or out proc ptr raise ref return -shl shr +shl shr static template try tuple type var when while with without diff --git a/doc/manual.txt b/doc/manual.txt index 9627e18c7d..9b53623241 100755 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -1640,6 +1640,30 @@ Constants cannot be of type ``ptr``, ``ref``, ``var`` or ``object``, nor can they contain such a type. +Static statement/expression +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Syntax:: + staticExpr ::= 'static' '(' optInd expr optPar ')' + staticStmt ::= 'static' ':' stmt + +A `static`:idx: statement/expression can be used to enforce compile +time evaluation explicitely. Enforced compile time evaluation can even evaluate +code that has side effects: + +.. code-block:: + + static: + echo "echo at compile time" + +It's a static error if the compiler cannot perform the evaluation at compile time. + +The current implementation poses some restrictions for compile time +evaluation: Code which contains ``cast`` or makes use of the foreign function +interface cannot be evaluated at compile time. Later versions of Nimrod will +support the FFI at compile time. + + If statement ~~~~~~~~~~~~ diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 19869c8eb1..2e82e13758 100755 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -87,7 +87,8 @@ type ## represents a Nimrod *symbol* in the compiler; a *symbol* is a looked-up ## *ident*. - PNimrodNode* = expr + TNimrodNode {.final.} = object + PNimrodNode* = ref TNimrodNode ## represents a Nimrod AST node. Macros operate on this type. const diff --git a/lib/system.nim b/lib/system.nim index bfaa5eb8fa..c92c86443e 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -2213,12 +2213,12 @@ proc shallow*(s: var string) {.noSideEffect, inline.} = var s = cast[PGenericSeq](s) s.reserved = s.reserved or seqShallowFlag -template static*(e: expr): expr = - ## evaluates a given expression `e` at compile-time - ## even if it has side effects - block: - const res = e - res +#template static*(e: expr): expr = +# ## evaluates a given expression `e` at compile-time +# ## even if it has side effects +# block: +# const res = e +# res template eval*(blk: stmt): stmt = ## executes a block of code at compile time just as if it was a macro diff --git a/tests/run/tidgen.nim b/tests/run/tidgen.nim index 68fffbabb5..0e856dc19b 100644 --- a/tests/run/tidgen.nim +++ b/tests/run/tidgen.nim @@ -6,14 +6,14 @@ import macros # Test compile-time state in same module -var gid = 3 +var gid {.compileTime.} = 3 macro genId(invokation: expr): expr = result = newIntLitNode(gid) inc gid -proc Id1(): int = return genId() -proc Id2(): int = return genId() +proc Id1(): int {.compileTime.} = return genId() +proc Id2(): int {.compileTime.} = return genId() echo Id1(), " ", Id2() diff --git a/todo.txt b/todo.txt index 50fc080b99..6c22d85542 100755 --- a/todo.txt +++ b/todo.txt @@ -1,7 +1,9 @@ version 0.9.0 ============= -- implement 'static' vs. 'const' +- implement 'static' vs. 'const'; + clear separation between tyExpr and PNimrodNode + - ``=`` should be overloadable; requires specialization for ``=`` - fix remaining generics bugs - fix remaining closure bugs: @@ -24,7 +26,6 @@ version 0.9.0 loop hoisting - we need to support iteration of 2 different data structures in parallel - make exceptions compatible with C++ exceptions -- 'const' objects including case objects - change how comments are part of the AST - optional indentation for 'case' statement; hm, keep in mind other syntax changes that people want; may turn out to be a bad idea @@ -77,6 +78,7 @@ version 0.9.XX - make pegs support a compile-time option and make c2nim use regexes instead per default? - fix implicit generic routines +- 'const' objects including case objects - improve docgen to use the semantic pass - 'export' feature (requires improved docgen) - think about ``{:}.toTable[int, string]()`` @@ -102,7 +104,7 @@ version 0.9.XX Library ------- -- wrappers for poppler; libharu +- wrappers for mongodb; poppler; libharu - suffix trees - locale support; i18n module - bignums diff --git a/web/news.txt b/web/news.txt index 540ba144a8..3eda8ed65f 100755 --- a/web/news.txt +++ b/web/news.txt @@ -19,8 +19,6 @@ Library Additions - Added ``system.shallow`` that can be used to speed up string and sequence assignments. -- Added ``system.static`` that can force compile-time evaluation of certain - expressions. - Added ``system.eval`` that can execute an anonymous block of code at compile time as if was a macro. - Added ``macros.emit`` that can emit an arbitrary computed string as nimrod @@ -34,11 +32,22 @@ Changes affecting backwards compatibility The ``system``, ``os``, ``osproc`` and ``memfiles`` modules use the wide string versions of the WinAPI. Use the ``-d:useWinAnsi`` switch to revert back to the old behaviour which uses the Ansi string versions. - +- ``static`` is now a keyword. + + Compiler Additions ------------------ - Win64 is now an officially supported target. +- The compiler can detect and evaluate calls that can be evaluated at compile + time for optimization purposes with the ``--implicitStatic`` command line + option or pragma. + + +Language Additions +------------------ + +- Added explicit ``static`` sections for enforced compile time evaluation. 2012-02-09 Version 0.8.14 released