bindSym suffices; no 'bind' for macros anymore

This commit is contained in:
Araq 2012-08-25 01:34:50 +02:00
commit 9a7f0cd851
9 changed files with 48 additions and 73 deletions

View file

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

View file

@ -40,7 +40,6 @@ type
lastException*: PNode lastException*: PNode
mode*: TEvalMode mode*: TEvalMode
globals*: TIdNodeTable # state of global vars globals*: TIdNodeTable # state of global vars
boundSyms: TStrTable # for 'bind' support within macros
PEvalContext* = ref TEvalContext PEvalContext* = ref TEvalContext
@ -66,7 +65,6 @@ proc newEvalContext*(module: PSym, filename: string,
result.module = module result.module = module
result.mode = mode result.mode = mode
initIdNodeTable(result.globals) initIdNodeTable(result.globals)
initStrTable(result.boundSyms)
proc pushStackFrame*(c: PEvalContext, t: PStackFrame) {.inline.} = proc pushStackFrame*(c: PEvalContext, t: PStackFrame) {.inline.} =
t.next = c.tos t.next = c.tos
@ -933,26 +931,6 @@ proc evalExpandToAst(c: PEvalContext, original: PNode): PNode =
"ExpandToAst: expanded symbol is no macro or template") "ExpandToAst: expanded symbol is no macro or template")
result = emptyNode 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 = proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
var m = getMagic(n) var m = getMagic(n)
case m case m
@ -1173,13 +1151,9 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[1], {efLValue}) result = evalAux(c, n.sons[1], {efLValue})
if isSpecial(result): return if isSpecial(result): return
result = copyTree(result) result = copyTree(result)
of mNGetBoundSym: of mNBindSym:
result = evalAux(c, n.sons[1], {}) # trivial implementation:
if isSpecial(result): return result = n.sons[1]
if not (result.kind in {nkStrLit..nkTripleStrLit}):
stackTrace(c, n, errFieldXNotFound, "getBoundSym")
return
result = getBoundSym(c, result)
of mStrToIdent: of mStrToIdent:
result = evalAux(c, n.sons[1], {}) result = evalAux(c, n.sons[1], {})
if isSpecial(result): return if isSpecial(result): return
@ -1269,11 +1243,6 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
if isEmpty(a) or isEmpty(b) or isEmpty(cc): result = emptyNode if isEmpty(a) or isEmpty(b) or isEmpty(cc): result = emptyNode
else: result = evalOp(m, n, a, b, cc) 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 = proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
result = emptyNode result = emptyNode
dec(gNestedEvals) dec(gNestedEvals)
@ -1344,10 +1313,8 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
result.typ = n.typ result.typ = n.typ
of nkPragmaBlock: of nkPragmaBlock:
result = evalAux(c, n.sons[1], flags) result = evalAux(c, n.sons[1], flags)
of nkBindStmt:
evalBindStmt(c, n)
of nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr, of nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr,
nkLambdaKinds, nkContinueStmt, nkIdent, nkParForStmt: nkLambdaKinds, nkContinueStmt, nkIdent, nkParForStmt, nkBindStmt:
result = raiseCannotEval(c, n.info) result = raiseCannotEval(c, n.info)
of nkRefTy: of nkRefTy:
result = evalAux(c, n.sons[0], flags) result = evalAux(c, n.sons[0], flags)

View file

@ -342,6 +342,19 @@ proc changeType(n: PNode, newType: PType) =
else: nil else: nil
n.typ = newType n.typ = newType
proc arrayConstrType(c: PContext, n: PNode): PType =
var typ = newTypeS(tyArrayConstr, c)
rawAddSon(typ, nil) # index type
if sonsLen(n) == 0:
rawAddSon(typ, newTypeS(tyEmpty, c)) # needs an empty basetype!
else:
var x = n.sons[0]
var lastIndex: biggestInt = sonsLen(n) - 1
var t = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyOrdinal})
addSonSkipIntLit(typ, t)
typ.sons[0] = makeRangeType(c, 0, sonsLen(n) - 1, n.info)
result = typ
proc semArrayConstr(c: PContext, n: PNode): PNode = proc semArrayConstr(c: PContext, n: PNode): PNode =
result = newNodeI(nkBracket, n.info) result = newNodeI(nkBracket, n.info)
result.typ = newTypeS(tyArrayConstr, c) result.typ = newTypeS(tyArrayConstr, c)
@ -382,7 +395,8 @@ proc fixAbstractType(c: PContext, n: PNode) =
case it.kind case it.kind
of nkHiddenStdConv, nkHiddenSubConv: of nkHiddenStdConv, nkHiddenSubConv:
if it.sons[1].kind == nkBracket: if it.sons[1].kind == nkBracket:
it.sons[1] = semArrayConstr(c, it.sons[1]) it.sons[1].typ = arrayConstrType(c, it.sons[1])
#it.sons[1] = semArrayConstr(c, it.sons[1])
if skipTypes(it.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: if skipTypes(it.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
#if n.sons[0].kind == nkSym and IdentEq(n.sons[0].sym.name, "[]="): #if n.sons[0].kind == nkSym and IdentEq(n.sons[0].sym.name, "[]="):
# debug(n) # debug(n)

View file

@ -45,6 +45,24 @@ proc semOrd(c: PContext, n: PNode): PNode =
result.typ = makeRangeType(c, firstOrd(n.sons[1].typ), result.typ = makeRangeType(c, firstOrd(n.sons[1].typ),
lastOrd(n.sons[1].typ), n.info) lastOrd(n.sons[1].typ), n.info)
proc semBindSym(c: PContext, n: PNode): PNode =
result = copyNode(n)
result.add(n.sons[0])
let sl = c.semConstExpr(c, n.sons[1])
if sl.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
LocalError(n.info, errStringLiteralExpected)
return errorNode(c, n)
let id = newIdentNode(getIdent(sl.strVal), n.info)
let s = QualifiedLookUp(c, id)
if s != nil:
# we need to mark all symbols:
let sc = symChoice(c, id, s)
result.add(sc)
else:
LocalError(n.sons[1].info, errUndeclaredIdentifier, sl.strVal)
proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode
proc magicsAfterOverloadResolution(c: PContext, n: PNode, proc magicsAfterOverloadResolution(c: PContext, n: PNode,
flags: TExprFlags): PNode = flags: TExprFlags): PNode =
@ -57,5 +75,6 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
of mInstantiationInfo: result = semInstantiationInfo(c, n) of mInstantiationInfo: result = semInstantiationInfo(c, n)
of mOrd: result = semOrd(c, n) of mOrd: result = semOrd(c, n)
of mShallowCopy: result = semShallowCopy(c, n, flags) of mShallowCopy: result = semShallowCopy(c, n, flags)
of mNBindSym: result = semBindSym(c, n)
else: result = n else: result = n

View file

@ -1118,22 +1118,6 @@ proc insertDestructors(c: PContext, varSection: PNode):
return 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 = proc SemStmt(c: PContext, n: PNode): PNode =
const # must be last statements in a block: const # must be last statements in a block:
LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt} LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt}
@ -1222,8 +1206,6 @@ proc SemStmt(c: PContext, n: PNode): PNode =
result = semPragmaBlock(c, n) result = semPragmaBlock(c, n)
of nkStaticStmt: of nkStaticStmt:
result = semStaticStmt(c, n) result = semStaticStmt(c, n)
of nkBindStmt:
result = semBindStmtForMacro(c, n)
else: else:
# in interactive mode, we embed the expression in an 'echo': # in interactive mode, we embed the expression in an 'echo':
if gCmd == cmdInteractive: if gCmd == cmdInteractive:

View file

