diff options
author | Araq <rumpf_a@web.de> | 2011-06-26 17:21:52 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2011-06-26 17:21:52 +0200 |
commit | 990dc2d7152f09c413d8fd96d66484d79aec97c7 (patch) | |
tree | a267c16996c61292c78019ab56d1116d811fd0dc /lib/core | |
parent | db0a4a9f86d167faccbd50f3f12f9de470e516b8 (diff) | |
download | Nim-990dc2d7152f09c413d8fd96d66484d79aec97c7.tar.gz |
code gen bugfixes; marshal.nim implemented
Diffstat (limited to 'lib/core')
-rwxr-xr-x | lib/core/marshal.nim | 275 | ||||
-rw-r--r-- | lib/core/typeinfo.nim | 243 |
2 files changed, 222 insertions, 296 deletions
diff --git a/lib/core/marshal.nim b/lib/core/marshal.nim deleted file mode 100755 index 26264b1a8..000000000 --- a/lib/core/marshal.nim +++ /dev/null @@ -1,275 +0,0 @@ -# -# -# Nimrod's Runtime Library -# (c) Copyright 2011 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module contains procs for serialization and deseralization of -## arbitrary Nimrod data structures. XXX This is not implemented yet! - -import streams - -proc load*[T](s: PStream, data: var T) = - ## loads `data` from the stream `s`. Raises `EIO` in case of an error. - -proc store*[T](s: PStream, data: T) = - ## stores `data` into the stream `s`. Raises `EIO` in case of an error. - - -type - TTypeInfo = distinct whatever - - TValue = object - t: TTypeInfo - x: pointer - - -proc rtti[T](x: T): TTypeInfo {.magic: "rtti".} - -proc `[]` (a: TValue, i: int): TValue = - ## works for arrays, objects, etc. - -proc `[]=` (a: TValue, i: int, x: TValue) = - ## - - - - -proc reprPointer(x: pointer): string {.compilerproc.} = - var buf: array [0..59, char] - c_sprintf(buf, "%p", x) - return $buf - -proc reprStrAux(result: var string, s: string) = - if cast[pointer](s) == nil: - add result, "nil" - return - add result, reprPointer(cast[pointer](s)) & "\"" - for c in items(s): - case c - of '"': add result, "\\\"" - of '\\': add result, "\\\\" # BUGFIX: forgotten - of '\10': add result, "\\10\"\n\"" # " \n " # better readability - of '\128' .. '\255', '\0'..'\9', '\11'..'\31': - add result, "\\" & reprInt(ord(c)) - else: result.add(c) - add result, "\"" - -proc reprStr(s: string): string {.compilerRtl.} = - result = "" - reprStrAux(result, s) - -proc reprBool(x: bool): string {.compilerRtl.} = - if x: result = "true" - else: result = "false" - -proc reprChar(x: char): string {.compilerRtl.} = - result = "\'" - case x - of '"': add result, "\\\"" - of '\\': add result, "\\\\" - of '\128' .. '\255', '\0'..'\31': add result, "\\" & reprInt(ord(x)) - else: add result, x - add result, "\'" - -proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} = - if e <% typ.node.len: # BUGFIX - result = $typ.node.sons[e].name - else: - result = $e & " (invalid data!)" - -type - pbyteArray = ptr array[0.. 0xffff, byte] - -proc addSetElem(result: var string, elem: int, typ: PNimType) = - case typ.kind - of tyEnum: add result, reprEnum(elem, typ) - of tyBool: add result, reprBool(bool(elem)) - of tyChar: add result, reprChar(chr(elem)) - of tyRange: addSetElem(result, elem, typ.base) - of tyInt..tyInt64: add result, reprInt(elem) - else: # data corrupt --> inform the user - add result, " (invalid data!)" - -proc reprSetAux(result: var string, p: pointer, typ: PNimType) = - # "typ.slots.len" field is for sets the "first" field - var elemCounter = 0 # we need this flag for adding the comma at - # the right places - add result, "{" - var u: int64 - case typ.size - of 1: u = ze64(cast[ptr int8](p)[]) - of 2: u = ze64(cast[ptr int16](p)[]) - of 4: u = ze64(cast[ptr int32](p)[]) - of 8: u = cast[ptr int64](p)[] - else: - var a = cast[pbyteArray](p) - for i in 0 .. typ.size*8-1: - if (ze(a[i div 8]) and (1 shl (i mod 8))) != 0: - if elemCounter > 0: add result, ", " - addSetElem(result, i+typ.node.len, typ.base) - inc(elemCounter) - if typ.size <= 8: - for i in 0..sizeof(int64)*8-1: - if (u and (1 shl i)) != 0: - if elemCounter > 0: add result, ", " - addSetElem(result, i+typ.node.len, typ.base) - inc(elemCounter) - add result, "}" - -proc reprSet(p: pointer, typ: PNimType): string {.compilerRtl.} = - result = "" - reprSetAux(result, p, typ) - -type - TReprClosure {.final.} = object # we cannot use a global variable here - # as this wouldn't be thread-safe - marked: TCellSet - recdepth: int # do not recurse endless - indent: int # indentation - -when not defined(useNimRtl): - proc initReprClosure(cl: var TReprClosure) = - Init(cl.marked) - cl.recdepth = -1 # default is to display everything! - cl.indent = 0 - - proc deinitReprClosure(cl: var TReprClosure) = - Deinit(cl.marked) - - proc reprBreak(result: var string, cl: TReprClosure) = - add result, "\n" - for i in 0..cl.indent-1: add result, ' ' - - proc reprAux(result: var string, p: pointer, typ: PNimType, - cl: var TReprClosure) - - proc reprArray(result: var string, p: pointer, typ: PNimType, - cl: var TReprClosure) = - add result, "[" - var bs = typ.base.size - for i in 0..typ.size div bs - 1: - if i > 0: add result, ", " - reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), typ.base, cl) - add result, "]" - - proc reprSequence(result: var string, p: pointer, typ: PNimType, - cl: var TReprClosure) = - if p == nil: - add result, "nil" - return - result.add(reprPointer(p) & "[") - var bs = typ.base.size - for i in 0..cast[PGenericSeq](p).len-1: - if i > 0: add result, ", " - reprAux(result, cast[pointer](cast[TAddress](p) + GenericSeqSize + i*bs), - typ.Base, cl) - add result, "]" - - proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode, - cl: var TReprClosure) = - case n.kind - of nkNone: assert(false) - of nkSlot: - add result, $n.name - add result, " = " - reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl) - of nkList: - for i in 0..n.len-1: - if i > 0: add result, ",\n" - reprRecordAux(result, p, n.sons[i], cl) - of nkCase: - var m = selectBranch(p, n) - reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl) - if m != nil: reprRecordAux(result, p, m, cl) - - proc reprRecord(result: var string, p: pointer, typ: PNimType, - cl: var TReprClosure) = - add result, "[" - reprRecordAux(result, p, typ.node, cl) - add result, "]" - - proc reprRef(result: var string, p: pointer, typ: PNimType, - cl: var TReprClosure) = - # we know that p is not nil here: - when defined(boehmGC) or defined(nogc): - var cell = cast[PCell](p) - else: - var cell = usrToCell(p) - add result, "ref " & reprPointer(p) - if cell notin cl.marked: - # only the address is shown: - incl(cl.marked, cell) - add result, " --> " - reprAux(result, p, typ.base, cl) - - proc reprAux(result: var string, p: pointer, typ: PNimType, - cl: var TReprClosure) = - if cl.recdepth == 0: - add result, "..." - return - dec(cl.recdepth) - case typ.kind - of tySet: reprSetAux(result, p, typ) - of tyArray: reprArray(result, p, typ, cl) - of tyTuple, tyPureObject: reprRecord(result, p, typ, cl) - of tyObject: - var t = cast[ptr PNimType](p)[] - reprRecord(result, p, t, cl) - of tyRef, tyPtr: - assert(p != nil) - if cast[ppointer](p)[] == nil: add result, "nil" - else: reprRef(result, cast[ppointer](p)[], typ, cl) - of tySequence: - reprSequence(result, cast[ppointer](p)[], typ, cl) - of tyInt: add result, $(cast[ptr int](p)[]) - of tyInt8: add result, $int(cast[ptr Int8](p)[]) - of tyInt16: add result, $int(cast[ptr Int16](p)[]) - of tyInt32: add result, $int(cast[ptr Int32](p)[]) - of tyInt64: add result, $(cast[ptr Int64](p)[]) - of tyFloat: add result, $(cast[ptr float](p)[]) - of tyFloat32: add result, $(cast[ptr float32](p)[]) - of tyFloat64: add result, $(cast[ptr float64](p)[]) - of tyEnum: add result, reprEnum(cast[ptr int](p)[], typ) - of tyBool: add result, reprBool(cast[ptr bool](p)[]) - of tyChar: add result, reprChar(cast[ptr char](p)[]) - of tyString: reprStrAux(result, cast[ptr string](p)[]) - of tyCString: reprStrAux(result, $(cast[ptr cstring](p)[])) - of tyRange: reprAux(result, p, typ.base, cl) - of tyProc, tyPointer: - if cast[ppointer](p)[] == nil: add result, "nil" - else: add result, reprPointer(cast[ppointer](p)[]) - else: - add result, "(invalid data!)" - inc(cl.recdepth) - -proc reprOpenArray(p: pointer, length: int, elemtyp: PNimType): string {. - compilerRtl.} = - var - cl: TReprClosure - initReprClosure(cl) - result = "[" - var bs = elemtyp.size - for i in 0..length - 1: - if i > 0: add result, ", " - reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), elemtyp, cl) - add result, "]" - deinitReprClosure(cl) - -when not defined(useNimRtl): - proc reprAny(p: pointer, typ: PNimType): string = - var - cl: TReprClosure - initReprClosure(cl) - result = "" - if typ.kind in {tyObject, tyPureObject, tyTuple, tyArray, tySet}: - reprAux(result, p, typ, cl) - else: - var p = p - reprAux(result, addr(p), typ, cl) - add result, "\n" - deinitReprClosure(cl) - diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index 9fc34a7bd..9de3fde16 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -11,8 +11,6 @@ ## Note that even though ``TAny`` and its operations hide the nasty low level ## details from its clients, it remains inherently unsafe! -# XXX raw pointer needs to be exposed somehow? - include "system/hti.nim" type @@ -42,7 +40,7 @@ type akFloat32 = 37, ## any represents a float32 akFloat64 = 38, ## any represents a float64 akFloat128 = 39, ## any represents a float128 - akPureObject = 40 ## any represents an object has no `type` field + akPureObject = 40 ## any represents an object that has no `type` field TAny* = object {.pure.} ## can represent any nimrod value; NOTE: the wrapped ## value can be modified with its wrapper! This means @@ -63,6 +61,13 @@ const GenericSeqSize = (2 * sizeof(int)) proc genericAssign(dest, src: Pointer, mt: PNimType) {.importc.} +proc genericShallowAssign(dest, src: Pointer, mt: PNimType) {.importc.} +proc incrSeq(seq: PGenSeq, elemSize: int): PGenSeq {.importc, nodecl.} +proc newObj(typ: PNimType, size: int): pointer {.importc, nodecl.} +proc newSeq(typ: PNimType, len: int): pointer {.importc.} +proc objectInit(dest: Pointer, typ: PNimType) {.importc.} + +template `+!!`(a, b: expr): expr = cast[pointer](cast[TAddress](a) + b) proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int = assert(n.kind == nkCase) @@ -95,28 +100,61 @@ proc toAny*[T](x: var T): TAny {.inline.} = result.value = addr(x) result.rawType = cast[PNimType](getTypeInfo(x)) -proc getKind*(x: TAny): TAnyKind {.inline.} = +proc kind*(x: TAny): TAnyKind {.inline.} = ## get the type kind result = TAnyKind(ord(x.rawType.kind)) + +proc baseTypeKind*(x: TAny): TAnyKind {.inline.} = + ## get the base type's kind; akNone is returned if `x` has no base type. + if x.rawType.base != nil: + result = TAnyKind(ord(x.rawType.base.kind)) + +proc baseTypeSize*(x: TAny): int = + ## returns the size of `x`'s basetype. + if x.rawType.base != nil: + result = x.rawType.base.size + +proc invokeNew*(x: TAny) = + ## performs ``new(x)``. `x` needs to represent a ``ref``. + assert x.rawType.kind == tyRef + var z = newObj(x.rawType, x.rawType.base.size) + genericAssign(x.value, addr(z), x.rawType) + +proc invokeNewSeq*(x: TAny, len: int) = + ## performs ``newSeq(x, len)``. `x` needs to represent a ``seq``. + assert x.rawType.kind == tySequence + var z = newSeq(x.rawType, len) + genericShallowAssign(x.value, addr(z), x.rawType) + +proc extendSeq*(x: TAny, elems = 1) = + ## performs ``setLen(x, x.len+elems)``. `x` needs to represent a ``seq``. + assert x.rawType.kind == tySequence + var y = cast[ptr PGenSeq](x.value)[] + var z = incrSeq(y, x.rawType.base.size * elems) + genericShallowAssign(x.value, addr(z), x.rawType) + +proc setObjectRuntimeType*(x: TAny) = + ## this needs to be called to set `x`'s runtime object type field. + assert x.rawType.kind == tyObject + objectInit(x.value, x.rawType) proc skipRange(x: PNimType): PNimType {.inline.} = result = x if result.kind == tyRange: result = result.base -template `+!!`(a, b: expr): expr = cast[pointer](cast[TAddress](a) + b) - proc `[]`*(x: TAny, i: int): TAny = ## accessor for an any `x` that represents an array or a sequence. case x.rawType.kind of tyArray: var bs = x.rawType.base.size - if i >% (x.rawType.size div bs - 1): + if i >=% x.rawType.size div bs: raise newException(EInvalidIndex, "index out of bounds") return newAny(x.value +!! i*bs, x.rawType.base) of tySequence: var s = cast[ppointer](x.value)[] + if s == nil: raise newException(EInvalidValue, "sequence is nil") var bs = x.rawType.base.size - if i >% (cast[PGenSeq](s).len-1): + if i >=% cast[PGenSeq](s).len: raise newException(EInvalidIndex, "index out of bounds") return newAny(s +!! (GenericSeqSize+i*bs), x.rawType.base) else: assert false @@ -126,14 +164,15 @@ proc `[]=`*(x: TAny, i: int, y: TAny) = case x.rawType.kind of tyArray: var bs = x.rawType.base.size - if i >% (x.rawType.size div bs - 1): + if i >=% x.rawType.size div bs: raise newException(EInvalidIndex, "index out of bounds") assert y.rawType == x.rawType.base genericAssign(x.value +!! i*bs, y.value, y.rawType) of tySequence: var s = cast[ppointer](x.value)[] + if s == nil: raise newException(EInvalidValue, "sequence is nil") var bs = x.rawType.base.size - if i >% (cast[PGenSeq](s).len-1): + if i >=% cast[PGenSeq](s).len: raise newException(EInvalidIndex, "index out of bounds") assert y.rawType == x.rawType.base genericAssign(s +!! (GenericSeqSize+i*bs), y.value, y.rawType) @@ -146,6 +185,29 @@ proc len*(x: TAny): int = of tySequence: result = cast[PGenSeq](cast[ppointer](x.value)[]).len else: assert false +proc isNil*(x: TAny): bool = + ## `isNil` for an any `x` that represents a sequence, string, cstring, + ## proc or some pointer type. + assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer, + tySequence, tyProc} + result = isNil(cast[ppointer](x.value)[]) + +proc getPointer*(x: TAny): pointer = + ## retrieve the pointer value out of `x`. ``x`` needs to be of kind + ## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``, + ## ``akPointer``, ``akSequence``. + assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer, + tySequence, tyProc} + result = cast[ppointer](x.value)[] + +proc setPointer*(x: TAny, y: pointer) = + ## sets the pointer value of `x`. ``x`` needs to be of kind + ## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``, + ## ``akPointer``, ``akSequence``. + assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer, + tySequence, tyProc} + cast[ppointer](x.value)[] = y + proc fieldsAux(p: pointer, n: ptr TNimNode, ret: var seq[tuple[name: cstring, any: TAny]]) = case n.kind @@ -173,6 +235,64 @@ iterator fields*(x: TAny): tuple[name: string, any: TAny] = for name, any in items(ret): yield ($name, any) +proc cmpIgnoreStyle(a, b: cstring): int {.noSideEffect.} = + proc toLower(c: char): char {.inline.} = + if c in {'A'..'Z'}: result = chr(ord(c) + (ord('a') - ord('A'))) + else: result = c + var i = 0 + var j = 0 + while True: + while a[i] == '_': inc(i) + while b[j] == '_': inc(j) # BUGFIX: typo + var aa = toLower(a[i]) + var bb = toLower(b[j]) + result = ord(aa) - ord(bb) + if result != 0 or aa == '\0': break + inc(i) + inc(j) + +proc getFieldNode(p: pointer, n: ptr TNimNode, + name: cstring): ptr TNimNode = + case n.kind + of nkNone: assert(false) + of nkSlot: + if cmpIgnoreStyle(n.name, name) == 0: + result = n + of nkList: + for i in 0..n.len-1: + result = getFieldNode(p, n.sons[i], name) + if result != nil: break + of nkCase: + if cmpIgnoreStyle(n.name, name) == 0: + result = n + else: + var m = selectBranch(p, n) + if m != nil: result = getFieldNode(p, m, name) + +proc `[]=`*(x: TAny, fieldName: string, value: TAny) = + ## sets a field of `x`; `x` represents an object or a tuple. + var t = x.rawType + if x.rawType.kind == tyObject: t = cast[ptr PNimType](x.value)[] + assert x.rawType.kind in {tyTuple, tyPureObject, tyObject} + var n = getFieldNode(x.value, t.node, fieldname) + if n != nil: + assert n.typ == value.rawType + genericAssign(x.value +!! n.offset, value.value, value.rawType) + else: + raise newException(EInvalidValue, "invalid field name: " & fieldName) + +proc `[]`*(x: TAny, fieldName: string): TAny = + ## gets a field of `x`; `x` represents an object or a tuple. + var t = x.rawType + if x.rawType.kind == tyObject: t = cast[ptr PNimType](x.value)[] + assert x.rawType.kind in {tyTuple, tyPureObject, tyObject} + var n = getFieldNode(x.value, t.node, fieldname) + if n != nil: + result.value = x.value +!! n.offset + result.rawType = n.typ + else: + raise newException(EInvalidValue, "invalid field name: " & fieldName) + proc `[]`*(x: TAny): TAny = ## dereference operation for the any `x` that represents a ptr or a ref. assert x.rawtype.kind in {tyRef, tyPtr} @@ -232,6 +352,27 @@ proc getBiggestInt*(x: TAny): biggestInt = else: assert false else: assert false +proc setBiggestInt*(x: TAny, y: biggestInt) = + ## sets the integer value of `x`. `x` needs to represent + ## some integer, a bool, a char or an enum. + var t = skipRange(x.rawtype) + case t.kind + of tyInt: cast[ptr int](x.value)[] = int(y) + of tyInt8: cast[ptr int8](x.value)[] = int8(y) + of tyInt16: cast[ptr int16](x.value)[] = int16(y) + of tyInt32: cast[ptr int32](x.value)[] = int32(y) + of tyInt64: cast[ptr int64](x.value)[] = int64(y) + of tyBool: cast[ptr bool](x.value)[] = y != 0 + of tyChar: cast[ptr char](x.value)[] = chr(y.int) + of tyEnum: + case t.size + of 1: cast[ptr int8](x.value)[] = toU8(y.int) + of 2: cast[ptr int16](x.value)[] = toU16(y.int) + of 4: cast[ptr int32](x.value)[] = int32(y) + of 8: cast[ptr int64](x.value)[] = y + else: assert false + else: assert false + proc getChar*(x: TAny): char = ## retrieve the char value out of `x`. `x` needs to represent a char. var t = skipRange(x.rawtype) @@ -244,11 +385,35 @@ proc getBool*(x: TAny): bool = assert t.kind == tyBool result = cast[ptr bool](x.value)[] -proc getEnumField*(x: TAny): string = - ## gets the enum field name as a string. `x` needs to represent an enum. +proc skipRange*(x: TAny): TAny = + ## skips the range information of `x`. + assert x.rawType.kind == tyRange + result.rawType = x.rawType.base + result.value = x.value + +proc getEnumOrdinal*(x: TAny, name: string): int = + ## gets the enum field ordinal from `name`. `x` needs to represent an enum + ## but is only used to access the type information. In case of an error + ## ``low(int)`` is returned. var typ = skipRange(x.rawtype) assert typ.kind == tyEnum - var e = int(getBiggestInt(x)) + var n = typ.node + var s = n.sons + for i in 0 .. n.len-1: + if cmpIgnoreStyle($s[i].name, name) == 0: + if ntfEnumHole notin typ.flags: + return i + else: + return s[i].offset + result = low(int) + +proc getEnumField*(x: TAny, ordinalValue: int): string = + ## gets the enum field name as a string. `x` needs to represent an enum + ## but is only used to access the type information. The field name of + ## `ordinalValue` is returned. + var typ = skipRange(x.rawtype) + assert typ.kind == tyEnum + var e = ordinalValue if ntfEnumHole notin typ.flags: if e <% typ.node.len: return $typ.node.sons[e].name @@ -258,7 +423,11 @@ proc getEnumField*(x: TAny): string = var s = n.sons for i in 0 .. n.len-1: if s[i].offset == e: return $s[i].name - result = $e & " (invalid data!)" + result = $e + +proc getEnumField*(x: TAny): string = + ## gets the enum field name as a string. `x` needs to represent an enum. + result = getEnumField(x, getBiggestInt(x).int) proc getFloat*(x: TAny): float = ## retrieve the float value out of `x`. `x` needs to represent an float. @@ -284,11 +453,30 @@ proc getBiggestFloat*(x: TAny): biggestFloat = of tyFloat64: result = biggestFloat(cast[ptr Float64](x.value)[]) else: assert false +proc setBiggestFloat*(x: TAny, y: biggestFloat) = + ## sets the float value of `x`. `x` needs to represent + ## some float. + case skipRange(x.rawtype).kind + of tyFloat: cast[ptr Float](x.value)[] = y + of tyFloat32: cast[ptr Float32](x.value)[] = y + of tyFloat64: cast[ptr Float64](x.value)[] = y + else: assert false + proc getString*(x: TAny): string = ## retrieve the string value out of `x`. `x` needs to represent a string. assert x.rawtype.kind == tyString result = cast[ptr string](x.value)[] +proc setString*(x: TAny, y: string) = + ## sets the string value of `x`. `x` needs to represent a string. + assert x.rawtype.kind == tyString + cast[ptr string](x.value)[] = y + +proc getCString*(x: TAny): cstring = + ## retrieve the cstring value out of `x`. `x` needs to represent a cstring. + assert x.rawtype.kind == tyCString + result = cast[ptr cstring](x.value)[] + proc assign*(x, y: TAny) = ## copies the value of `y` to `x`. The assignment operator for ``TAny`` ## does NOT do this; it performs a shallow copy instead! @@ -339,7 +527,7 @@ proc inclSetElement*(x: TAny, elem: int) = a[] = a[] or (1'i64 shl e) else: var a = cast[pbyteArray](p) - a[e div 8] = toU8(a[e div 8] or (1 shl (e mod 8))) + a[e shr 3] = toU8(a[e shr 3] or (1 shl (e and 7))) when isMainModule: type @@ -365,8 +553,8 @@ when isMainModule: var i = 0 for n, a in fields(x2): case i - of 0: assert n == "name" and $a.getKind == "akString" - of 1: assert n == "s" and $a.getKind == "akInt" + of 0: assert n == "name" and $a.kind == "akString" + of 1: assert n == "s" and $a.kind == "akInt" else: assert false inc i @@ -377,9 +565,9 @@ when isMainModule: i = 0 for n, a in fields(x3): case i - of 0: assert n == "test" and $a.getKind == "akInt" - of 1: assert n == "asd" and $a.getKind == "akInt" - of 2: assert n == "test2" and $a.getKind == "akEnum" + of 0: assert n == "test" and $a.kind == "akInt" + of 1: assert n == "asd" and $a.kind == "akInt" + of 2: assert n == "test2" and $a.kind == "akEnum" else: assert false inc i @@ -387,4 +575,17 @@ when isMainModule: new(test4) test4[] = "test" var x4 = toAny(test4) - assert($x4[].getKind() == "akString") + assert($x4[].kind() == "akString") + + block: + # gimme a new scope dammit + var myarr: array[0..4, array[0..4, string]] = [ + ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], + ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], + ["test", "1", "2", "3", "4"]] + var m = toAny(myArr) + for i in 0 .. m.len-1: + for j in 0 .. m[i].len-1: + echo getString(m[i][j]) + + |