summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2015-09-05 10:03:35 +0200
committerAndreas Rumpf <rumpf_a@web.de>2015-09-05 10:03:35 +0200
commit63a6bfce7114bd1a0cf488b0a401f043212d6216 (patch)
tree83b38df915652f9c1dc7b8d0538b4e175bc06583
parentcd9d126a2f5054092f494674a4fa33a21a416891 (diff)
parentc0fa4b7d9c0fce48116102c5fa57dc722665fbe0 (diff)
downloadNim-63a6bfce7114bd1a0cf488b0a401f043212d6216.tar.gz
Merge pull request #3286 from yglukhov/when-nimvm
when nimvm stmt
-rw-r--r--compiler/ast.nim3
-rw-r--r--compiler/ccgexprs.nim3
-rw-r--r--compiler/jsgen.nim3
-rw-r--r--compiler/semexprs.nim41
-rw-r--r--compiler/semfold.nim2
-rw-r--r--compiler/semparallel.nim2
-rw-r--r--compiler/sempass2.nim2
-rw-r--r--compiler/vmgen.nim5
-rw-r--r--doc/manual/stmts.txt29
-rw-r--r--lib/system.nim4
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 {.