hlo.nim 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2013 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # This include implements the high level optimization pass.
  10. # included from sem.nim
  11. when defined(nimPreviewSlimSystem):
  12. import std/assertions
  13. proc hlo(c: PContext, n: PNode): PNode
  14. proc evalPattern(c: PContext, n, orig: PNode): PNode =
  15. internalAssert c.config, n.kind == nkCall and n[0].kind == nkSym
  16. # we need to ensure that the resulting AST is semchecked. However, it's
  17. # awful to semcheck before macro invocation, so we don't and treat
  18. # templates and macros as immediate in this context.
  19. var rule: string =
  20. if c.config.hasHint(hintPattern):
  21. renderTree(n, {renderNoComments})
  22. else:
  23. ""
  24. let s = n[0].sym
  25. case s.kind
  26. of skMacro:
  27. result = semMacroExpr(c, n, orig, s)
  28. of skTemplate:
  29. result = semTemplateExpr(c, n, s, {efFromHlo})
  30. else:
  31. result = semDirectOp(c, n, {})
  32. if c.config.hasHint(hintPattern):
  33. message(c.config, orig.info, hintPattern, rule & " --> '" &
  34. renderTree(result, {renderNoComments}) & "'")
  35. proc applyPatterns(c: PContext, n: PNode): PNode =
  36. result = n
  37. # we apply the last pattern first, so that pattern overriding is possible;
  38. # however the resulting AST would better not trigger the old rule then
  39. # anymore ;-)
  40. for i in countdown(c.patterns.len-1, 0):
  41. let pattern = c.patterns[i]
  42. if not isNil(pattern):
  43. let x = applyRule(c, pattern, result)
  44. if not isNil(x):
  45. assert x.kind in {nkStmtList, nkCall}
  46. # better be safe than sorry, so check evalTemplateCounter too:
  47. inc(c.config.evalTemplateCounter)
  48. if c.config.evalTemplateCounter > evalTemplateLimit:
  49. globalError(c.config, n.info, "template instantiation too nested")
  50. # deactivate this pattern:
  51. c.patterns[i] = nil
  52. if x.kind == nkStmtList:
  53. assert x.len == 3
  54. x[1] = evalPattern(c, x[1], result)
  55. result = flattenStmts(x)
  56. else:
  57. result = evalPattern(c, x, result)
  58. dec(c.config.evalTemplateCounter)
  59. # activate this pattern again:
  60. c.patterns[i] = pattern
  61. proc hlo(c: PContext, n: PNode): PNode =
  62. inc(c.hloLoopDetector)
  63. # simply stop and do not perform any further transformations:
  64. if c.hloLoopDetector > 300: return n
  65. case n.kind
  66. of nkMacroDef, nkTemplateDef, procDefs:
  67. # already processed (special cases in semstmts.nim)
  68. result = n
  69. else:
  70. if n.kind in {nkFastAsgn, nkAsgn, nkSinkAsgn, nkIdentDefs, nkVarTuple} and
  71. n[0].kind == nkSym and
  72. {sfGlobal, sfPure} <= n[0].sym.flags:
  73. # do not optimize 'var g {.global} = re(...)' again!
  74. return n
  75. result = applyPatterns(c, n)
  76. if result == n:
  77. # no optimization applied, try subtrees:
  78. for i in 0..<result.safeLen:
  79. let a = result[i]
  80. let h = hlo(c, a)
  81. if h != a: result[i] = h
  82. else:
  83. # perform type checking, so that the replacement still fits:
  84. if isEmptyType(n.typ) and isEmptyType(result.typ):
  85. discard
  86. else:
  87. result = fitNode(c, n.typ, result, n.info)
  88. # optimization has been applied so check again:
  89. result = commonOptimizations(c.graph, c.idgen, c.module, result)
  90. result = hlo(c, result)
  91. result = commonOptimizations(c.graph, c.idgen, c.module, result)
  92. proc hloBody(c: PContext, n: PNode): PNode =
  93. # fast exit:
  94. if c.patterns.len == 0 or optTrMacros notin c.config.options: return n
  95. c.hloLoopDetector = 0
  96. result = hlo(c, n)
  97. proc hloStmt(c: PContext, n: PNode): PNode =
  98. # fast exit:
  99. if c.patterns.len == 0 or optTrMacros notin c.config.options: return n
  100. c.hloLoopDetector = 0
  101. result = hlo(c, n)