implemented 'bind' for macros
This commit is contained in:
parent
bdf3bee055
commit
c7ba6f5eb6
7 changed files with 83 additions and 15 deletions
|
|
@ -439,6 +439,7 @@ type
|
|||
mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal,
|
||||
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo,
|
||||
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr,
|
||||
mNGetBoundSym,
|
||||
mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError,
|
||||
mInstantiationInfo, mGetTypeInfo
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ type
|
|||
lastException*: PNode
|
||||
mode*: TEvalMode
|
||||
globals*: TIdNodeTable # state of global vars
|
||||
boundSyms: TStrTable # for 'bind' support within macros
|
||||
|
||||
PEvalContext* = ref TEvalContext
|
||||
|
||||
|
|
@ -65,6 +66,7 @@ proc newEvalContext*(module: PSym, filename: string,
|
|||
result.module = module
|
||||
result.mode = mode
|
||||
initIdNodeTable(result.globals)
|
||||
initStrTable(result.boundSyms)
|
||||
|
||||
proc pushStackFrame*(c: PEvalContext, t: PStackFrame) {.inline.} =
|
||||
t.next = c.tos
|
||||
|
|
@ -931,6 +933,26 @@ proc evalExpandToAst(c: PEvalContext, original: PNode): PNode =
|
|||
"ExpandToAst: expanded symbol is no macro or template")
|
||||
result = emptyNode
|
||||
|
||||
proc getBoundSym(c: PEvalContext, n: PNode): PNode =
|
||||
# we return either an nkSym or an nkSymChoice; XXX we really need
|
||||
# to distinguish between open and closed nkSymChoice somehow.
|
||||
var ident = getIdent(n.strVal)
|
||||
|
||||
# semantic checking requires a type; ``fitNode`` deals with it
|
||||
# appropriately
|
||||
result = newNodeIT(nkSymChoice, n.info, newType(tyNone, c.module))
|
||||
|
||||
var ii: TIdentIter
|
||||
var a = InitIdentIter(ii, c.boundSyms, ident)
|
||||
while a != nil:
|
||||
incl(a.flags, sfUsed)
|
||||
addSon(result, newSymNode(a, n.info))
|
||||
a = NextIdentIter(ii, c.boundSyms)
|
||||
case result.len
|
||||
of 0: stackTrace(c, n, errUndeclaredIdentifier, n.strVal)
|
||||
of 1: result = result.sons[0]
|
||||
else: nil
|
||||
|
||||
proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||
var m = getMagic(n)
|
||||
case m
|
||||
|
|
@ -1151,6 +1173,13 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
|||
result = evalAux(c, n.sons[1], {efLValue})
|
||||
if isSpecial(result): return
|
||||
result = copyTree(result)
|
||||
of mNGetBoundSym:
|
||||
result = evalAux(c, n.sons[1], {})
|
||||
if isSpecial(result): return
|
||||
if not (result.kind in {nkStrLit..nkTripleStrLit}):
|
||||
stackTrace(c, n, errFieldXNotFound, "getBoundSym")
|
||||
return
|
||||
result = getBoundSym(c, result)
|
||||
of mStrToIdent:
|
||||
result = evalAux(c, n.sons[1], {})
|
||||
if isSpecial(result): return
|
||||
|
|
@ -1240,6 +1269,11 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
|||
if isEmpty(a) or isEmpty(b) or isEmpty(cc): result = emptyNode
|
||||
else: result = evalOp(m, n, a, b, cc)
|
||||
|
||||
proc evalBindStmt(c: PEvalContext, n: PNode) =
|
||||
for i in 0 .. < n.len:
|
||||
let a = n.sons[i]
|
||||
if a.kind == nkSym: StrTableAdd(c.boundSyms, a.sym)
|
||||
|
||||
proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||
result = emptyNode
|
||||
dec(gNestedEvals)
|
||||
|
|
@ -1310,6 +1344,8 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
|||
result.typ = n.typ
|
||||
of nkPragmaBlock:
|
||||
result = evalAux(c, n.sons[1], flags)
|
||||
of nkBindStmt:
|
||||
evalBindStmt(c, n)
|
||||
of nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr,
|
||||
nkLambdaKinds, nkContinueStmt, nkIdent, nkParForStmt:
|
||||
result = raiseCannotEval(c, n.info)
|
||||
|
|
|
|||
|
|
@ -1118,6 +1118,22 @@ proc insertDestructors(c: PContext, varSection: PNode):
|
|||
|
||||
return
|
||||
|
||||
proc semBindStmtForMacro(c: PContext, n: PNode): PNode =
|
||||
if c.p.owner.kind != skMacro:
|
||||
LocalError(n.info, errXNotAllowedHere, "bind")
|
||||
result = newNodeI(nkBindStmt, n.info)
|
||||
for i in 0 .. < n.len:
|
||||
var a = n.sons[i]
|
||||
let s = QualifiedLookUp(c, a)
|
||||
if s != nil:
|
||||
# we need to mark all symbols:
|
||||
let sc = symChoice(c, a, s)
|
||||
if sc.kind == nkSym: result.add(sc)
|
||||
else:
|
||||
for x in items(sc): result.add(x)
|
||||
else:
|
||||
illFormedAst(a)
|
||||
|
||||
proc SemStmt(c: PContext, n: PNode): PNode =
|
||||
const # must be last statements in a block:
|
||||
LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt}
|
||||
|
|
@ -1206,6 +1222,8 @@ proc SemStmt(c: PContext, n: PNode): PNode =
|
|||
result = semPragmaBlock(c, n)
|
||||
of nkStaticStmt:
|
||||
result = semStaticStmt(c, n)
|
||||
of nkBindStmt:
|
||||
result = semBindStmtForMacro(c, n)
|
||||
else:
|
||||
# in interactive mode, we embed the expression in an 'echo':
|
||||
if gCmd == cmdInteractive:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue