commit
63a6bfce71
10 changed files with 80 additions and 14 deletions
|
|
@ -605,7 +605,8 @@ type
|
||||||
mNBindSym, mLocals, mNCallSite,
|
mNBindSym, mLocals, mNCallSite,
|
||||||
mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl,
|
mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl,
|
||||||
mNHint, mNWarning, mNError,
|
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:
|
# things that we can evaluate safely at compile time, even if not asked for it:
|
||||||
const
|
const
|
||||||
|
|
|
||||||
|
|
@ -2069,6 +2069,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
of nkStmtList:
|
of nkStmtList:
|
||||||
for i in countup(0, sonsLen(n) - 1): genStmts(p, n.sons[i])
|
for i in countup(0, sonsLen(n) - 1): genStmts(p, n.sons[i])
|
||||||
of nkIfExpr, nkIfStmt: genIf(p, n, d)
|
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 nkObjDownConv: downConv(p, n, d)
|
||||||
of nkObjUpConv: upConv(p, n, d)
|
of nkObjUpConv: upConv(p, n, d)
|
||||||
of nkChckRangeF: genRangeChck(p, n, d, "chckRangeF")
|
of nkChckRangeF: genRangeChck(p, n, d, "chckRangeF")
|
||||||
|
|
|
||||||
|
|
@ -1687,6 +1687,9 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
gen(p, lastSon(n), r)
|
gen(p, lastSon(n), r)
|
||||||
of nkBlockStmt, nkBlockExpr: genBlock(p, n, r)
|
of nkBlockStmt, nkBlockExpr: genBlock(p, n, r)
|
||||||
of nkIfStmt, nkIfExpr: genIf(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 nkWhileStmt: genWhileStmt(p, n)
|
||||||
of nkVarSection, nkLetSection: genVarStmt(p, n)
|
of nkVarSection, nkLetSection: genVarStmt(p, n)
|
||||||
of nkConstSection: discard
|
of nkConstSection: discard
|
||||||
|
|
|
||||||
|
|
@ -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!
|
if semCheck: result = semStmt(c, e) # do not open a new scope!
|
||||||
else: result = e
|
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):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
case it.kind
|
case it.kind
|
||||||
of nkElifBranch, nkElifExpr:
|
of nkElifBranch, nkElifExpr:
|
||||||
checkSonsLen(it, 2)
|
checkSonsLen(it, 2)
|
||||||
var e = semConstExpr(c, it.sons[0])
|
if whenNimvm:
|
||||||
if e.kind != nkIntLit:
|
if semCheck:
|
||||||
# can happen for cascading errors, assume false
|
it.sons[1] = semStmt(c, it.sons[1])
|
||||||
# InternalError(n.info, "semWhen")
|
result = n # when nimvm is not elimited until codegen
|
||||||
discard
|
else:
|
||||||
elif e.intVal != 0 and result == nil:
|
var e = semConstExpr(c, it.sons[0])
|
||||||
setResult(it.sons[1])
|
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:
|
of nkElse, nkElseExpr:
|
||||||
checkSonsLen(it, 1)
|
checkSonsLen(it, 1)
|
||||||
if result == nil:
|
if result == nil or whenNimvm:
|
||||||
setResult(it.sons[0])
|
if semCheck:
|
||||||
|
it.sons[0] = semStmt(c, it.sons[0])
|
||||||
|
if result == nil:
|
||||||
|
result = it.sons[0]
|
||||||
else: illFormedAst(n)
|
else: illFormedAst(n)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
result = newNodeI(nkEmpty, n.info)
|
result = newNodeI(nkEmpty, n.info)
|
||||||
|
|
@ -2162,7 +2179,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
result = semWhen(c, n, true)
|
result = semWhen(c, n, true)
|
||||||
else:
|
else:
|
||||||
result = semWhen(c, n, false)
|
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:
|
of nkBracketExpr:
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
var s = qualifiedLookUp(c, n.sons[0], {checkUndeclared})
|
var s = qualifiedLookUp(c, n.sons[0], {checkUndeclared})
|
||||||
|
|
|
||||||
|
|
@ -640,6 +640,8 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||||
of mNaN: result = newFloatNodeT(NaN, n)
|
of mNaN: result = newFloatNodeT(NaN, n)
|
||||||
of mInf: result = newFloatNodeT(Inf, n)
|
of mInf: result = newFloatNodeT(Inf, n)
|
||||||
of mNegInf: result = newFloatNodeT(NegInf, n)
|
of mNegInf: result = newFloatNodeT(NegInf, n)
|
||||||
|
of mNimvm:
|
||||||
|
localError(n.info, "illegal context for 'nimvm' magic")
|
||||||
else:
|
else:
|
||||||
if sfFakeConst notin s.flags: result = copyTree(s.ast)
|
if sfFakeConst notin s.flags: result = copyTree(s.ast)
|
||||||
of {skProc, skMethod}:
|
of {skProc, skMethod}:
|
||||||
|
|
|
||||||
|
|
@ -363,7 +363,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
|
||||||
else: internalError(it.info, "slot already has a lower bound")
|
else: internalError(it.info, "slot already has a lower bound")
|
||||||
if not isSpawned: analyse(c, value)
|
if not isSpawned: analyse(c, value)
|
||||||
of nkCaseStmt: analyseCase(c, n)
|
of nkCaseStmt: analyseCase(c, n)
|
||||||
of nkIfStmt, nkIfExpr: analyseIf(c, n)
|
of nkWhen, nkIfStmt, nkIfExpr: analyseIf(c, n)
|
||||||
of nkWhileStmt:
|
of nkWhileStmt:
|
||||||
analyse(c, n.sons[0])
|
analyse(c, n.sons[0])
|
||||||
# 'while true' loop?
|
# 'while true' loop?
|
||||||
|
|
|
||||||
|
|
@ -735,7 +735,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||||
# since 'var (a, b): T = ()' is not even allowed, there is always type
|
# since 'var (a, b): T = ()' is not even allowed, there is always type
|
||||||
# inference for (a, b) and thus no nil checking is necessary.
|
# inference for (a, b) and thus no nil checking is necessary.
|
||||||
of nkCaseStmt: trackCase(tracked, n)
|
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 nkBlockStmt, nkBlockExpr: trackBlock(tracked, n.sons[1])
|
||||||
of nkWhileStmt:
|
of nkWhileStmt:
|
||||||
track(tracked, n.sons[0])
|
track(tracked, n.sons[0])
|
||||||
|
|
|
||||||
|
|
@ -1664,7 +1664,10 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||||
of nkBracketExpr: genArrAccess(c, n, dest, flags)
|
of nkBracketExpr: genArrAccess(c, n, dest, flags)
|
||||||
of nkDerefExpr, nkHiddenDeref: genAddrDeref(c, n, dest, opcLdDeref, flags)
|
of nkDerefExpr, nkHiddenDeref: genAddrDeref(c, n, dest, opcLdDeref, flags)
|
||||||
of nkAddr, nkHiddenAddr: genAddrDeref(c, n, dest, opcAddrNode, 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 nkCaseStmt: genCase(c, n, dest)
|
||||||
of nkWhileStmt:
|
of nkWhileStmt:
|
||||||
unused(n, dest)
|
unused(n, dest)
|
||||||
|
|
|
||||||
|
|
@ -329,6 +329,35 @@ The ``when`` statement enables conditional compilation techniques. As
|
||||||
a special syntactic extension, the ``when`` construct is also available
|
a special syntactic extension, the ``when`` construct is also available
|
||||||
within ``object`` definitions.
|
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
|
Return statement
|
||||||
----------------
|
----------------
|
||||||
|
|
|
||||||
|
|
@ -1173,6 +1173,10 @@ const
|
||||||
## "i386", "alpha", "powerpc", "powerpc64", "powerpc64el", "sparc",
|
## "i386", "alpha", "powerpc", "powerpc64", "powerpc64el", "sparc",
|
||||||
## "amd64", "mips", "mipsel", "arm", "arm64".
|
## "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)
|
seqShallowFlag = low(int)
|
||||||
|
|
||||||
proc compileOption*(option: string): bool {.
|
proc compileOption*(option: string): bool {.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue