diff options
author | Araq <rumpf_a@web.de> | 2012-08-24 01:18:03 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2012-08-24 01:18:03 +0200 |
commit | c7ba6f5eb6f555ae650417c6f3bf9cdc0bad1427 (patch) | |
tree | e76ddea5dc65e48b16854fa69905f5618998acc1 /compiler | |
parent | bdf3bee05510718581510cb78fa70ca183039d55 (diff) | |
download | Nim-c7ba6f5eb6f555ae650417c6f3bf9cdc0bad1427.tar.gz |
implemented 'bind' for macros
Diffstat (limited to 'compiler')
-rwxr-xr-x | compiler/ast.nim | 1 | ||||
-rwxr-xr-x | compiler/evals.nim | 36 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 18 |
3 files changed, 55 insertions, 0 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 36cafe6f3..bb78fcd57 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -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 diff --git a/compiler/evals.nim b/compiler/evals.nim index 58f797e14..b107015eb 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -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) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index b8bf9e970..3bd368b7e 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -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: |