mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-14 15:23:27 +00:00
first steps for cleaner static/const distinction
This commit is contained in:
@@ -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]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) =
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
8
todo.txt
8
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
|
||||
|
||||
15
web/news.txt
15
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
|
||||
|
||||
Reference in New Issue
Block a user