Added typeinfo module

This commit is contained in:
dom96
2011-06-09 22:23:29 +01:00
parent 3bc821aa5c
commit 8b98ba9a63
5 changed files with 210 additions and 3 deletions

View File

@@ -352,7 +352,7 @@ type
mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal,
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal,
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr,
mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError
mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError, mGetTypeInfo
type
PNode* = ref TNode

View File

@@ -1052,6 +1052,10 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprAny($1, $2)",
[addrLoc(a), genTypeInfo(p.module, t)]))
proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) =
var t = skipTypes(e.sons[1].typ, abstractVarRange)
putIntoDest(p, d, e.typ, genTypeInfo(p.module, t))
proc genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
var a: TLoc
InitLocExpr(p, n.sons[1], a)
@@ -1378,6 +1382,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mShrI..mXor: binaryArith(p, e, d, op)
of mAddi..mModi64: binaryArithOverflow(p, e, d, op)
of mRepr: genRepr(p, e, d)
of mGetTypeInfo: genGetTypeInfo(p, e, d)
of mSwap: genSwap(p, e, d)
of mUnaryLt:
if not (optOverflowCheck in p.Options): unaryExpr(p, e, d, "$1 - 1")

195
lib/core/typeinfo.nim Normal file
View File

@@ -0,0 +1,195 @@
include "system/hti.nim"
type
TType* = enum # This mirrors the TNimKind type in hti.nim
TNNone, TNBool, TNChar,
TNEmpty, TNArrayConstr, TNNil, TNExpr, TNStmt, TNTypeDesc,
TNGenericInvokation, # ``T[a, b]`` for types to invoke
TNGenericBody, # ``T[a, b, body]`` last parameter is the body
TNGenericInst, # ``T[a, b, realInstance]`` instantiated generic type
TNGenericParam, # ``a`` in the example
TNDistinct, # distinct type
TNEnum,
TNOrdinal,
TNArray,
TNObject,
TNTuple,
TNSet,
TNRange,
TNPtr, TNRef,
TNVar,
TNSequence,
TNProc,
TNPointer, TNOpenArray,
TNString, TNCString, TNForward,
TNInt, TNInt8, TNInt16, TNInt32, TNInt64,
TNFloat, TNFloat32, TNFloat64, TNFloat128,
TNPureObject # signals that object has no `n_type` field
TAny* = object {.pure.}
value: pointer
rawType: PNimType
ppointer = ptr pointer
TGenSeq {.pure.} = object
len, space: int
PGenSeq = ptr TGenSeq
const
GenericSeqSize = (2 * sizeof(int))
proc genericAssign(dest, src: Pointer, mt: PNimType) {.importc.}
proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int =
assert(n.kind == nkCase)
var d: int
var a = cast[TAddress](aa)
case n.typ.size
of 1: d = ze(cast[ptr int8](a +% n.offset)[])
of 2: d = ze(cast[ptr int16](a +% n.offset)[])
of 4: d = int(cast[ptr int32](a +% n.offset)[])
else: assert(false)
return d
proc selectBranch(aa: Pointer, n: ptr TNimNode): ptr TNimNode =
var discr = getDiscriminant(aa, n)
if discr <% n.len:
result = n.sons[discr]
if result == nil: result = n.sons[n.len]
# n.sons[n.len] contains the ``else`` part (but may be nil)
else:
result = n.sons[n.len]
proc newAny(value: pointer, rawType: PNimType): TAny =
result.value = value
result.rawType = rawType
proc toAny*[T](x: var T): TAny =
var k = getTypeInfo(x)
return newAny(addr(x), cast[PNimType](k))
proc getType*(x: TAny): TType = return TType(x.rawType.kind)
proc `[]`*(x: TAny, i: int): TAny =
assert getType(x) in {TNArray, TNSequence}
if x.getType == TNArray:
var bs = x.rawType.base.size
if i >% (x.rawType.size div bs - 1):
raise newException(EInvalidIndex, "Index out of bounds.")
return newAny(cast[pointer](cast[TAddress](x.value) + i*bs),
x.rawType.base)
elif x.getType == TNSequence:
var s = cast[ppointer](x.value)[]
var bs = x.rawType.base.size
if i >% (cast[PGenSeq](s).len-1):
raise newException(EInvalidIndex, "Index out of bounds.")
return newAny(cast[pointer](cast[TAddress](s) + GenericSeqSize+i*bs),
x.rawType.base)
proc `[]=`*(x: TAny, i: int, y: TAny) =
assert getType(x) in {TNArray, TNSequence}
if x.getType == TNArray:
var bs = x.rawType.base.size
if i >% (x.rawType.size div bs - 1):
raise newException(EInvalidIndex, "Index out of bounds.")
genericAssign(cast[pointer](cast[TAddress](x.value) + i*bs),
y.value, y.rawType)
elif x.getType == TNSequence:
var s = cast[ppointer](x.value)[]
var bs = x.rawType.base.size
if i >% (cast[PGenSeq](s).len-1):
raise newException(EInvalidIndex, "Index out of bounds.")
genericAssign(cast[pointer](cast[TAddress](s) + GenericSeqSize+i*bs),
y.value, y.rawType)
proc fieldsAux(p: pointer, n: ptr TNimNode,
ret: var seq[tuple[name: cstring, any: TAny]]) =
case n.kind
of nkNone: assert(false)
of nkSlot:
var tup = (n.name,
newAny(cast[pointer](cast[TAddress](p) + n.offset), n.typ))
ret.add(tup)
assert ret[ret.len()-1][0] != nil
of nkList:
for i in 0..n.len-1:
fieldsAux(p, n.sons[i], ret)
of nkCase:
var m = selectBranch(p, n)
ret.add((n.name, newAny(cast[pointer](cast[TAddress](p) + n.offset), n.typ)))
if m != nil: fieldsAux(p, m, ret)
iterator fields*(x: TAny): tuple[name: string, any: TAny] =
assert getType(x) in {TNTuple, TNPureObject, TNObject}
var p = x.value
var t = x.rawType
if x.getType == TNObject: t = cast[ptr PNimType](x.value)[]
var n = t.node
var ret: seq[tuple[name: cstring, any: TAny]] = @[]
fieldsAux(p, n, ret)
for name, any in items(ret):
yield ($name, any)
proc `[]`*(x: TAny): TAny =
assert getType(x) in {TNRef, TNPtr}
var p = cast[ppointer](x.value)[]
if p == nil:
result.value = nil
result.rawType = nil
return
else:
result.value = p
result.rawType = x.rawType.base
proc readInt*(x: TAny): int = cast[ptr int](x.value)[]
proc readInt8*(x: TAny): int8 = cast[ptr int8](x.value)[]
proc readInt16*(x: TAny): int16 = cast[ptr int16](x.value)[]
proc readInt32*(x: TAny): int32 = cast[ptr int32](x.value)[]
proc readInt64*(x: TAny): int64 = cast[ptr int64](x.value)[]
proc readFloat*(x: TAny): float = cast[ptr float](x.value)[]
proc readFloat32*(x: TAny): float32 = cast[ptr float32](x.value)[]
proc readFloat64*(x: TAny): float64 = cast[ptr float64](x.value)[]
proc readString*(x: TAny): string = cast[ptr string](x.value)[]
when isMainModule:
type
TE = enum
blah, blah2
TestObj = object
test, asd: int
case test2: TE
of blah:
help: string
else:
nil
var test = @[0,1,2,3,4]
var x = toAny(test)
var y = 78
x[4] = toAny(y)
echo cast[ptr int](x[2].value)[]
var test2: tuple[name: string, s: int] = ("test", 56)
var x2 = toAny(test2)
for n, a in fields(x2):
echo("Name = ", n)
echo("Any type = ", a.getType)
var test3: TestObj
test3.test = 42
test3.test2 = blah2
var x3 = toAny(test3)
for n, a in fields(x3):
echo("Name = ", n)
echo("Any type = ", a.getType)
var test4: ref string
new(test4)
test4[] = "test"
var x4 = toAny(test4)
echo x4[].getType()

