diff --git a/compiler/vm/vm.nim b/compiler/vm/vm.nim index aae8dc60934..0d972ead292 100644 --- a/compiler/vm/vm.nim +++ b/compiler/vm/vm.nim @@ -1287,6 +1287,34 @@ proc rawExecute(c: var TCtx, pc: var int, tos: var StackFrameIndex): TFullReg = ast[i] = a.sym.ast[i] ast[bodyPos] = transformBody(c.graph, c.idgen, a.sym, cache=true) ast.copyTree() + of opcExpandToAst: + decodeBC(rkNode) + + let + callExprAst = c.constants[regs[rb].intVal.int] + prc = callExprAst[0].sym + prevFrame = c.sframes[tos].next + + assert callExprAst.kind in nkCallKinds + assert prc.kind == skTemplate + + let genSymOwner = if prevFrame > 0 and c.sframes[prevFrame].prc != nil: + c.sframes[prevFrame].prc + else: + c.module + var templCall = newNodeI(nkCall, c.debug[pc]) + templCall.add(newSymNode(prc)) + for i in 1..rc-1: + let node = regs[rb+i].regToNode + node.info = c.debug[pc] + templCall.add(node) + + var a = evalTemplate(templCall, prc, genSymOwner, c.config, c.cache, c.templInstCounter, c.idgen) + if a.kind == nkStmtList and a.len == 1: # flatten if a single statement + a = a[0] + a.recSetFlagIsRef + regs[ra].node = a + of opcSymOwner: decodeB(rkNode) let a = regs[rb].node @@ -1370,7 +1398,7 @@ proc rawExecute(c: var TCtx, pc: var int, tos: var StackFrameIndex): TFullReg = currentException: c.currentExceptionA, currentLineInfo: c.debug[pc])) - elif prc.kind != skTemplate: + else: let newPc = compile(c, prc) # tricky: a recursion is also a jump back, so we use the same # logic as for loops: @@ -1387,24 +1415,6 @@ proc rawExecute(c: var TCtx, pc: var int, tos: var StackFrameIndex): TFullReg = pushFrame(newFrame) # -1 for the following 'inc pc' pc = newPc-1 - else: - let prevFrame = c.sframes[tos].next - # for 'getAst' support we need to support template expansion here: - let genSymOwner = if prevFrame > 0 and c.sframes[prevFrame].prc != nil: - c.sframes[prevFrame].prc - else: - c.module - var macroCall = newNodeI(nkCall, c.debug[pc]) - macroCall.add(newSymNode(prc)) - for i in 1..rc-1: - let node = regs[rb+i].regToNode - node.info = c.debug[pc] - macroCall.add(node) - var a = evalTemplate(macroCall, prc, genSymOwner, c.config, c.cache, c.templInstCounter, c.idgen) - if a.kind == nkStmtList and a.len == 1: a = a[0] - a.recSetFlagIsRef - ensureKind(rkNode) - regs[ra].node = a of opcTJmp: # jump Bx if A != 0 let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc' diff --git a/compiler/vm/vm_enums.nim b/compiler/vm/vm_enums.nim index efcc52734f2..6cef8bd2ea7 100644 --- a/compiler/vm/vm_enums.nim +++ b/compiler/vm/vm_enums.nim @@ -102,7 +102,9 @@ type opcEqIdent, opcStrToIdent, opcGetImpl, - opcGetImplTransf + opcGetImplTransf, + + opcExpandToAst, opcEcho, opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ... diff --git a/compiler/vm/vmgen.nim b/compiler/vm/vmgen.nim index 26554578619..64f8e831804 100644 --- a/compiler/vm/vmgen.nim +++ b/compiler/vm/vmgen.nim @@ -1411,7 +1411,26 @@ proc genMagic(c: var TCtx; n: PNode; dest: var TDest; m: TMagic) = #if arg[0].kind != nkSym or arg[0].sym.kind notin {skTemplate, skMacro}: # "ExpandToAst: expanded symbol is no macro or template" if dest < 0: dest = c.getTemp(n.typ) - c.genCall(arg, dest) + + if arg[0].sym.kind == skTemplate: + let x = c.getTempRange(arg.len, slotTempUnknown) + + # Pass the whole call expression as the first value. Since the node + # might have a nil type, we can't use `genLit`. Instead load the + # constant index and make the instruction do the lookup itself + c.gABx(n, opcLdImmInt, TRegister(x), c.genLiteral(arg)) + + # Generate the arguments + for i in 1..