improvements for TR macros

This commit is contained in:
Araq 2013-09-17 23:43:07 +02:00
commit 9de3bc8ef6
6 changed files with 53 additions and 21 deletions

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -30,8 +30,6 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode =
if optHints in gOptions and hintPattern in gNotes: if optHints in gOptions and hintPattern in gNotes:
Message(orig.info, hintPattern, rule & " --> '" & Message(orig.info, hintPattern, rule & " --> '" &
renderTree(result, {renderNoComments}) & "'") renderTree(result, {renderNoComments}) & "'")
# check the resulting AST for optimization rules again:
result = hlo(c, result)
proc applyPatterns(c: PContext, n: PNode): PNode = proc applyPatterns(c: PContext, n: PNode): PNode =
result = n result = n
@ -44,11 +42,12 @@ proc applyPatterns(c: PContext, n: PNode): PNode =
let x = applyRule(c, pattern, result) let x = applyRule(c, pattern, result)
if not isNil(x): if not isNil(x):
assert x.kind in {nkStmtList, nkCall} assert x.kind in {nkStmtList, nkCall}
# better be safe than sorry, so check evalTemplateCounter too:
inc(evalTemplateCounter) inc(evalTemplateCounter)
if evalTemplateCounter > 100: if evalTemplateCounter > 100:
GlobalError(n.info, errTemplateInstantiationTooNested) GlobalError(n.info, errTemplateInstantiationTooNested)
# deactivate this pattern: # deactivate this pattern:
c.patterns[i] = nil #c.patterns[i] = nil
if x.kind == nkStmtList: if x.kind == nkStmtList:
assert x.len == 3 assert x.len == 3
x.sons[1] = evalPattern(c, x.sons[1], result) x.sons[1] = evalPattern(c, x.sons[1], result)
@ -57,9 +56,12 @@ proc applyPatterns(c: PContext, n: PNode): PNode =
result = evalPattern(c, x, result) result = evalPattern(c, x, result)
dec(evalTemplateCounter) dec(evalTemplateCounter)
# activate this pattern again: # activate this pattern again:
c.patterns[i] = pattern #c.patterns[i] = pattern
proc hlo(c: PContext, n: PNode): PNode = proc hlo(c: PContext, n: PNode): PNode =
inc(c.hloLoopDetector)
# simply stop and do not perform any further transformations:
if c.hloLoopDetector > 300: result = n
case n.kind case n.kind
of nkMacroDef, nkTemplateDef, procDefs: of nkMacroDef, nkTemplateDef, procDefs:
# already processed (special cases in semstmts.nim) # already processed (special cases in semstmts.nim)
@ -74,18 +76,23 @@ proc hlo(c: PContext, n: PNode): PNode =
if h != a: result.sons[i] = h if h != a: result.sons[i] = h
else: else:
# perform type checking, so that the replacement still fits: # perform type checking, so that the replacement still fits:
if n.typ == nil and (result.typ == nil or if isEmptyType(n.typ) and isEmptyType(result.typ):
result.typ.kind in {tyStmt, tyEmpty}):
nil nil
else: else:
result = fitNode(c, n.typ, result) result = fitNode(c, n.typ, result)
# optimization has been applied so check again:
result = commonOptimizations(c.module, result)
result = hlo(c, result)
result = commonOptimizations(c.module, result)
proc hloBody(c: PContext, n: PNode): PNode = proc hloBody(c: PContext, n: PNode): PNode =
# fast exit: # fast exit:
if c.patterns.len == 0 or optPatterns notin gOptions: return n if c.patterns.len == 0 or optPatterns notin gOptions: return n
c.hloLoopDetector = 0
result = hlo(c, n) result = hlo(c, n)
proc hloStmt(c: PContext, n: PNode): PNode = proc hloStmt(c: PContext, n: PNode): PNode =
# fast exit: # fast exit:
if c.patterns.len == 0 or optPatterns notin gOptions: return n if c.patterns.len == 0 or optPatterns notin gOptions: return n
c.hloLoopDetector = 0
result = hlo(c, n) result = hlo(c, n)

