summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAdam Strzelecki <ono@java.pl>2015-06-02 21:29:28 +0200
committerOscar Campbell <oscar@campbell.nu>2015-06-07 13:14:52 +0200
commit4674b3eb8003b44656ae15ff0a5b7fc742714597 (patch)
tree04133c5f28af96b84ff543f6b80a58b5b7dab5c7
parentc55f5dfca263788169c21fcff2dd78103a20e891 (diff)
downloadNim-4674b3eb8003b44656ae15ff0a5b7fc742714597.tar.gz
Introduce {.noRewrite.} expr pragma disabling TR
Term rewriting macros/templates are currently greedy and they will rewrite as
long as there is a match. So there was no way to ensure some rewrite happens
only once, eg. when rewriting term to same term plus extra content.

With new macro we can actually prevent further rewriting on marked expr or
stmts, eg. with given example echo(...) will be rewritten just once:

  template pwnEcho{echo(x)}(x: expr) =
    {.noRewrite.}: echo("pwned!")

  echo "ab"
-rw-r--r--compiler/ast.nim1
-rw-r--r--compiler/patterns.nim4
-rw-r--r--compiler/pragmas.nim4
-rw-r--r--compiler/semstmts.nim2
-rw-r--r--compiler/wordrecg.nim4
5 files changed, 11 insertions, 4 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 044f21341..c349f81ed 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -423,6 +423,7 @@ type
                 # but unfortunately it has measurable impact for compilation
                 # efficiency
     nfTransf,   # node has been transformed
+    nfNoRewrite # node should not be transformed anymore
     nfSem       # node has been checked for semantics
     nfLL        # node has gone through lambda lifting
     nfDotField  # the call can use a dot operator
diff --git a/compiler/patterns.nim b/compiler/patterns.nim
index 368b0b37b..3f8b05940 100644
--- a/compiler/patterns.nim
+++ b/compiler/patterns.nim
@@ -130,7 +130,9 @@ proc matchNested(c: PPatternContext, p, n: PNode, rpn: bool): bool =
 
 proc matches(c: PPatternContext, p, n: PNode): bool =
   # hidden conversions (?)
-  if isPatternParam(c, p):
+  if nfNoRewrite in n.flags:
+    result = false
+  elif isPatternParam(c, p):
     result = bindOrCheck(c, p.sym, n)
   elif n.kind == nkSym and p.kind == nkIdent:
     result = p.ident.id == n.sym.name.id
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index c048d78e9..6f37fe756 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -37,7 +37,7 @@ const
     wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
     wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
     wTags, wLocks, wGcSafe}
-  exprPragmas* = {wLine, wLocks}
+  exprPragmas* = {wLine, wLocks, wNoRewrite}
   stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
     wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
     wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
@@ -859,6 +859,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
             c.module.flags.incl sfExperimental
           else:
             localError(it.info, "'experimental' pragma only valid as toplevel statement")
+        of wNoRewrite:
+          noVal(it)
         else: invalidPragma(it)
       else: invalidPragma(it)
   else: processNote(c, it)
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index c355a5bf1..43cdca866 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1268,6 +1268,8 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
     of wLocks:
       result = n
       result.typ = n.sons[1].typ
+    of wNoRewrite:
+      incl(result.flags, nfNoRewrite)
     else: discard
 
 proc semStaticStmt(c: PContext, n: PNode): PNode =
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index 63fd995c4..deb12536f 100644
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -55,7 +55,7 @@ type
     wFloatchecks, wNanChecks, wInfChecks,
     wAssertions, wPatterns, wWarnings,
     wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects, wTags,
-    wDeadCodeElim, wSafecode, wNoForward,
+    wDeadCodeElim, wSafecode, wNoForward, wNoRewrite,
     wPragma,
     wCompileTime, wNoInit,
     wPassc, wPassl, wBorrow, wDiscardable,
@@ -139,7 +139,7 @@ const
 
     "assertions", "patterns", "warnings", "hints",
     "optimization", "raises", "writes", "reads", "size", "effects", "tags",
-    "deadcodeelim", "safecode", "noforward",
+    "deadcodeelim", "safecode", "noforward", "norewrite",
     "pragma",
     "compiletime", "noinit",
     "passc", "passl", "borrow", "discardable", "fieldchecks",