diff options
Diffstat (limited to 'compiler/evals.nim')
-rwxr-xr-x | compiler/evals.nim | 108 |
1 files changed, 105 insertions, 3 deletions
diff --git a/compiler/evals.nim b/compiler/evals.nim index 1d443a404..d2559176e 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -65,6 +65,7 @@ proc popStackFrame*(c: PEvalContext) {.inline.} = if (c.tos == nil): InternalError("popStackFrame") c.tos = c.tos.next +proc eval*(c: PEvalContext, n: PNode): PNode proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode proc stackTraceAux(x: PStackFrame) = @@ -764,7 +765,7 @@ proc isEmpty(n: PNode): bool = proc stringStartingLine(s: PNode): int = result = s.info.line - countLines(s.strVal) -proc evalParseExpr(c: PEvalContext, n: Pnode): Pnode = +proc evalParseExpr(c: PEvalContext, n: PNode): PNode = var code = evalAux(c, n.sons[1], {}) var ast = parseString(code.getStrValue, code.info.toFilename, code.stringStartingLine) @@ -773,12 +774,108 @@ proc evalParseExpr(c: PEvalContext, n: Pnode): Pnode = result = ast.sons[0] result.typ = newType(tyExpr, c.module) -proc evalParseStmt(c: PEvalContext, n: Pnode): Pnode = +proc evalParseStmt(c: PEvalContext, n: PNode): PNode = var code = evalAux(c, n.sons[1], {}) result = parseString(code.getStrValue, code.info.toFilename, code.stringStartingLine) result.typ = newType(tyStmt, c.module) +proc evalTemplateAux*(templ, actual: PNode, sym: PSym): PNode = + case templ.kind + of nkSym: + var p = templ.sym + if (p.kind == skParam) and (p.owner.id == sym.id): + result = copyTree(actual.sons[p.position]) + else: + result = copyNode(templ) + of nkNone..nkIdent, nkType..nkNilLit: # atom + result = copyNode(templ) + else: + result = copyNode(templ) + newSons(result, sonsLen(templ)) + for i in countup(0, sonsLen(templ) - 1): + result.sons[i] = evalTemplateAux(templ.sons[i], actual, sym) + +proc evalTemplateArgs(n: PNode, s: PSym): PNode = + var + f, a: int + arg: PNode + + f = sonsLen(s.typ) + + # if the template has zero arguments, it can be called without ``()`` + # `n` is then a nkSym or something similar + case n.kind + of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: + a = sonsLen(n) + else: a = 0 + + if a > f: GlobalError(n.info, errWrongNumberOfArguments) + + result = copyNode(n) + for i in countup(1, f - 1): + if i < a: + arg = n.sons[i] + else: + arg = copyTree(s.typ.n.sons[i].sym.ast) + + addSon(result, arg) + +var evalTemplateCounter = 0 + # to prevend endless recursion in templates instantation + +proc evalTemplate(n: PNode, sym: PSym): PNode = + inc(evalTemplateCounter) + if evalTemplateCounter > 100: + GlobalError(n.info, errTemplateInstantiationTooNested) + + # replace each param by the corresponding node: + var args = evalTemplateArgs(n, sym) + result = evalTemplateAux(sym.ast.sons[codePos], args, sym) + + dec(evalTemplateCounter) + +proc evalMacroCall*(c: PEvalContext, n: PNode, sym: PSym): PNode = + inc(evalTemplateCounter) + if evalTemplateCounter > 100: + GlobalError(n.info, errTemplateInstantiationTooNested) + + var s = newStackFrame() + s.call = n + setlen(s.params, 2) + s.params[0] = newNodeIT(nkNilLit, n.info, sym.typ.sons[0]) + s.params[1] = n + pushStackFrame(c, s) + discard eval(c, sym.ast.sons[codePos]) + result = s.params[0] + popStackFrame(c) + if cyclicTree(result): GlobalError(n.info, errCyclicTree) + + dec(evalTemplateCounter) + +proc evalExpandToAst(c: PEvalContext, original: PNode): PNode = + var + n = original.copyTree + macroCall = n.sons[1] + expandedSym = macroCall.sons[0].sym + + for i in countup(1, macroCall.sonsLen - 1): + macroCall.sons[i] = evalAux(c, macroCall.sons[i], {}) + + case expandedSym.kind + of skTemplate: + result = evalTemplate(macroCall, expandedSym) + of skMacro: + # At this point macroCall.sons[0] is nkSym node. + # To be completely compatible with normal macro invocation, + # we want to replace it with nkIdent node featuring + # the original unmangled macro name. + macroCall.sons[0] = newIdentNode(expandedSym.name, expandedSym.info) + result = evalMacroCall(c, macroCall, expandedSym) + else: + InternalError(macroCall.info, + "ExpandToAst: expanded symbol is no macro or template") + proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode = var m = getMagic(n) case m @@ -805,7 +902,8 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode = of mAppendSeqElem: result = evalAppendSeqElem(c, n) of mParseExprToAst: result = evalParseExpr(c, n) of mParseStmtToAst: result = evalParseStmt(c, n) - of mNLen: + of mExpandToAst: result = evalExpandToAst(c, n) + of mNLen: result = evalAux(c, n.sons[1], {efLValue}) if isSpecial(result): return var a = result @@ -1011,6 +1109,10 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode = if (a == b) or (b.kind in {nkNilLit, nkEmpty}) and (a.kind in {nkNilLit, nkEmpty}): result.intVal = 1 + of mNLineInfo: + result = evalAux(c, n.sons[1], {}) + if isSpecial(result): return + result = newStrNodeT(result.info.toFileLineCol, n) of mAstToYaml: var ast = evalAux(c, n.sons[1], {efLValue}) result = newStrNode(nkStrLit, ast.treeToYaml.ropeToStr) |