parameter passing works the same for macros and templates; use callsite magic to access the invokation AST

This commit is contained in:
Araq 2012-08-28 22:15:29 +02:00
commit b4844a189d
16 changed files with 270 additions and 180 deletions

View file

@ -441,7 +441,7 @@ type
mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal,
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo,
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr,
mNBindSym,
mNBindSym, mNCallSite,
mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError,
mInstantiationInfo, mGetTypeInfo

View file

@ -38,6 +38,7 @@ type
module*: PSym
tos*: PStackFrame # top of stack
lastException*: PNode
callsite: PNode # for 'callsite' magic
mode*: TEvalMode
globals*: TIdNodeTable # state of global vars
@ -74,7 +75,7 @@ proc popStackFrame*(c: PEvalContext) {.inline.} =
if c.tos != nil: c.tos = c.tos.next
else: InternalError("popStackFrame")
proc evalMacroCall*(c: PEvalContext, n: PNode, sym: PSym): PNode
proc evalMacroCall*(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode
proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode
proc raiseCannotEval(c: PEvalContext, info: TLineInfo): PNode =
@ -106,8 +107,11 @@ proc stackTrace(c: PEvalContext, n: PNode, msg: TMsgKind, arg = "") =
proc isSpecial(n: PNode): bool {.inline.} =
result = n.kind == nkExceptBranch
proc myreset(n: PNode) {.inline.} =
when defined(system.reset): reset(n[])
proc myreset(n: PNode) =
when defined(system.reset):
var oldInfo = n.info
reset(n[])
n.info = oldInfo
proc evalIf(c: PEvalContext, n: PNode): PNode =
var i = 0
@ -245,6 +249,11 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
of tyObject:
result = newNodeIT(nkPar, info, t)
getNullValueAux(t.n, result)
# initialize inherited fields:
var base = t.sons[0]
while base != nil:
getNullValueAux(skipTypes(base, skipPtrs).n, result)
base = base.sons[0]
of tyArray, tyArrayConstr:
result = newNodeIT(nkBracket, info, t)
for i in countup(0, int(lengthOrd(t)) - 1):
@ -925,7 +934,7 @@ proc evalExpandToAst(c: PEvalContext, original: PNode): PNode =
# 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)
result = evalMacroCall(c, macroCall, original, expandedSym)
else:
InternalError(macroCall.info,
"ExpandToAst: expanded symbol is no macro or template")
@ -1166,10 +1175,13 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
of mIdentToStr:
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
if result.kind != nkIdent: InternalError(n.info, "no ident node")
var a = result
result = newNodeIT(nkStrLit, n.info, n.typ)
result.strVal = a.ident.s
if a.kind == nkSym:
result.strVal = a.sym.name.s
else:
if a.kind != nkIdent: InternalError(n.info, "no ident node")
result.strVal = a.ident.s
of mEqIdent:
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
@ -1226,6 +1238,9 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
var a = result
result = newNodeIT(nkStrLit, n.info, n.typ)
result.strVal = newString(0)
of mNCallSite:
if c.callsite != nil: result = c.callsite
else: stackTrace(c, n, errFieldXNotFound, "callsite")
else:
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
@ -1355,24 +1370,31 @@ proc evalConstExpr*(module: PSym, e: PNode): PNode =
proc evalStaticExpr*(module: PSym, e: PNode): PNode =
result = evalConstExprAux(module, e, emStatic)
proc evalMacroCall*(c: PEvalContext, n: PNode, sym: PSym): PNode =
proc setupMacroParam(x: PNode): PNode =
result = x
if result.kind == nkHiddenStdConv: result = result.sons[1]
proc evalMacroCall(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode =
# XXX GlobalError() is ugly here, but I don't know a better solution for now
inc(evalTemplateCounter)
if evalTemplateCounter > 100:
if evalTemplateCounter > 100:
GlobalError(n.info, errTemplateInstantiationTooNested)
#inc genSymBaseId
c.callsite = nOrig
var s = newStackFrame()
s.call = n
setlen(s.params, 2)
setlen(s.params, n.len)
# return value:
s.params[0] = newNodeIT(nkNilLit, n.info, sym.typ.sons[0])
s.params[1] = n
# setup parameters:
for i in 1 .. < n.len: s.params[i] = setupMacroParam(n.sons[i])
pushStackFrame(c, s)
discard eval(c, sym.getBody)
result = s.params[0]
popStackFrame(c)
if cyclicTree(result): GlobalError(n.info, errCyclicTree)
dec(evalTemplateCounter)
c.callsite = nil
proc myOpen(module: PSym, filename: string): PPassContext =
var c = newEvalContext(module, filename, emRepl)

View file

@ -774,7 +774,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkRStrLit, '\"' & replace(n[1].strVal, "\"", "\"\"") & '\"')
else:
gsub(g, n.sons[1])
of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: gsub(g, n.sons[0])
of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: gsub(g, n.sons[1])
of nkCast:
put(g, tkCast, "cast")
put(g, tkBracketLe, "[")

View file

@ -81,7 +81,7 @@ proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode
proc semMacroExpr(c: PContext, n: PNode, sym: PSym,
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
semCheck: bool = true): PNode
proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode
@ -127,14 +127,14 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
#GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
dec(evalTemplateCounter)
proc semMacroExpr(c: PContext, n: PNode, sym: PSym,
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
semCheck: bool = true): PNode =
markUsed(n, sym)
if sym == c.p.owner:
GlobalError(n.info, errRecursiveDependencyX, sym.name.s)
if c.evalContext == nil:
c.evalContext = newEvalContext(c.module, "", emStatic)
result = evalMacroCall(c.evalContext, n, sym)
result = evalMacroCall(c.evalContext, n, nOrig, sym)
if semCheck: result = semAfterMacroCall(c, result, sym)
proc forceBool(c: PContext, n: PNode): PNode =

View file

@ -98,7 +98,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
else: result = newSymNode(s, n.info)
else:
result = newSymNode(s, n.info)
of skMacro: result = semMacroExpr(c, n, s)
of skMacro: result = semMacroExpr(c, n, n, s)
of skTemplate: result = semTemplateExpr(c, n, s)
of skVar, skLet, skResult, skParam, skForVar:
markUsed(n, s)
@ -705,7 +705,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
return errorNode(c, n)
let callee = result.sons[0].sym
case callee.kind
of skMacro: result = semMacroExpr(c, nOrig, callee)
of skMacro: result = semMacroExpr(c, result, nOrig, callee)
of skTemplate: result = semTemplateExpr(c, nOrig, callee)
else:
fixAbstractType(c, result)
@ -1398,7 +1398,8 @@ proc semBlockExpr(c: PContext, n: PNode): PNode =
closeScope(c.tab)
Dec(c.p.nestedBlockCounter)
proc semMacroStmt(c: PContext, n: PNode, semCheck = true): PNode =
proc semMacroStmt(c: PContext, n: PNode, semCheck = true): PNode =
# XXX why no overloading here?
checkMinSonsLen(n, 2)
var a: PNode
if isCallExpr(n.sons[0]): a = n.sons[0].sons[0]
@ -1407,7 +1408,7 @@ proc semMacroStmt(c: PContext, n: PNode, semCheck = true): PNode =
if s != nil:
case s.kind
of skMacro:
result = semMacroExpr(c, n, s, semCheck)
result = semMacroExpr(c, n, n, s, semCheck)
of skTemplate:
# transform
# nkMacroStmt(nkCall(a...), stmt, b...)
@ -1499,16 +1500,16 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if s != nil:
case s.kind
of skMacro:
if false and sfImmediate notin s.flags: # XXX not yet enabled
if sfImmediate notin s.flags:
result = semDirectOp(c, n, flags)
else:
result = semMacroExpr(c, n, s)
result = semMacroExpr(c, n, n, s)
of skTemplate:
if sfImmediate notin s.flags:
result = semDirectOp(c, n, flags)
else:
result = semTemplateExpr(c, n, s)
of skType:
of skType:
# XXX think about this more (``set`` procs)
if n.len == 2:
result = semConv(c, n, s)

View file

@ -51,7 +51,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
of skTemplate:
result = semTemplateExpr(c, n, s, false)
of skMacro:
result = semMacroExpr(c, n, s, false)
result = semMacroExpr(c, n, n, s, false)
of skGenericParam:
result = newSymNode(s, n.info)
of skParam:
@ -97,7 +97,7 @@ proc semGenericStmt(c: PContext, n: PNode,
incl(s.flags, sfUsed)
case s.kind
of skMacro:
result = semMacroExpr(c, n, s, false)
result = semMacroExpr(c, n, n, s, false)
of skTemplate:
result = semTemplateExpr(c, n, s, false)
# BUGFIX: we must not return here, we need to do first phase of

View file

@ -892,13 +892,10 @@ proc semConverterDef(c: PContext, n: PNode): PNode =
proc semMacroDef(c: PContext, n: PNode): PNode =
checkSonsLen(n, bodyPos + 1)
if n.sons[genericParamsPos].kind != nkEmpty:
LocalError(n.info, errNoGenericParamsAllowedForX, "macro")
result = semProcAux(c, n, skMacro, macroPragmas)
var s = result.sons[namePos].sym
var t = s.typ
if t.sons[0] == nil: LocalError(n.info, errXNeedsReturnType, "macro")
if sonsLen(t) != 2: LocalError(n.info, errXRequiresOneArgument, "macro")
if n.sons[bodyPos].kind == nkEmpty:
LocalError(n.info, errImplOfXexpected, s.name.s)

View file

@ -237,9 +237,11 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
return errorSym(c, n)
if result.typ.kind != tyGenericParam:
# XXX get rid of this hack!
var oldInfo = n.info
reset(n[])
n.kind = nkSym
n.sym = result
n.info = oldInfo
else:
LocalError(n.info, errIdentifierExpected)
result = errorSym(c, n)
@ -549,7 +551,9 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
incl(result.flags, tfFinal)
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
if kind == skMacro and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}:
if kind == skMacro:
# within a macro, every param has the type PNimrodNode!
# and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}:
let nn = getSysSym"PNimrodNode"
var a = copySym(param)
a.typ = nn.typ
@ -779,7 +783,7 @@ proc semTypeFromMacro(c: PContext, n: PNode): PType =
markUsed(n, sym)
case sym.kind
of skMacro:
result = semTypeNode(c, semMacroExpr(c, n, sym), nil)
result = semTypeNode(c, semMacroExpr(c, n, n, sym), nil)
of skTemplate:
result = semTypeNode(c, semTemplateExpr(c, n, sym), nil)
else: