summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xcompiler/ast.nim2
-rwxr-xr-xcompiler/ccgexprs.nim5
-rw-r--r--lib/core/typeinfo.nim195
-rwxr-xr-xlib/system.nim1
-rwxr-xr-xlib/system/hti.nim10
5 files changed, 210 insertions, 3 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index d1c10168a..673dae5e9 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -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
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 2cb99d3a9..7447dbb6c 100755
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -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")
diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim
new file mode 100644
index 000000000..d6415d6dc
--- /dev/null
+++ b/lib/core/typeinfo.nim
@@ -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()
diff --git a/lib/system.nim b/lib/system.nim
index 5250a7ae7..e348bafea 100755
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -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".}
diff --git a/lib/system/hti.nim b/lib/system/hti.nim
index c6ea0bc44..c5b6967ef 100755
--- a/lib/system/hti.nim
+++ b/lib/system/hti.nim
@@ -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]