View File

@@ -1889,3 +1889,4 @@ proc `[]=`*[T](s: var seq[T], x: TSlice[int], b: openArray[T]) =
else:
raise newException(EOutOfRange, "differing lengths for slice assignment")
proc getTypeInfo*[T](x: T): pointer {.magic: "ToAny".}

View File

@@ -7,6 +7,12 @@
# distribution, for details about the copyright.
#
when defined(NimString):
# we are in system module:
{.pragma: codegenType, compilerproc.}
else:
{.pragma: codegenType.}
type # This should be he same as ast.TTypeKind
# many enum fields are not used at runtime
TNimKind = enum
@@ -35,7 +41,7 @@ type # This should be he same as ast.TTypeKind
tyPureObject # signals that object has no `n_type` field
TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase
TNimNode {.compilerproc, final.} = object
TNimNode {.codegenType, final.} = object
kind: TNimNodeKind
offset: int
typ: ptr TNimType
@@ -48,7 +54,7 @@ type # This should be he same as ast.TTypeKind
ntfAcyclic = 1, # type cannot form a cycle
ntfEnumHole = 2 # enum has holes and thus `$` for them needs the slow
# version
TNimType {.compilerproc, final.} = object
TNimType {.codegenType, final.} = object
size: int
kind: TNimKind
flags: set[TNimTypeFlag]