bindSym suffices; no 'bind' for macros anymore
This commit is contained in:
parent
8a92e95ccf
commit
9a7f0cd851
9 changed files with 48 additions and 73 deletions
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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!
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue