experimental support for querying the type of expressions within macros
normalised the line endings of macros.nim (minor edits otherwise)
This commit is contained in:
parent
9c8bc3a244
commit
2e5265bef5
5 changed files with 369 additions and 344 deletions
|
|
@ -41,6 +41,7 @@ type
|
||||||
callsite: PNode # for 'callsite' magic
|
callsite: PNode # for 'callsite' magic
|
||||||
mode*: TEvalMode
|
mode*: TEvalMode
|
||||||
globals*: TIdNodeTable # state of global vars
|
globals*: TIdNodeTable # state of global vars
|
||||||
|
getType*: proc(n: PNode): PNode
|
||||||
|
|
||||||
PEvalContext* = ref TEvalContext
|
PEvalContext* = ref TEvalContext
|
||||||
|
|
||||||
|
|
@ -1091,7 +1092,10 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||||
result = evalAux(c, n.sons[1], {})
|
result = evalAux(c, n.sons[1], {})
|
||||||
if isSpecial(result): return
|
if isSpecial(result): return
|
||||||
if result.kind != nkIdent: stackTrace(c, n, errFieldXNotFound, "ident")
|
if result.kind != nkIdent: stackTrace(c, n, errFieldXNotFound, "ident")
|
||||||
of mNGetType: result = evalAux(c, n.sons[1], {})
|
of mNGetType:
|
||||||
|
var ast = evalAux(c, n.sons[1], {})
|
||||||
|
InternalAssert c.getType != nil
|
||||||
|
result = c.getType(ast)
|
||||||
of mNStrVal:
|
of mNStrVal:
|
||||||
result = evalAux(c, n.sons[1], {})
|
result = evalAux(c, n.sons[1], {})
|
||||||
if isSpecial(result): return
|
if isSpecial(result): return
|
||||||
|
|
@ -1152,7 +1156,8 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
|
||||||
var a = result
|
var a = result
|
||||||
result = evalAux(c, n.sons[2], {efLValue})
|
result = evalAux(c, n.sons[2], {efLValue})
|
||||||
if isSpecial(result): return
|
if isSpecial(result): return
|
||||||
a.typ = result.typ # XXX: exception handling?
|
InternalAssert result.kind == nkSym and result.sym.kind == skType
|
||||||
|
a.typ = result.sym.typ
|
||||||
result = emptyNode
|
result = emptyNode
|
||||||
of mNSetStrVal:
|
of mNSetStrVal:
|
||||||
result = evalAux(c, n.sons[1], {efLValue})
|
result = evalAux(c, n.sons[1], {efLValue})
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ proc addParams(c: PContext, n: PNode, kind: TSymKind)
|
||||||
proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind)
|
proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind)
|
||||||
proc addResultNode(c: PContext, n: PNode)
|
proc addResultNode(c: PContext, n: PNode)
|
||||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
|
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
|
||||||
|
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||||
|
|
||||||
proc typeMismatch(n: PNode, formal, actual: PType) =
|
proc typeMismatch(n: PNode, formal, actual: PType) =
|
||||||
if formal.kind != tyError and actual.kind != tyError:
|
if formal.kind != tyError and actual.kind != tyError:
|
||||||
|
|
@ -156,8 +157,18 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||||
markUsed(n, sym)
|
markUsed(n, sym)
|
||||||
if sym == c.p.owner:
|
if sym == c.p.owner:
|
||||||
GlobalError(n.info, errRecursiveDependencyX, sym.name.s)
|
GlobalError(n.info, errRecursiveDependencyX, sym.name.s)
|
||||||
|
|
||||||
if c.evalContext == nil:
|
if c.evalContext == nil:
|
||||||
c.evalContext = newEvalContext(c.module, "", emStatic)
|
c.evalContext = newEvalContext(c.module, "", emStatic)
|
||||||
|
c.evalContext.getType = proc (n: PNode): PNode =
|
||||||
|
var e = tryExpr(c, n)
|
||||||
|
if e == nil:
|
||||||
|
result = symNodeFromType(c, errorType(c), n.info)
|
||||||
|
elif e.typ == nil:
|
||||||
|
result = newSymNode(getSysSym"void")
|
||||||
|
else:
|
||||||
|
result = symNodeFromType(c, e.typ, n.info)
|
||||||
|
|
||||||
result = evalMacroCall(c.evalContext, n, nOrig, sym)
|
result = evalMacroCall(c.evalContext, n, nOrig, sym)
|
||||||
if semCheck: result = semAfterMacroCall(c, result, sym)
|
if semCheck: result = semAfterMacroCall(c, result, sym)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1237,12 +1237,7 @@ proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
|
||||||
else:
|
else:
|
||||||
result = semDirectOp(c, n, flags)
|
result = semDirectOp(c, n, flags)
|
||||||
|
|
||||||
proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
# we replace this node by a 'true' or 'false' node:
|
|
||||||
if sonsLen(n) != 2: return semDirectOp(c, n, flags)
|
|
||||||
result = newIntNode(nkIntLit, 0)
|
|
||||||
result.info = n.info
|
|
||||||
result.typ = getSysType(tyBool)
|
|
||||||
# watch out, hacks ahead:
|
# watch out, hacks ahead:
|
||||||
let oldErrorCount = msgs.gErrorCounter
|
let oldErrorCount = msgs.gErrorCounter
|
||||||
let oldErrorMax = msgs.gErrorMax
|
let oldErrorMax = msgs.gErrorMax
|
||||||
|
|
@ -1264,8 +1259,8 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
let oldProcCon = c.p
|
let oldProcCon = c.p
|
||||||
c.generics = newGenericsCache()
|
c.generics = newGenericsCache()
|
||||||
try:
|
try:
|
||||||
discard semExpr(c, n.sons[1])
|
result = semExpr(c, n, flags)
|
||||||
result.intVal = ord(msgs.gErrorCounter == oldErrorCount)
|
if msgs.gErrorCounter != oldErrorCount: result = nil
|
||||||
except ERecoverableError:
|
except ERecoverableError:
|
||||||
nil
|
nil
|
||||||
# undo symbol table changes (as far as it's possible):
|
# undo symbol table changes (as far as it's possible):
|
||||||
|
|
@ -1282,6 +1277,14 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
msgs.gErrorCounter = oldErrorCount
|
msgs.gErrorCounter = oldErrorCount
|
||||||
msgs.gErrorMax = oldErrorMax
|
msgs.gErrorMax = oldErrorMax
|
||||||
|
|
||||||
|
proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
|
# we replace this node by a 'true' or 'false' node:
|
||||||
|
if sonsLen(n) != 2: return semDirectOp(c, n, flags)
|
||||||
|
|
||||||
|
result = newIntNode(nkIntLit, ord(tryExpr(c, n, flags) != nil))
|
||||||
|
result.info = n.info
|
||||||
|
result.typ = getSysType(tyBool)
|
||||||
|
|
||||||
proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
if sonsLen(n) == 3:
|
if sonsLen(n) == 3:
|
||||||
# XXX ugh this is really a hack: shallowCopy() can be overloaded only
|
# XXX ugh this is really a hack: shallowCopy() can be overloaded only
|
||||||
|
|
|
||||||
|
|
@ -84,12 +84,6 @@ type
|
||||||
## represents a Nimrod identifier in the AST
|
## represents a Nimrod identifier in the AST
|
||||||
|
|
||||||
TNimrodSymbol {.final.} = object # hidden
|
TNimrodSymbol {.final.} = object # hidden
|
||||||
TNimrodType {.final.} = object # hidden
|
|
||||||
|
|
||||||
PNimrodType* {.compilerproc.} = ref TNimrodType
|
|
||||||
## represents a Nimrod type in the compiler; currently this is not very
|
|
||||||
## useful as there is no API to deal with Nimrod types.
|
|
||||||
|
|
||||||
PNimrodSymbol* {.compilerproc.} = ref TNimrodSymbol
|
PNimrodSymbol* {.compilerproc.} = ref TNimrodSymbol
|
||||||
## represents a Nimrod *symbol* in the compiler; a *symbol* is a looked-up
|
## represents a Nimrod *symbol* in the compiler; a *symbol* is a looked-up
|
||||||
## *ident*.
|
## *ident*.
|
||||||
|
|
@ -140,14 +134,14 @@ proc intVal*(n: PNimrodNode): biggestInt {.magic: "NIntVal".}
|
||||||
proc floatVal*(n: PNimrodNode): biggestFloat {.magic: "NFloatVal".}
|
proc floatVal*(n: PNimrodNode): biggestFloat {.magic: "NFloatVal".}
|
||||||
proc symbol*(n: PNimrodNode): PNimrodSymbol {.magic: "NSymbol".}
|
proc symbol*(n: PNimrodNode): PNimrodSymbol {.magic: "NSymbol".}
|
||||||
proc ident*(n: PNimrodNode): TNimrodIdent {.magic: "NIdent".}
|
proc ident*(n: PNimrodNode): TNimrodIdent {.magic: "NIdent".}
|
||||||
proc typ*(n: PNimrodNode): PNimrodType {.magic: "NGetType".}
|
proc typ*(n: PNimrodNode): typedesc {.magic: "NGetType".}
|
||||||
proc strVal*(n: PNimrodNode): string {.magic: "NStrVal".}
|
proc strVal*(n: PNimrodNode): string {.magic: "NStrVal".}
|
||||||
|
|
||||||
proc `intVal=`*(n: PNimrodNode, val: biggestInt) {.magic: "NSetIntVal".}
|
proc `intVal=`*(n: PNimrodNode, val: biggestInt) {.magic: "NSetIntVal".}
|
||||||
proc `floatVal=`*(n: PNimrodNode, val: biggestFloat) {.magic: "NSetFloatVal".}
|
proc `floatVal=`*(n: PNimrodNode, val: biggestFloat) {.magic: "NSetFloatVal".}
|
||||||
proc `symbol=`*(n: PNimrodNode, val: PNimrodSymbol) {.magic: "NSetSymbol".}
|
proc `symbol=`*(n: PNimrodNode, val: PNimrodSymbol) {.magic: "NSetSymbol".}
|
||||||
proc `ident=`*(n: PNimrodNode, val: TNimrodIdent) {.magic: "NSetIdent".}
|
proc `ident=`*(n: PNimrodNode, val: TNimrodIdent) {.magic: "NSetIdent".}
|
||||||
proc `typ=`*(n: PNimrodNode, typ: PNimrodType) {.magic: "NSetType".}
|
proc `typ=`*(n: PNimrodNode, typ: typedesc) {.magic: "NSetType".}
|
||||||
proc `strVal=`*(n: PNimrodNode, val: string) {.magic: "NSetStrVal".}
|
proc `strVal=`*(n: PNimrodNode, val: string) {.magic: "NSetStrVal".}
|
||||||
|
|
||||||
proc newNimNode*(kind: TNimrodNodeKind,
|
proc newNimNode*(kind: TNimrodNodeKind,
|
||||||
|
|
|
||||||
12
tests/compile/tmacrotypes.nim
Normal file
12
tests/compile/tmacrotypes.nim
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import macros, typetraits
|
||||||
|
|
||||||
|
macro checkType(ex, expected: expr): stmt {.immediate.} =
|
||||||
|
var t = ex.typ
|
||||||
|
assert t.name == expected.strVal
|
||||||
|
|
||||||
|
proc voidProc = echo "hello"
|
||||||
|
proc intProc(a, b): int = 10
|
||||||
|
|
||||||
|
checkType(voidProc(), "void")
|
||||||
|
checkType(intProc(10, 20.0), "int")
|
||||||
|
checkType(noproc(10, 20.0), "Error Type")
|
||||||
Loading…
Add table
Add a link
Reference in a new issue