diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2015-09-05 10:03:35 +0200 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2015-09-05 10:03:35 +0200 |
commit | 63a6bfce7114bd1a0cf488b0a401f043212d6216 (patch) | |
tree | 83b38df915652f9c1dc7b8d0538b4e175bc06583 | |
parent | cd9d126a2f5054092f494674a4fa33a21a416891 (diff) | |
parent | c0fa4b7d9c0fce48116102c5fa57dc722665fbe0 (diff) | |
download | Nim-63a6bfce7114bd1a0cf488b0a401f043212d6216.tar.gz |
Merge pull request #3286 from yglukhov/when-nimvm
when nimvm stmt
-rw-r--r-- | compiler/ast.nim | 3 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 3 | ||||
-rw-r--r-- | compiler/jsgen.nim | 3 | ||||
-rw-r--r-- | compiler/semexprs.nim | 41 | ||||
-rw-r--r-- | compiler/semfold.nim | 2 | ||||
-rw-r--r-- | compiler/semparallel.nim | 2 | ||||
-rw-r--r-- | compiler/sempass2.nim | 2 | ||||
-rw-r--r-- | compiler/vmgen.nim | 5 | ||||
-rw-r--r-- | doc/manual/stmts.txt | 29 | ||||
-rw-r--r-- | lib/system.nim | 4 |
10 files changed, 80 insertions, 14 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 0ad0a0718..aafe503dc 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -605,7 +605,8 @@ type mNBindSym, mLocals, mNCallSite, mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNHint, mNWarning, mNError, - mInstantiationInfo, mGetTypeInfo, mNGenSym + mInstantiationInfo, mGetTypeInfo, mNGenSym, + mNimvm # things that we can evaluate safely at compile time, even if not asked for it: const diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index c237eeffa..ba8ced52a 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2069,6 +2069,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = of nkStmtList: for i in countup(0, sonsLen(n) - 1): genStmts(p, n.sons[i]) of nkIfExpr, nkIfStmt: genIf(p, n, d) + of nkWhen: + # This should be a "when nimvm" node. + expr(p, n.sons[1].sons[0], d) of nkObjDownConv: downConv(p, n, d) of nkObjUpConv: upConv(p, n, d) of nkChckRangeF: genRangeChck(p, n, d, "chckRangeF") diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index c72365cce..36caf5e3e 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1687,6 +1687,9 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = gen(p, lastSon(n), r) of nkBlockStmt, nkBlockExpr: genBlock(p, n, r) of nkIfStmt, nkIfExpr: genIf(p, n, r) + of nkWhen: + # This is "when nimvm" node + gen(p, n.sons[1].sons[0], r) of nkWhileStmt: genWhileStmt(p, n) of nkVarSection, nkLetSection: genVarStmt(p, n) of nkConstSection: discard diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index d6f6e3a2c..fe74e75dd 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1764,22 +1764,39 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode = if semCheck: result = semStmt(c, e) # do not open a new scope! else: result = e + # Check if the node is "when nimvm" + # when nimvm: + # ... + # else: + # ... + let whenNimvm = n.sons.len == 2 and n.sons[0].kind == nkElifBranch and + n.sons[1].kind == nkElse and n.sons[0].sons[0].kind == nkIdent and + lookUp(c, n.sons[0].sons[0]).magic == mNimvm + for i in countup(0, sonsLen(n) - 1): var it = n.sons[i] case it.kind of nkElifBranch, nkElifExpr: checkSonsLen(it, 2) - var e = semConstExpr(c, it.sons[0]) - if e.kind != nkIntLit: - # can happen for cascading errors, assume false - # InternalError(n.info, "semWhen") - discard - elif e.intVal != 0 and result == nil: - setResult(it.sons[1]) + if whenNimvm: + if semCheck: + it.sons[1] = semStmt(c, it.sons[1]) + result = n # when nimvm is not elimited until codegen + else: + var e = semConstExpr(c, it.sons[0]) + if e.kind != nkIntLit: + # can happen for cascading errors, assume false + # InternalError(n.info, "semWhen") + discard + elif e.intVal != 0 and result == nil: + setResult(it.sons[1]) of nkElse, nkElseExpr: checkSonsLen(it, 1) - if result == nil: - setResult(it.sons[0]) + if result == nil or whenNimvm: + if semCheck: + it.sons[0] = semStmt(c, it.sons[0]) + if result == nil: + result = it.sons[0] else: illFormedAst(n) if result == nil: result = newNodeI(nkEmpty, n.info) @@ -2162,7 +2179,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = semWhen(c, n, true) else: result = semWhen(c, n, false) - result = semExpr(c, result, flags) + if result == n: + # This is a "when nimvm" stmt. + result = semWhen(c, n, true) + else: + result = semExpr(c, result, flags) of nkBracketExpr: checkMinSonsLen(n, 1) var s = qualifiedLookUp(c, n.sons[0], {checkUndeclared}) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 2ab43a9c9..22cf05aa8 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -640,6 +640,8 @@ proc getConstExpr(m: PSym, n: PNode): PNode = of mNaN: result = newFloatNodeT(NaN, n) of mInf: result = newFloatNodeT(Inf, n) of mNegInf: result = newFloatNodeT(NegInf, n) + of mNimvm: + localError(n.info, "illegal context for 'nimvm' magic") else: if sfFakeConst notin s.flags: result = copyTree(s.ast) of {skProc, skMethod}: diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim index fbcd6b6da..36c63d038 100644 --- a/compiler/semparallel.nim +++ b/compiler/semparallel.nim @@ -363,7 +363,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) = else: internalError(it.info, "slot already has a lower bound") if not isSpawned: analyse(c, value) of nkCaseStmt: analyseCase(c, n) - of nkIfStmt, nkIfExpr: analyseIf(c, n) + of nkWhen, nkIfStmt, nkIfExpr: analyseIf(c, n) of nkWhileStmt: analyse(c, n.sons[0]) # 'while true' loop? diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index d363eee77..272412b04 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -735,7 +735,7 @@ proc track(tracked: PEffects, n: PNode) = # since 'var (a, b): T = ()' is not even allowed, there is always type # inference for (a, b) and thus no nil checking is necessary. of nkCaseStmt: trackCase(tracked, n) - of nkIfStmt, nkIfExpr: trackIf(tracked, n) + of nkWhen, nkIfStmt, nkIfExpr: trackIf(tracked, n) of nkBlockStmt, nkBlockExpr: trackBlock(tracked, n.sons[1]) of nkWhileStmt: track(tracked, n.sons[0]) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 237a44e18..64a18a731 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1664,7 +1664,10 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = of nkBracketExpr: genArrAccess(c, n, dest, flags) of nkDerefExpr, nkHiddenDeref: genAddrDeref(c, n, dest, opcLdDeref, flags) of nkAddr, nkHiddenAddr: genAddrDeref(c, n, dest, opcAddrNode, flags) - of nkWhenStmt, nkIfStmt, nkIfExpr: genIf(c, n, dest) + of nkIfStmt, nkIfExpr: genIf(c, n, dest) + of nkWhenStmt: + # This is "when nimvm" node. Chose the first branch. + gen(c, n.sons[0].sons[1], dest) of nkCaseStmt: genCase(c, n, dest) of nkWhileStmt: unused(n, dest) diff --git a/doc/manual/stmts.txt b/doc/manual/stmts.txt index cecf37b64..3fc950b4b 100644 --- a/doc/manual/stmts.txt +++ b/doc/manual/stmts.txt @@ -329,6 +329,35 @@ The ``when`` statement enables conditional compilation techniques. As a special syntactic extension, the ``when`` construct is also available within ``object`` definitions. +When nimvm statement +--------------------- +``nimvm`` is a special symbol, that may be used as expression of ``when nimvm`` +statement to differentiate execution path between runtime and compile time. + +Example: + +.. code-block:: nim + proc someProcThatMayRunInCompileTime(): bool = + when nimvm: + # This code runs in compile time + result = true + else: + # This code runs in runtime + result = false + const ctValue = someProcThatMayRunInCompileTime() + let rtValue = someProcThatMayRunInCompileTime() + assert(ctValue == true) + assert(rtValue == false) + +``when nimvm`` statement must meet the following requirements: + +* Its expression must always be ``nimvm``. More complex expressions are not + allowed. +* It must not contain ``elif`` branches. +* It must contain ``else`` branch. +* Code in branches must not affect semantics of the code that follows the + ``when nimvm`` statement. E.g. it must not define symbols that are used in + the following code. Return statement ---------------- diff --git a/lib/system.nim b/lib/system.nim index 042813ae1..5bd8c56c7 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1173,6 +1173,10 @@ const ## "i386", "alpha", "powerpc", "powerpc64", "powerpc64el", "sparc", ## "amd64", "mips", "mipsel", "arm", "arm64". + nimvm* {.magic: "Nimvm".}: bool = false + ## may be used only in "when" expression. + ## It is true in Nim VM context and false otherwise + seqShallowFlag = low(int) proc compileOption*(option: string): bool {. |