mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-26 09:14:00 +00:00
code gen bugfixes; marshal.nim implemented
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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])
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user