summary refs log tree commit diff stats
path: root/compiler/hlo.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/hlo.nim')
-rw-r--r--compiler/hlo.nim106
1 files changed, 106 insertions, 0 deletions
diff --git a/compiler/hlo.nim b/compiler/hlo.nim
new file mode 100644
index 000000000..9fdec38c0
--- /dev/null
+++ b/compiler/hlo.nim
@@ -0,0 +1,106 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This include implements the high level optimization pass.
+# included from sem.nim
+
+proc hlo(c: PContext, n: PNode): PNode
+
+proc evalPattern(c: PContext, n, orig: PNode): PNode =
+  internalAssert c.config, n.kind == nkCall and n[0].kind == nkSym
+  # we need to ensure that the resulting AST is semchecked. However, it's
+  # awful to semcheck before macro invocation, so we don't and treat
+  # templates and macros as immediate in this context.
+  var rule: string =
+    if c.config.hasHint(hintPattern):
+      renderTree(n, {renderNoComments})
+    else:
+      ""
+  let s = n[0].sym
+  case s.kind
+  of skMacro:
+    result = semMacroExpr(c, n, orig, s)
+  of skTemplate:
+    result = semTemplateExpr(c, n, s, {efFromHlo})
+  else:
+    result = semDirectOp(c, n, {})
+  if c.config.hasHint(hintPattern):
+    message(c.config, orig.info, hintPattern, rule & " --> '" &
+      renderTree(result, {renderNoComments}) & "'")
+
+proc applyPatterns(c: PContext, n: PNode): PNode =
+  result = n
+  # we apply the last pattern first, so that pattern overriding is possible;
+  # however the resulting AST would better not trigger the old rule then
+  # anymore ;-)
+  for i in countdown(c.patterns.len-1, 0):
+    let pattern = c.patterns[i]
+    if not isNil(pattern):
+      let x = applyRule(c, pattern, result)
+      if not isNil(x):
+        assert x.kind in {nkStmtList, nkCall}
+        # better be safe than sorry, so check evalTemplateCounter too:
+        inc(c.config.evalTemplateCounter)
+        if c.config.evalTemplateCounter > evalTemplateLimit:
+          globalError(c.config, n.info, "template instantiation too nested")
+        # deactivate this pattern:
+        c.patterns[i] = nil
+        if x.kind == nkStmtList:
+          assert x.len == 3
+          x[1] = evalPattern(c, x[1], result)
+          result = flattenStmts(x)
+        else:
+          result = evalPattern(c, x, result)
+        dec(c.config.evalTemplateCounter)
+        # activate this pattern again:
+        c.patterns[i] = pattern
+
+proc hlo(c: PContext, n: PNode): PNode =
+  inc(c.hloLoopDetector)
+  # simply stop and do not perform any further transformations:
+  if c.hloLoopDetector > 300: return n
+  case n.kind
+  of nkMacroDef, nkTemplateDef, procDefs:
+    # already processed (special cases in semstmts.nim)
+    result = n
+  else:
+    if n.kind in {nkFastAsgn, nkAsgn, nkSinkAsgn, nkIdentDefs, nkVarTuple} and
+        n[0].kind == nkSym and
+        {sfGlobal, sfPure} <= n[0].sym.flags:
+      # do not optimize 'var g {.global} = re(...)' again!
+      return n
+    result = applyPatterns(c, n)
+    if result == n:
+      # no optimization applied, try subtrees:
+      for i in 0..<result.safeLen:
+        let a = result[i]
+        let h = hlo(c, a)
+        if h != a: result[i] = h
+    else:
+      # perform type checking, so that the replacement still fits:
+      if isEmptyType(n.typ) and isEmptyType(result.typ):
+        discard
+      else:
+        result = fitNode(c, n.typ, result, n.info)
+      # optimization has been applied so check again:
+      result = commonOptimizations(c.graph, c.idgen, c.module, result)
+      result = hlo(c, result)
+      result = commonOptimizations(c.graph, c.idgen, c.module, result)
+
+proc hloBody(c: PContext, n: PNode): PNode =
+  # fast exit:
+  if c.patterns.len == 0 or optTrMacros notin c.config.options: return n
+  c.hloLoopDetector = 0
+  result = hlo(c, n)
+
+proc hloStmt(c: PContext, n: PNode): PNode =
+  # fast exit:
+  if c.patterns.len == 0 or optTrMacros notin c.config.options: return n
+  c.hloLoopDetector = 0
+  result = hlo(c, n)