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"
This commit is contained in:
Adam Strzelecki 2015-06-02 21:29:28 +02:00
commit 13b57dbc2f
5 changed files with 11 additions and 4 deletions

View file

@ -423,6 +423,7 @@ type
# but unfortunately it has measurable impact for compilation # but unfortunately it has measurable impact for compilation
# efficiency # efficiency
nfTransf, # node has been transformed nfTransf, # node has been transformed
nfNoRewrite # node should not be transformed anymore
nfSem # node has been checked for semantics nfSem # node has been checked for semantics
nfLL # node has gone through lambda lifting nfLL # node has gone through lambda lifting
nfDotField # the call can use a dot operator nfDotField # the call can use a dot operator

View file

@ -130,7 +130,9 @@ proc matchNested(c: PPatternContext, p, n: PNode, rpn: bool): bool =
proc matches(c: PPatternContext, p, n: PNode): bool = proc matches(c: PPatternContext, p, n: PNode): bool =
# hidden conversions (?) # hidden conversions (?)
if isPatternParam(c, p): if nfNoRewrite in n.flags:
result = false
elif isPatternParam(c, p):
result = bindOrCheck(c, p.sym, n) result = bindOrCheck(c, p.sym, n)
elif n.kind == nkSym and p.kind == nkIdent: elif n.kind == nkSym and p.kind == nkIdent:
result = p.ident.id == n.sym.name.id result = p.ident.id == n.sym.name.id

View file

@ -37,7 +37,7 @@ const
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern, wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises, wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
wTags, wLocks, wGcSafe} wTags, wLocks, wGcSafe}
exprPragmas* = {wLine, wLocks} exprPragmas* = {wLine, wLocks, wNoRewrite}
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks, stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError, 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 c.module.flags.incl sfExperimental
else: else:
localError(it.info, "'experimental' pragma only valid as toplevel statement") localError(it.info, "'experimental' pragma only valid as toplevel statement")
of wNoRewrite:
noVal(it)
else: invalidPragma(it) else: invalidPragma(it)
else: invalidPragma(it) else: invalidPragma(it)
else: processNote(c, it) else: processNote(c, it)

View file

@ -1268,6 +1268,8 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
of wLocks: of wLocks:
result = n result = n
result.typ = n.sons[1].typ result.typ = n.sons[1].typ
of wNoRewrite:
incl(result.flags, nfNoRewrite)
else: discard else: discard
proc semStaticStmt(c: PContext, n: PNode): PNode = proc semStaticStmt(c: PContext, n: PNode): PNode =

View file

@ -55,7 +55,7 @@ type
wFloatchecks, wNanChecks, wInfChecks, wFloatchecks, wNanChecks, wInfChecks,
wAssertions, wPatterns, wWarnings, wAssertions, wPatterns, wWarnings,
wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects, wTags, wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects, wTags,
wDeadCodeElim, wSafecode, wNoForward, wDeadCodeElim, wSafecode, wNoForward, wNoRewrite,
wPragma, wPragma,
wCompileTime, wNoInit, wCompileTime, wNoInit,
wPassc, wPassl, wBorrow, wDiscardable, wPassc, wPassl, wBorrow, wDiscardable,
@ -139,7 +139,7 @@ const
"assertions", "patterns", "warnings", "hints", "assertions", "patterns", "warnings", "hints",
"optimization", "raises", "writes", "reads", "size", "effects", "tags", "optimization", "raises", "writes", "reads", "size", "effects", "tags",
"deadcodeelim", "safecode", "noforward", "deadcodeelim", "safecode", "noforward", "norewrite",
"pragma", "pragma",
"compiletime", "noinit", "compiletime", "noinit",
"passc", "passl", "borrow", "discardable", "fieldchecks", "passc", "passl", "borrow", "discardable", "fieldchecks",