mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-07 12:24:19 +00:00
implements a type API for macros
This commit is contained in:
@@ -945,6 +945,13 @@ template `{}`*(n: PNode, i: int): expr = n[i -| n]
|
||||
template `{}=`*(n: PNode, i: int, s: PNode): stmt =
|
||||
n.sons[i -| n] = s
|
||||
|
||||
when defined(useNodeIds):
|
||||
const nodeIdToDebug* = -1 # 884953 # 612794
|
||||
#612840 # 612905 # 614635 # 614637 # 614641
|
||||
# 423408
|
||||
#429107 # 430443 # 441048 # 441090 # 441153
|
||||
var gNodeId: int
|
||||
|
||||
proc newNode*(kind: TNodeKind): PNode =
|
||||
new(result)
|
||||
result.kind = kind
|
||||
@@ -1061,13 +1068,6 @@ proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) =
|
||||
proc discardSons*(father: PNode) =
|
||||
father.sons = nil
|
||||
|
||||
when defined(useNodeIds):
|
||||
const nodeIdToDebug* = -1 # 884953 # 612794
|
||||
#612840 # 612905 # 614635 # 614637 # 614641
|
||||
# 423408
|
||||
#429107 # 430443 # 441048 # 441090 # 441153
|
||||
var gNodeId: int
|
||||
|
||||
proc withInfo*(n: PNode, info: TLineInfo): PNode =
|
||||
n.info = info
|
||||
return n
|
||||
|
||||
@@ -332,10 +332,15 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||
if result.typ.kind != tyGenericParam:
|
||||
# XXX get rid of this hack!
|
||||
var oldInfo = n.info
|
||||
when defined(useNodeIds):
|
||||
let oldId = n.id
|
||||
reset(n[])
|
||||
when defined(useNodeIds):
|
||||
n.id = oldId
|
||||
n.kind = nkSym
|
||||
n.sym = result
|
||||
n.info = oldInfo
|
||||
n.typ = result.typ
|
||||
else:
|
||||
localError(n.info, errIdentifierExpected)
|
||||
result = errorSym(c, n)
|
||||
@@ -1179,11 +1184,12 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
var typeExpr = semExpr(c, n)
|
||||
if typeExpr.typ.kind != tyTypeDesc:
|
||||
localError(n.info, errTypeExpected)
|
||||
return errorType(c)
|
||||
result = typeExpr.typ.base
|
||||
if result.isMetaType:
|
||||
var preprocessed = semGenericStmt(c, n)
|
||||
return makeTypeFromExpr(c, preprocessed)
|
||||
result = errorType(c)
|
||||
else:
|
||||
result = typeExpr.typ.base
|
||||
if result.isMetaType:
|
||||
var preprocessed = semGenericStmt(c, n)
|
||||
result = makeTypeFromExpr(c, preprocessed)
|
||||
of nkIdent, nkAccQuoted:
|
||||
var s = semTypeIdent(c, n)
|
||||
if s.typ == nil:
|
||||
@@ -1254,7 +1260,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
else:
|
||||
localError(n.info, errTypeExpected)
|
||||
result = newOrPrevType(tyError, prev, c)
|
||||
|
||||
n.typ = result
|
||||
|
||||
proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
|
||||
m.typ.kind = kind
|
||||
m.typ.align = size.int16
|
||||
|
||||
@@ -123,8 +123,12 @@ proc createStrKeepNode(x: var TFullReg) =
|
||||
if x.node.isNil:
|
||||
x.node = newNode(nkStrLit)
|
||||
elif x.node.kind == nkNilLit:
|
||||
when defined(useNodeIds):
|
||||
let id = x.node.id
|
||||
system.reset(x.node[])
|
||||
x.node.kind = nkStrLit
|
||||
when defined(useNodeIds):
|
||||
x.node.id = id
|
||||
elif x.node.kind notin {nkStrLit..nkTripleStrLit} or
|
||||
nfAllConst in x.node.flags:
|
||||
# XXX this is hacky; tests/txmlgen triggers it:
|
||||
@@ -1133,7 +1137,21 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
else:
|
||||
stackTrace(c, tos, pc, errFieldXNotFound, "ident")
|
||||
of opcNGetType:
|
||||
internalError(c.debug[pc], "unknown opcode " & $instr.opcode)
|
||||
let rb = instr.regB
|
||||
let rc = instr.regC
|
||||
if rc == 0:
|
||||
ensureKind(rkNode)
|
||||
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
|
||||
regs[ra].node = opMapTypeToAst(regs[rb].node.typ, c.debug[pc])
|
||||
else:
|
||||
stackTrace(c, tos, pc, errGenerated, "node has no type")
|
||||
else:
|
||||
# typeKind opcode:
|
||||
ensureKind(rkInt)
|
||||
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
|
||||
regs[ra].intVal = ord(regs[rb].node.typ.kind)
|
||||
#else:
|
||||
# stackTrace(c, tos, pc, errGenerated, "node has no type")
|
||||
of opcNStrVal:
|
||||
decodeB(rkNode)
|
||||
createStr regs[ra]
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
# (c) Copyright 2015 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import ast, types, msgs, osproc, streams, options
|
||||
import ast, types, msgs, osproc, streams, options, idents
|
||||
|
||||
proc readOutput(p: Process): string =
|
||||
result = ""
|
||||
@@ -19,11 +19,14 @@ proc readOutput(p: Process): string =
|
||||
discard p.waitForExit
|
||||
|
||||
proc opGorge*(cmd, input: string): string =
|
||||
var p = startProcess(cmd, options={poEvalCommand})
|
||||
if input.len != 0:
|
||||
p.inputStream.write(input)
|
||||
p.inputStream.close()
|
||||
result = p.readOutput
|
||||
try:
|
||||
var p = startProcess(cmd, options={poEvalCommand})
|
||||
if input.len != 0:
|
||||
p.inputStream.write(input)
|
||||
p.inputStream.close()
|
||||
result = p.readOutput
|
||||
except IOError, OSError:
|
||||
result = ""
|
||||
|
||||
proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
|
||||
try:
|
||||
@@ -36,3 +39,111 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
|
||||
except IOError:
|
||||
localError(info, errCannotOpenFile, file)
|
||||
result = ""
|
||||
|
||||
proc atomicTypeX(name: string; t: PType; info: TLineInfo): PNode =
|
||||
let sym = newSym(skType, getIdent(name), t.owner, info)
|
||||
result = newSymNode(sym)
|
||||
result.typ = t
|
||||
|
||||
proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode
|
||||
|
||||
proc mapTypeToBracket(name: string; t: PType; info: TLineInfo): PNode =
|
||||
result = newNodeIT(nkBracketExpr, info, t)
|
||||
result.add atomicTypeX(name, t, info)
|
||||
for i in 0 .. < t.len:
|
||||
result.add mapTypeToAst(t.sons[i], info)
|
||||
|
||||
proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode =
|
||||
template atomicType(name): expr = atomicTypeX(name, t, info)
|
||||
|
||||
case t.kind
|
||||
of tyNone: result = atomicType("none")
|
||||
of tyBool: result = atomicType("bool")
|
||||
of tyChar: result = atomicType("char")
|
||||
of tyNil: result = atomicType("nil")
|
||||
of tyExpr: result = atomicType("expr")
|
||||
of tyStmt: result = atomicType("stmt")
|
||||
of tyEmpty: result = atomicType"void"
|
||||
of tyArrayConstr, tyArray:
|
||||
result = newNodeIT(nkBracketExpr, info, t)
|
||||
result.add atomicType("array")
|
||||
result.add mapTypeToAst(t.sons[0], info)
|
||||
result.add mapTypeToAst(t.sons[1], info)
|
||||
of tyTypeDesc:
|
||||
if t.base != nil:
|
||||
result = newNodeIT(nkBracketExpr, info, t)
|
||||
result.add atomicType("typeDesc")
|
||||
result.add mapTypeToAst(t.base, info)
|
||||
else:
|
||||
result = atomicType"typeDesc"
|
||||
of tyGenericInvocation:
|
||||
result = newNodeIT(nkBracketExpr, info, t)
|
||||
for i in 0 .. < t.len:
|
||||
result.add mapTypeToAst(t.sons[i], info)
|
||||
of tyGenericInst, tyGenericBody, tyOrdinal, tyUserTypeClassInst:
|
||||
result = mapTypeToAst(t.lastSon, info)
|
||||
of tyGenericParam, tyDistinct, tyForward: result = atomicType(t.sym.name.s)
|
||||
of tyObject:
|
||||
if allowRecursion:
|
||||
result = newNodeIT(nkObjectTy, info, t)
|
||||
if t.sons[0] == nil:
|
||||
result.add ast.emptyNode
|
||||
else:
|
||||
result.add mapTypeToAst(t.sons[0], info)
|
||||
result.add copyTree(t.n)
|
||||
else:
|
||||
result = atomicType(t.sym.name.s)
|
||||
of tyEnum:
|
||||
result = newNodeIT(nkEnumTy, info, t)
|
||||
result.add copyTree(t.n)
|
||||
of tyTuple: result = mapTypeToBracket("tuple", t, info)
|
||||
of tySet: result = mapTypeToBracket("set", t, info)
|
||||
of tyPtr: result = mapTypeToBracket("ptr", t, info)
|
||||
of tyRef: result = mapTypeToBracket("ref", t, info)
|
||||
of tyVar: result = mapTypeToBracket("var", t, info)
|
||||
of tySequence: result = mapTypeToBracket("sequence", t, info)
|
||||
of tyProc: result = mapTypeToBracket("proc", t, info)
|
||||
of tyOpenArray: result = mapTypeToBracket("openArray", t, info)
|
||||
of tyRange:
|
||||
result = newNodeIT(nkBracketExpr, info, t)
|
||||
result.add atomicType("range")
|
||||
result.add t.n.sons[0].copyTree
|
||||
result.add t.n.sons[1].copyTree
|
||||
of tyPointer: result = atomicType"pointer"
|
||||
of tyString: result = atomicType"string"
|
||||
of tyCString: result = atomicType"cstring"
|
||||
of tyInt: result = atomicType"int"
|
||||
of tyInt8: result = atomicType"int8"
|
||||
of tyInt16: result = atomicType"int16"
|
||||
of tyInt32: result = atomicType"int32"
|
||||
of tyInt64: result = atomicType"int64"
|
||||
of tyFloat: result = atomicType"float"
|
||||
of tyFloat32: result = atomicType"float32"
|
||||
of tyFloat64: result = atomicType"float64"
|
||||
of tyFloat128: result = atomicType"float128"
|
||||
of tyUInt: result = atomicType"uint"
|
||||
of tyUInt8: result = atomicType"uint8"
|
||||
of tyUInt16: result = atomicType"uint16"
|
||||
of tyUInt32: result = atomicType"uint32"
|
||||
of tyUInt64: result = atomicType"uint64"
|
||||
of tyBigNum: result = atomicType"bignum"
|
||||
of tyConst: result = mapTypeToBracket("const", t, info)
|
||||
of tyMutable: result = mapTypeToBracket("mutable", t, info)
|
||||
of tyVarargs: result = mapTypeToBracket("varargs", t, info)
|
||||
of tyIter: result = mapTypeToBracket("iter", t, info)
|
||||
of tyProxy: result = atomicType"error"
|
||||
of tyBuiltInTypeClass: result = mapTypeToBracket("builtinTypeClass", t, info)
|
||||
of tyUserTypeClass: result = mapTypeToBracket("userTypeClass", t, info)
|
||||
of tyCompositeTypeClass: result = mapTypeToBracket("compositeTypeClass", t, info)
|
||||
of tyAnd: result = mapTypeToBracket("and", t, info)
|
||||
of tyOr: result = mapTypeToBracket("or", t, info)
|
||||
of tyNot: result = mapTypeToBracket("not", t, info)
|
||||
of tyAnything: result = atomicType"anything"
|
||||
of tyStatic, tyFromExpr, tyFieldAccessor:
|
||||
result = newNodeIT(nkBracketExpr, info, t)
|
||||
result.add atomicType("static")
|
||||
if t.n != nil:
|
||||
result.add t.n.copyTree
|
||||
|
||||
proc opMapTypeToAst*(t: PType; info: TLineInfo): PNode =
|
||||
result = mapTypeToAst(t, info, true)
|
||||
|
||||
@@ -950,7 +950,12 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
|
||||
of mNFloatVal: genUnaryABC(c, n, dest, opcNFloatVal)
|
||||
of mNSymbol: genUnaryABC(c, n, dest, opcNSymbol)
|
||||
of mNIdent: genUnaryABC(c, n, dest, opcNIdent)
|
||||
of mNGetType: genUnaryABC(c, n, dest, opcNGetType)
|
||||
of mNGetType:
|
||||
let tmp = c.genx(n.sons[1])
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
c.gABC(n, opcNGetType, dest, tmp, if n[0].sym.name.s == "typeKind": 1 else: 0)
|
||||
c.freeTemp(tmp)
|
||||
#genUnaryABC(c, n, dest, opcNGetType)
|
||||
of mNStrVal: genUnaryABC(c, n, dest, opcNStrVal)
|
||||
of mNSetIntVal:
|
||||
unused(n, dest)
|
||||
|
||||
@@ -83,7 +83,13 @@ type
|
||||
ntySequence, ntyProc, ntyPointer, ntyOpenArray,
|
||||
ntyString, ntyCString, ntyForward, ntyInt,
|
||||
ntyInt8, ntyInt16, ntyInt32, ntyInt64,
|
||||
ntyFloat, ntyFloat32, ntyFloat64, ntyFloat128
|
||||
ntyFloat, ntyFloat32, ntyFloat64, ntyFloat128,
|
||||
ntyUInt, ntyUInt8, ntyUInt16, ntyUInt32, ntyUInt64,
|
||||
ntyBigNum,
|
||||
ntyConst, ntyMutable, ntyVarargs,
|
||||
ntyIter,
|
||||
ntyError
|
||||
|
||||
TNimTypeKinds* {.deprecated.} = set[NimTypeKind]
|
||||
NimSymKind* = enum
|
||||
nskUnknown, nskConditional, nskDynLib, nskParam,
|
||||
@@ -100,7 +106,7 @@ type
|
||||
NimIdent* = object of RootObj
|
||||
## represents a Nim identifier in the AST
|
||||
|
||||
NimSymObj {.final.} = object # hidden
|
||||
NimSymObj = object # hidden
|
||||
NimSym* = ref NimSymObj
|
||||
## represents a Nim *symbol* in the compiler; a *symbol* is a looked-up
|
||||
## *ident*.
|
||||
@@ -125,16 +131,16 @@ proc `!`*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect.}
|
||||
## constructs an identifier from the string `s`
|
||||
|
||||
proc `$`*(i: NimIdent): string {.magic: "IdentToStr", noSideEffect.}
|
||||
## converts a Nimrod identifier to a string
|
||||
## converts a Nim identifier to a string
|
||||
|
||||
proc `$`*(s: NimSym): string {.magic: "IdentToStr", noSideEffect.}
|
||||
## converts a Nimrod symbol to a string
|
||||
## converts a Nim symbol to a string
|
||||
|
||||
proc `==`*(a, b: NimIdent): bool {.magic: "EqIdent", noSideEffect.}
|
||||
## compares two Nimrod identifiers
|
||||
## compares two Nim identifiers
|
||||
|
||||
proc `==`*(a, b: PNimrodNode): bool {.magic: "EqNimrodNode", noSideEffect.}
|
||||
## compares two Nimrod nodes
|
||||
## compares two Nim nodes
|
||||
|
||||
proc len*(n: PNimrodNode): int {.magic: "NLen", noSideEffect.}
|
||||
## returns the number of children of `n`.
|
||||
@@ -159,7 +165,19 @@ proc intVal*(n: PNimrodNode): BiggestInt {.magic: "NIntVal", noSideEffect.}
|
||||
proc floatVal*(n: PNimrodNode): BiggestFloat {.magic: "NFloatVal", noSideEffect.}
|
||||
proc symbol*(n: PNimrodNode): NimSym {.magic: "NSymbol", noSideEffect.}
|
||||
proc ident*(n: PNimrodNode): NimIdent {.magic: "NIdent", noSideEffect.}
|
||||
proc typ*(n: PNimrodNode): typedesc {.magic: "NGetType", noSideEffect.}
|
||||
|
||||
proc getType*(n: PNimrodNode): PNimrodNode {.magic: "NGetType", noSideEffect.}
|
||||
## with 'getType' you can access the node's `type`:idx:. A Nim type is
|
||||
## mapped to a Nim AST too, so it's slightly confusing but it means the same
|
||||
## API can be used to traverse types. Recursive types are flattened for you
|
||||
## so there is no danger of infinite recursions during traversal. To
|
||||
## resolve recursive types, you have to call 'getType' again. To see what
|
||||
## kind of type it is, call `typeKind` on getType's result.
|
||||
|
||||
proc typeKind*(n: PNimrodNode): NimTypeKind {.magic: "NGetType", noSideEffect.}
|
||||
## Returns the type kind of the node 'n' that should represent a type, that
|
||||
## means the node should have been obtained via `getType`.
|
||||
|
||||
proc strVal*(n: PNimrodNode): string {.magic: "NStrVal", noSideEffect.}
|
||||
|
||||
proc `intVal=`*(n: PNimrodNode, val: BiggestInt) {.magic: "NSetIntVal", noSideEffect.}
|
||||
@@ -216,7 +234,7 @@ proc newIdentNode*(i: string): PNimrodNode {.compileTime.} =
|
||||
result.ident = !i
|
||||
|
||||
type
|
||||
TBindSymRule* = enum ## specifies how ``bindSym`` behaves
|
||||
BindSymRule* = enum ## specifies how ``bindSym`` behaves
|
||||
brClosed, ## only the symbols in current scope are bound
|
||||
brOpen, ## open wrt overloaded symbols, but may be a single
|
||||
## symbol if not ambiguous (the rules match that of
|
||||
@@ -225,7 +243,9 @@ type
|
||||
## if not ambiguous (this cannot be achieved with
|
||||
## any other means in the language currently)
|
||||
|
||||
proc bindSym*(ident: string, rule: TBindSymRule = brClosed): PNimrodNode {.
|
||||
{.deprecated: [TBindSymRule: BindSymRule].}
|
||||
|
||||
proc bindSym*(ident: string, rule: BindSymRule = brClosed): PNimrodNode {.
|
||||
magic: "NBindSym", noSideEffect.}
|
||||
## creates a node that binds `ident` to a symbol node. The bound symbol
|
||||
## may be an overloaded symbol.
|
||||
@@ -236,7 +256,7 @@ proc bindSym*(ident: string, rule: TBindSymRule = brClosed): PNimrodNode {.
|
||||
## If ``rule == brForceOpen`` always an ``nkOpenSymChoice`` tree is
|
||||
## returned even if the symbol is not ambiguous.
|
||||
|
||||
proc genSym*(kind: TNimrodSymKind = nskLet; ident = ""): PNimrodNode {.
|
||||
proc genSym*(kind: NimSymKind = nskLet; ident = ""): PNimrodNode {.
|
||||
magic: "NGenSym", noSideEffect.}
|
||||
## generates a fresh symbol that is guaranteed to be unique. The symbol
|
||||
## needs to occur in a declaration context.
|
||||
@@ -245,7 +265,7 @@ proc callsite*(): PNimrodNode {.magic: "NCallSite", benign.}
|
||||
## returns the AST of the invocation expression that invoked this macro.
|
||||
|
||||
proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} =
|
||||
## converts the AST `n` to the concrete Nimrod code and wraps that
|
||||
## converts the AST `n` to the concrete Nim code and wraps that
|
||||
## in a string literal node
|
||||
return newStrLitNode(repr(n))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user