View file

@ -237,15 +237,6 @@ proc addToArgList(result, n: PNode) =
else: else:
for i in 0 .. <n.len: result.add(n.sons[i]) for i in 0 .. <n.len: result.add(n.sons[i])
when false:
proc procPatternMatches*(c: PContext, s: PSym, n: PNode): bool =
## for AST-based overloading:
var ctx: TPatternContext
ctx.owner = s
ctx.c = c
ctx.formals = sonsLen(s.typ)-1
result = matches(ctx, s.ast.sons[patternPos], n)
proc applyRule*(c: PContext, s: PSym, n: PNode): PNode = proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
## returns a tree to semcheck if the rule triggered; nil otherwise ## returns a tree to semcheck if the rule triggered; nil otherwise
var ctx: TPatternContext var ctx: TPatternContext

View file

@ -85,6 +85,7 @@ type
# naming it multiple times # naming it multiple times
generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile
lastGenericIdx*: int # used for the generics stack lastGenericIdx*: int # used for the generics stack
hloLoopDetector*: int # used to prevent endless loops in the HLO
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair = proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
result.genericSym = s result.genericSym = s

View file

@ -574,9 +574,14 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
fc.c = c fc.c = c
semForObjectFields(fc, tupleTypeA.n, n, stmts) semForObjectFields(fc, tupleTypeA.n, n, stmts)
Dec(c.p.nestedLoopCounter) Dec(c.p.nestedLoopCounter)
var b = newNodeI(nkBreakStmt, n.info) # for TR macros this 'while true: ...; break' loop is pretty bad, so
b.add(ast.emptyNode) # we avoid it now if we can:
stmts.add(b) if hasSonWith(stmts, nkBreakStmt):
var b = newNodeI(nkBreakStmt, n.info)
b.add(ast.emptyNode)
stmts.add(b)
else:
result = stmts
proc addForVarDecl(c: PContext, v: PSym) = proc addForVarDecl(c: PContext, v: PSym) =
if warnShadowIdent in gNotes: if warnShadowIdent in gNotes:

View file

@ -588,6 +588,36 @@ proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkBracket} and result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkBracket} and
cnst.len != 0 cnst.len != 0
proc commonOptimizations*(c: PSym, n: PNode): PNode =
result = n
for i in 0 .. < n.safeLen:
result.sons[i] = commonOptimizations(c, n.sons[i])
var op = getMergeOp(n)
if (op != nil) and (op.magic != mNone) and (sonsLen(n) >= 3):
result = newNodeIT(nkCall, n.info, n.typ)
add(result, n.sons[0])
var args = newNode(nkArgList)
flattenTreeAux(args, n, op)
var j = 0
while j < sonsLen(args):
var a = args.sons[j]
inc(j)
if isConstExpr(a):
while j < sonsLen(args):
let b = args.sons[j]
if not isConstExpr(b): break
a = evalOp(op.magic, result, a, b, nil)
inc(j)
add(result, a)
if len(result) == 2: result = result[1]
else:
var cnst = getConstExpr(c, n)
# we inline constants if they are not complex constants:
if cnst != nil and not dontInlineConstant(n, cnst):
result = cnst
else:
result = n
proc transform(c: PTransf, n: PNode): PTransNode = proc transform(c: PTransf, n: PNode): PTransNode =
case n.kind case n.kind
of nkSym: of nkSym:

View file

@ -12,8 +12,6 @@ version 0.9.4
- special rule for ``[]=`` - special rule for ``[]=``
- ``=`` should be overloadable; requires specialization for ``=``; general - ``=`` should be overloadable; requires specialization for ``=``; general
lift mechanism in the compiler is already implemented for 'fields' lift mechanism in the compiler is already implemented for 'fields'
- mocking support with ``tyProxy`` that does: fallback for ``.`` operator
- overloading of ``.``? Special case ``.=``?
- built-in 'getImpl' - built-in 'getImpl'
- optimize 'genericReset'; 'newException' leads to code bloat - optimize 'genericReset'; 'newException' leads to code bloat
- stack-less GC - stack-less GC