@ -3154,27 +3154,22 @@ The macro call expands to:
writeln(stdout, x) writeln(stdout, x)
Bind in macros BindSym
~~~~~~~~~~~~~~ ~~~~~~~
The above ``debug`` macro relies on the fact that ``write``, ``writeln`` and The above ``debug`` macro relies on the fact that ``write``, ``writeln`` and
``stdout`` are declared in the system module and thus visible in the ``stdout`` are declared in the system module and thus visible in the
instantiating context. There is a way to use bound identifiers instantiating context. There is a way to use bound identifiers
(aka `symbols`:idx) instead of using unbound identifiers. The ``bind`` (aka `symbols`:idx) instead of using unbound identifiers. The ``bindSym``
statement plus the ``bindSym`` builtin can be used for that: builtin can be used for that:
.. code-block:: nimrod .. code-block:: nimrod
# to work with Nimrod syntax trees, we need an API that is defined in the
# ``macros`` module:
import macros import macros
macro debug(n: expr): stmt = macro debug(n: expr): stmt =
# we need to declare the used symbols here:
bind write, writeln, stdout
result = newNimNode(nnkStmtList, n) result = newNimNode(nnkStmtList, n)
# iterate over any argument that is passed to this macro:
for i in 1..n.len-1: for i in 1..n.len-1:
# we can access the bound symbol via 'bindSym': # we can bind symbols in scope via 'bindSym':
add(result, newCall(bindSym"write", bindSym"stdout", toStrLit(n[i]))) add(result, newCall(bindSym"write", bindSym"stdout", toStrLit(n[i])))
add(result, newCall(bindSym"write", bindSym"stdout", newStrLitNode(": "))) add(result, newCall(bindSym"write", bindSym"stdout", newStrLitNode(": ")))
add(result, newCall(bindSym"writeln", bindSym"stdout", n[i])) add(result, newCall(bindSym"writeln", bindSym"stdout", n[i]))
@ -3203,7 +3198,7 @@ The macro call expands to:
writeln(stdout, x) writeln(stdout, x)
However, the symbols ``write``, ``writeln`` and ``stdout`` are already bound However, the symbols ``write``, ``writeln`` and ``stdout`` are already bound
and are not looked up again. As the example shows, ``bind`` does work with and are not looked up again. As the example shows, ``bindSym`` does work with
overloaded symbols implicitely. overloaded symbols implicitely.

View file

@ -186,7 +186,7 @@ proc newIdentNode*(i: string): PNimrodNode {.compileTime.} =
result = newNimNode(nnkIdent) result = newNimNode(nnkIdent)
result.ident = !i result.ident = !i
proc bindSym*(ident: string): PNimrodNode {.magic: "NGetBoundSym".} proc bindSym*(ident: string): PNimrodNode {.magic: "NBindSym".}
## creates a node that binds `ident` to a symbol node. The bound symbol ## creates a node that binds `ident` to a symbol node. The bound symbol
## needs to be predeclared in a ``bind`` statement! ## needs to be predeclared in a ``bind`` statement!

View file

@ -326,8 +326,7 @@ proc styledEchoProcessArg(color: TForegroundColor) = setForeGroundColor color
proc styledEchoProcessArg(color: TBackgroundColor) = setBackGroundColor color proc styledEchoProcessArg(color: TBackgroundColor) = setBackGroundColor color
macro styledEcho*(m: stmt): stmt = macro styledEcho*(m: stmt): stmt =
bind styledEchoProcessArg, write, resetAttributes, stdout ## to be documented.
result = newNimNode(nnkStmtList) result = newNimNode(nnkStmtList)
for i in countup(1, m.len - 1): for i in countup(1, m.len - 1):

View file

@ -160,7 +160,6 @@ Language Additions
in templates. in templates.
- Comments can be continued with a backslash continuation character so that - Comments can be continued with a backslash continuation character so that
comment pieces don't have to align on the same column. comment pieces don't have to align on the same column.
- Macros support the ``bind`` statement.
2012-02-09 Version 0.8.14 released 2012-02-09 Version 0.8.14 released