Implementing repr for JS (#5578)
This commit is contained in:
parent
2f9a698e87
commit
2946c7a4b9
3 changed files with 728 additions and 18 deletions
|
|
@ -1626,22 +1626,56 @@ proc genToArray(p: PProc; n: PNode; r: var TCompRes) =
|
||||||
localError(x.info, "'toArray' needs an array literal")
|
localError(x.info, "'toArray' needs an array literal")
|
||||||
r.res.add(")")
|
r.res.add(")")
|
||||||
|
|
||||||
|
proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = nil) =
|
||||||
|
useMagic(p, magic)
|
||||||
|
add(r.res, magic & "(")
|
||||||
|
var a: TCompRes
|
||||||
|
|
||||||
|
gen(p, n.sons[1], a)
|
||||||
|
if magic == "reprAny":
|
||||||
|
# the pointer argument in reprAny is expandend to
|
||||||
|
# (pointedto, pointer), so we need to fill it
|
||||||
|
if a.address.isNil:
|
||||||
|
add(r.res, a.res)
|
||||||
|
add(r.res, ", null")
|
||||||
|
else:
|
||||||
|
add(r.res, "$1, $2" % [a.address, a.res])
|
||||||
|
else:
|
||||||
|
add(r.res, a.res)
|
||||||
|
|
||||||
|
if not typ.isNil:
|
||||||
|
add(r.res, ", ")
|
||||||
|
add(r.res, typ)
|
||||||
|
add(r.res, ")")
|
||||||
|
|
||||||
proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
|
proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
if p.target == targetPHP:
|
if p.target == targetPHP:
|
||||||
localError(n.info, "'repr' not available for PHP backend")
|
localError(n.info, "'repr' not available for PHP backend")
|
||||||
return
|
return
|
||||||
let t = skipTypes(n.sons[1].typ, abstractVarRange)
|
let t = skipTypes(n.sons[1].typ, abstractVarRange)
|
||||||
case t.kind
|
case t.kind:
|
||||||
of tyInt..tyUInt64:
|
of tyInt..tyInt64, tyUInt..tyUInt64:
|
||||||
unaryExpr(p, n, r, "", "(\"\"+ ($1))")
|
genReprAux(p, n, r, "reprInt")
|
||||||
|
of tyChar:
|
||||||
|
genReprAux(p, n, r, "reprChar")
|
||||||
|
of tyBool:
|
||||||
|
genReprAux(p, n, r, "reprBool")
|
||||||
|
of tyFloat..tyFloat128:
|
||||||
|
genReprAux(p, n, r, "reprFloat")
|
||||||
|
of tyString:
|
||||||
|
genReprAux(p, n, r, "reprStr")
|
||||||
of tyEnum, tyOrdinal:
|
of tyEnum, tyOrdinal:
|
||||||
gen(p, n.sons[1], r)
|
genReprAux(p, n, r, "reprEnum", genTypeInfo(p, t))
|
||||||
useMagic(p, "cstrToNimstr")
|
of tySet:
|
||||||
r.kind = resExpr
|
genReprAux(p, n, r, "reprSet", genTypeInfo(p, t))
|
||||||
r.res = "cstrToNimstr($1.node.sons[$2].name)" % [genTypeInfo(p, t), r.res]
|
of tyEmpty, tyVoid:
|
||||||
|
localError(n.info, "'repr' doesn't support 'void' type")
|
||||||
|
of tyPointer:
|
||||||
|
genReprAux(p, n, r, "reprPointer")
|
||||||
|
of tyOpenArray, tyVarargs:
|
||||||
|
genReprAux(p, n, r, "reprJSONStringify")
|
||||||
else:
|
else:
|
||||||
# XXX:
|
genReprAux(p, n, r, "reprAny", genTypeInfo(p, t))
|
||||||
internalError(n.info, "genRepr: Not implemented")
|
|
||||||
|
|
||||||
proc genOf(p: PProc, n: PNode, r: var TCompRes) =
|
proc genOf(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
var x: TCompRes
|
var x: TCompRes
|
||||||
|
|
|
||||||
|
|
@ -6,18 +6,272 @@
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
# The generic ``repr`` procedure for the javascript backend.
|
||||||
|
|
||||||
proc reprInt(x: int64): string {.compilerproc.} = return $x
|
proc reprInt(x: int64): string {.compilerproc.} = return $x
|
||||||
|
proc reprFloat(x: float): string {.compilerproc.} =
|
||||||
|
# Js toString doesn't differentiate between 1.0 and 1,
|
||||||
|
# but we do.
|
||||||
|
if $x == $(x.int): $x & ".0"
|
||||||
|
else: $x
|
||||||
|
|
||||||
|
proc reprPointer(p: pointer): string {.compilerproc.} =
|
||||||
|
# Do we need to generate the full 8bytes ? In js a pointer is an int anyway
|
||||||
|
var tmp: int
|
||||||
|
{. emit: """
|
||||||
|
if (`p`_Idx == null) {
|
||||||
|
`tmp` = 0;
|
||||||
|
} else {
|
||||||
|
`tmp` = `p`_Idx;
|
||||||
|
}
|
||||||
|
""" .}
|
||||||
|
result = $tmp
|
||||||
|
|
||||||
|
proc reprBool(x: bool): string {.compilerRtl.} =
|
||||||
|
if x: result = "true"
|
||||||
|
else: result = "false"
|
||||||
|
|
||||||
|
proc isUndefined[T](x: T): bool {.inline.} = {.emit: "`result` = `x` === undefined;"}
|
||||||
|
|
||||||
proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
|
proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
|
||||||
if ntfEnumHole notin typ.flags:
|
if not typ.node.sons[e].isUndefined:
|
||||||
if e <% typ.node.len:
|
result = $typ.node.sons[e].name
|
||||||
return $typ.node.sons[e].name
|
|
||||||
else:
|
else:
|
||||||
# ugh we need a slow linear search:
|
|
||||||
var n = typ.node
|
|
||||||
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 & " (invalid data!)"
|
||||||
|
|
||||||
|
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 reprStrAux(result: var string, s: cstring, len: int) =
|
||||||
|
add(result, "\"")
|
||||||
|
for i in 0 .. <len:
|
||||||
|
let c = s[i]
|
||||||
|
case c
|
||||||
|
of '"': add(result, "\\\"")
|
||||||
|
of '\\': add(result, "\\\\")
|
||||||
|
of '\10': add(result, "\\10\"\n\"")
|
||||||
|
of '\128'..'\255', '\0'..'\9', '\11'..'\31':
|
||||||
|
add( result, "\\" & reprInt(ord(c)) )
|
||||||
|
else:
|
||||||
|
add( result, reprInt(ord(c)) ) # Not sure about this.
|
||||||
|
add(result, "\"")
|
||||||
|
|
||||||
|
proc reprStr(s: string): string {.compilerRtl.} =
|
||||||
|
result = ""
|
||||||
|
if cast[pointer](s).isNil:
|
||||||
|
# Handle nil strings here because they don't have a length field in js
|
||||||
|
# TODO: check for null/undefined before generating call to length in js?
|
||||||
|
# Also: c backend repr of a nil string is <pointer>"", but repr of an
|
||||||
|
# array of string that is not initialized is [nil, nil, ...] ??
|
||||||
|
add(result, "nil")
|
||||||
|
else:
|
||||||
|
reprStrAux(result, s, s.len)
|
||||||
|
|
||||||
|
proc addSetElem(result: var string, elem: int, typ: PNimType) =
|
||||||
|
# Dispatch each set element to the correct repr<Type> proc
|
||||||
|
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) # Note the base to advance towards the element type
|
||||||
|
of tyInt..tyInt64, tyUInt8, tyUInt16: add result, reprInt(elem)
|
||||||
|
else: # data corrupt --> inform the user
|
||||||
|
add(result, " (invalid data!)")
|
||||||
|
|
||||||
|
iterator setKeys(s: int): int {.inline.} =
|
||||||
|
# The type of s is a lie, but it's expected to be a set.
|
||||||
|
# Iterate over the JS object representing a set
|
||||||
|
# and returns the keys as int.
|
||||||
|
var len: int
|
||||||
|
var yieldRes: int
|
||||||
|
var i: int = 0
|
||||||
|
{. emit: """
|
||||||
|
var setObjKeys = Object.getOwnPropertyNames(`s`);
|
||||||
|
`len` = setObjKeys.length;
|
||||||
|
""" .}
|
||||||
|
while i < len:
|
||||||
|
{. emit: "`yieldRes` = parseInt(setObjKeys[`i`],10);\n" .}
|
||||||
|
yield yieldRes
|
||||||
|
inc i
|
||||||
|
|
||||||
|
proc reprSetAux(result: var string, s: int, typ: PNimType) =
|
||||||
|
add(result, "{")
|
||||||
|
var first: bool = true
|
||||||
|
for el in setKeys(s):
|
||||||
|
if first:
|
||||||
|
first = false
|
||||||
|
else:
|
||||||
|
add(result, ", ")
|
||||||
|
addSetElem(result, el, typ.base)
|
||||||
|
add(result, "}")
|
||||||
|
|
||||||
|
proc reprSet(e: int, typ: PNimType): string {.compilerRtl.} =
|
||||||
|
result = ""
|
||||||
|
reprSetAux(result, e, typ)
|
||||||
|
|
||||||
|
type
|
||||||
|
ReprClosure {.final.} = object
|
||||||
|
recDepth: int # do not recurse endlessly
|
||||||
|
indent: int # indentation
|
||||||
|
|
||||||
|
proc initReprClosure(cl: var ReprClosure) =
|
||||||
|
cl.recDepth = -1 # default is to display everything!
|
||||||
|
cl.indent = 0
|
||||||
|
|
||||||
|
proc reprAux(result: var string, p: pointer, typ: PNimType, cl: var ReprClosure)
|
||||||
|
|
||||||
|
proc reprArray(a: pointer, typ: PNimType,
|
||||||
|
cl: var ReprClosure): string {.compilerRtl.} =
|
||||||
|
var isNilArrayOrSeq: bool
|
||||||
|
# isnil is not enough here as it would try to deref `a` without knowing what's inside
|
||||||
|
{. emit: """
|
||||||
|
if (`a` == null) {
|
||||||
|
`isNilArrayOrSeq` = true;
|
||||||
|
} else if (`a`[0] == null) {
|
||||||
|
`isNilArrayOrSeq` = true;
|
||||||
|
} else {
|
||||||
|
`isNilArrayOrSeq` = false;
|
||||||
|
};
|
||||||
|
""" .}
|
||||||
|
if typ.kind == tySequence and isNilArrayOrSeq:
|
||||||
|
return "nil"
|
||||||
|
|
||||||
|
# We prepend @ to seq, the C backend prepends the pointer to the seq.
|
||||||
|
result = if typ.kind == tySequence: "@[" else: "["
|
||||||
|
var len: int = 0
|
||||||
|
var i: int = 0
|
||||||
|
|
||||||
|
{. emit: "`len` = `a`.length;\n" .}
|
||||||
|
var dereffed: pointer = a
|
||||||
|
for i in 0 .. < len:
|
||||||
|
if i > 0 :
|
||||||
|
add(result, ", ")
|
||||||
|
# advance pointer and point to element at index
|
||||||
|
{. emit: """
|
||||||
|
`dereffed`_Idx = `i`;
|
||||||
|
`dereffed` = `a`[`dereffed`_Idx];
|
||||||
|
""" .}
|
||||||
|
reprAux(result, dereffed, typ.base, cl)
|
||||||
|
|
||||||
|
add(result, "]")
|
||||||
|
|
||||||
|
proc isPointedToNil(p: pointer): bool {.inline.}=
|
||||||
|
{. emit: "if (`p` === null) {`result` = true};\n" .}
|
||||||
|
|
||||||
|
proc reprRef(result: var string, p: pointer, typ: PNimType,
|
||||||
|
cl: var ReprClosure) =
|
||||||
|
if p.isPointedToNil:
|
||||||
|
add(result , "nil")
|
||||||
|
return
|
||||||
|
add( result, "ref " & reprPointer(p) )
|
||||||
|
add(result, " --> ")
|
||||||
|
if typ.base.kind != tyArray:
|
||||||
|
{. emit: """
|
||||||
|
if (`p` != null && `p`.length > 0) {
|
||||||
|
`p` = `p`[`p`_Idx];
|
||||||
|
}
|
||||||
|
""" .}
|
||||||
|
reprAux(result, p, typ.base, cl)
|
||||||
|
|
||||||
|
proc reprRecordAux(result: var string, o: pointer, typ: PNimType, cl: var ReprClosure) =
|
||||||
|
add(result, "[")
|
||||||
|
|
||||||
|
var first: bool = true
|
||||||
|
var val: pointer = o
|
||||||
|
if typ.node.len == 0:
|
||||||
|
# if the object has only one field, len is 0 and sons is nil, the field is in node
|
||||||
|
let key: cstring = typ.node.name
|
||||||
|
add(result, $key & " = ")
|
||||||
|
{. emit: "`val` = `o`[`key`];\n" .}
|
||||||
|
reprAux(result, val, typ.node.typ, cl)
|
||||||
|
else:
|
||||||
|
# if the object has more than one field, sons is not nil and contains the fields.
|
||||||
|
for i in 0 .. <typ.node.len:
|
||||||
|
if first: first = false
|
||||||
|
else: add(result, ",\n")
|
||||||
|
|
||||||
|
let key: cstring = typ.node.sons[i].name
|
||||||
|
add(result, $key & " = ")
|
||||||
|
{. emit: "`val` = `o`[`key`];\n" .} # access the field by name
|
||||||
|
reprAux(result, val, typ.node.sons[i].typ, cl)
|
||||||
|
add(result, "]")
|
||||||
|
|
||||||
|
proc reprRecord(o: pointer, typ: PNimType, cl: var ReprClosure): string {.compilerRtl.} =
|
||||||
|
result = ""
|
||||||
|
reprRecordAux(result, o, typ,cl)
|
||||||
|
|
||||||
|
|
||||||
|
proc reprJSONStringify(p: int): string {.compilerRtl.} =
|
||||||
|
# As a last resort, use stringify
|
||||||
|
# We use this for tyOpenArray, tyVarargs while genTypeInfo is not implemented
|
||||||
|
var tmp: cstring
|
||||||
|
{. emit: "`tmp` = JSON.stringify(`p`);\n" .}
|
||||||
|
result = $tmp
|
||||||
|
|
||||||
|
proc reprAux(result: var string, p: pointer, typ: PNimType,
|
||||||
|
cl: var ReprClosure) =
|
||||||
|
if cl.recDepth == 0:
|
||||||
|
add(result, "...")
|
||||||
|
return
|
||||||
|
dec(cl.recDepth)
|
||||||
|
case typ.kind
|
||||||
|
of tyInt..tyInt64, tyUInt..tyUInt64:
|
||||||
|
add( result, reprInt(cast[int](p)) )
|
||||||
|
of tyChar:
|
||||||
|
add( result, reprChar(cast[char](p)) )
|
||||||
|
of tyBool:
|
||||||
|
add( result, reprBool(cast[bool](p)) )
|
||||||
|
of tyFloat..tyFloat128:
|
||||||
|
add( result, reprFloat(cast[float](p)) )
|
||||||
|
of tyString:
|
||||||
|
var fp: int
|
||||||
|
{. emit: "`fp` = `p`;\n" .}
|
||||||
|
if cast[string](fp).isNil:
|
||||||
|
add(result, "nil")
|
||||||
|
else:
|
||||||
|
add( result, reprStr(cast[string](p)) )
|
||||||
|
of tyCString:
|
||||||
|
var fp: cstring
|
||||||
|
{. emit: "`fp` = `p`;\n" .}
|
||||||
|
if fp.isNil:
|
||||||
|
add(result, "nil")
|
||||||
|
else:
|
||||||
|
reprStrAux(result, fp, fp.len)
|
||||||
|
of tyEnum, tyOrdinal:
|
||||||
|
var fp: int
|
||||||
|
{. emit: "`fp` = `p`;\n" .}
|
||||||
|
add(result, reprEnum(fp, typ))
|
||||||
|
of tySet:
|
||||||
|
var fp: int
|
||||||
|
{. emit: "`fp` = `p`;\n" .}
|
||||||
|
add(result, reprSet(fp, typ))
|
||||||
|
of tyRange: reprAux(result, p, typ.base, cl)
|
||||||
|
of tyObject, tyTuple:
|
||||||
|
add(result, reprRecord(p, typ, cl))
|
||||||
|
of tyArray, tyArrayConstr, tySequence:
|
||||||
|
add(result, reprArray(p, typ, cl))
|
||||||
|
of tyPointer:
|
||||||
|
add(result, reprPointer(p))
|
||||||
|
of tyPtr, tyRef:
|
||||||
|
reprRef(result, p, typ, cl)
|
||||||
|
of tyProc:
|
||||||
|
if p.isPointedToNil:
|
||||||
|
add(result, "nil")
|
||||||
|
else:
|
||||||
|
add(result, reprPointer(p))
|
||||||
|
else:
|
||||||
|
add( result, "(invalid data!)" & reprJsonStringify(cast[int](p)) )
|
||||||
|
inc(cl.recDepth)
|
||||||
|
|
||||||
|
proc reprAny(p: pointer, typ: PNimType): string {.compilerRtl.} =
|
||||||
|
var cl: ReprClosure
|
||||||
|
initReprClosure(cl)
|
||||||
|
result = ""
|
||||||
|
reprAux(result, p, typ, cl)
|
||||||
|
add(result, "\n")
|
||||||
422
tests/js/trepr.nim
Normal file
422
tests/js/trepr.nim
Normal file
|
|
@ -0,0 +1,422 @@
|
||||||
|
discard """
|
||||||
|
action: run
|
||||||
|
"""
|
||||||
|
|
||||||
|
block ints:
|
||||||
|
let
|
||||||
|
na: int8 = -120'i8
|
||||||
|
nb: int16 = -32700'i16
|
||||||
|
nc: int32 = -2147483000'i32
|
||||||
|
nd: int64 = -9223372036854775000'i64
|
||||||
|
ne: int = -1234567
|
||||||
|
pa: int8 = 120'i8
|
||||||
|
pb: int16 = 32700'i16
|
||||||
|
pc: int32 = 2147483000'i32
|
||||||
|
pd: int64 = 9223372036854775000'i64
|
||||||
|
pe: int = 1234567
|
||||||
|
|
||||||
|
doAssert(repr(na) == "-120")
|
||||||
|
doAssert(repr(nb) == "-32700")
|
||||||
|
doAssert(repr(nc) == "-2147483000")
|
||||||
|
doAssert(repr(nd) == "-9223372036854775000")
|
||||||
|
doAssert(repr(ne) == "-1234567")
|
||||||
|
doAssert(repr(pa) == "120")
|
||||||
|
doAssert(repr(pb) == "32700")
|
||||||
|
doAssert(repr(pc) == "2147483000")
|
||||||
|
doAssert(repr(pd) == "9223372036854775000")
|
||||||
|
doAssert(repr(pe) == "1234567")
|
||||||
|
|
||||||
|
block uints:
|
||||||
|
let
|
||||||
|
a: uint8 = 254'u8
|
||||||
|
b: uint16 = 65300'u16
|
||||||
|
c: uint32 = 4294967290'u32
|
||||||
|
# d: uint64 = 18446744073709551610'u64 -> unknown node type
|
||||||
|
e: uint = 1234567
|
||||||
|
|
||||||
|
doAssert(repr(a) == "254")
|
||||||
|
doAssert(repr(b) == "65300")
|
||||||
|
doAssert(repr(c) == "4294967290")
|
||||||
|
# doAssert(repr(d) == "18446744073709551610")
|
||||||
|
doAssert(repr(e) == "1234567")
|
||||||
|
|
||||||
|
block floats:
|
||||||
|
let
|
||||||
|
a: float32 = 3.4e38'f32
|
||||||
|
b: float64 = 1.7976931348623157e308'f64
|
||||||
|
c: float = 1234.567e89
|
||||||
|
|
||||||
|
when defined js:
|
||||||
|
doAssert(repr(a) == "3.4e+38") # in C: 3.399999952144364e+038
|
||||||
|
doAssert(repr(b) == "1.7976931348623157e+308") # in C: 1.797693134862316e+308
|
||||||
|
doAssert(repr(c) == "1.234567e+92") # in C: 1.234567e+092
|
||||||
|
|
||||||
|
block bools:
|
||||||
|
let
|
||||||
|
a: bool = true
|
||||||
|
b: bool = false
|
||||||
|
|
||||||
|
doAssert(repr(a) == "true")
|
||||||
|
doAssert(repr(b) == "false")
|
||||||
|
|
||||||
|
block enums:
|
||||||
|
type
|
||||||
|
AnEnum = enum
|
||||||
|
aeA
|
||||||
|
aeB
|
||||||
|
aeC
|
||||||
|
HoledEnum = enum
|
||||||
|
heA = -12
|
||||||
|
heB = 15
|
||||||
|
heC = 123
|
||||||
|
|
||||||
|
doAssert(repr(aeA) == "aeA")
|
||||||
|
doAssert(repr(aeB) == "aeB")
|
||||||
|
doAssert(repr(aeC) == "aeC")
|
||||||
|
doAssert(repr(heA) == "heA")
|
||||||
|
doAssert(repr(heB) == "heB")
|
||||||
|
doAssert(repr(heC) == "heC")
|
||||||
|
|
||||||
|
block chars:
|
||||||
|
let
|
||||||
|
a = 'a'
|
||||||
|
b = 'z'
|
||||||
|
one = '1'
|
||||||
|
nl = '\x0A'
|
||||||
|
|
||||||
|
doAssert(repr(a) == "'a'")
|
||||||
|
doAssert(repr(b) == "'z'")
|
||||||
|
doAssert(repr(one) == "'1'")
|
||||||
|
doAssert(repr(nl) == "'\\10'")
|
||||||
|
|
||||||
|
block strings:
|
||||||
|
let
|
||||||
|
a: string = "12345"
|
||||||
|
b: string = "hello,repr"
|
||||||
|
c: string = "hi\nthere"
|
||||||
|
when defined js: # C prepends the pointer, JS does not.
|
||||||
|
doAssert(repr(a) == "\"12345\"")
|
||||||
|
doAssert(repr(b) == "\"hello,repr\"")
|
||||||
|
doAssert(repr(c) == "\"hi\nthere\"")
|
||||||
|
|
||||||
|
block sets:
|
||||||
|
let
|
||||||
|
a: set[int16] = {1'i16, 2'i16, 3'i16}
|
||||||
|
b: set[char] = {'A', 'k'}
|
||||||
|
|
||||||
|
doAssert(repr(a) == "{1, 2, 3}")
|
||||||
|
doAssert(repr(b) == "{'A', 'k'}")
|
||||||
|
|
||||||
|
block ranges:
|
||||||
|
let
|
||||||
|
a: range[0..12] = 6
|
||||||
|
b: range[-12..0] = -6
|
||||||
|
doAssert(repr(a) == "6")
|
||||||
|
doAssert(repr(b) == "-6")
|
||||||
|
|
||||||
|
block tuples:
|
||||||
|
type
|
||||||
|
ATuple = tuple
|
||||||
|
a: int
|
||||||
|
b: float
|
||||||
|
c: string
|
||||||
|
d: OtherTuple
|
||||||
|
OtherTuple = tuple
|
||||||
|
a: bool
|
||||||
|
b: int8
|
||||||
|
|
||||||
|
let
|
||||||
|
ot: OtherTuple = (a: true, b: 120'i8)
|
||||||
|
t: ATuple = (a: 42, b: 12.34, c: "tuple", d: ot)
|
||||||
|
when defined js:
|
||||||
|
doAssert(repr(ot) == """
|
||||||
|
[Field0 = true,
|
||||||
|
Field1 = 120]
|
||||||
|
""")
|
||||||
|
doAssert(repr(t) == """
|
||||||
|
[Field0 = 42,
|
||||||
|
Field1 = 12.34,
|
||||||
|
Field2 = "tuple",
|
||||||
|
Field3 = [Field0 = true,
|
||||||
|
Field1 = 120]]
|
||||||
|
""")
|
||||||
|
|
||||||
|
block objects:
|
||||||
|
type
|
||||||
|
AnObj = object
|
||||||
|
a: int
|
||||||
|
b: float
|
||||||
|
c: OtherObj
|
||||||
|
OtherObj = object
|
||||||
|
a: bool
|
||||||
|
b: int8
|
||||||
|
let
|
||||||
|
oo: OtherObj = OtherObj(a: true, b: 120'i8)
|
||||||
|
o: AnObj = AnObj(a: 42, b: 12.34, c: oo)
|
||||||
|
|
||||||
|
doAssert(repr(oo) == """
|
||||||
|
[a = true,
|
||||||
|
b = 120]
|
||||||
|
""")
|
||||||
|
doAssert(repr(o) == """
|
||||||
|
[a = 42,
|
||||||
|
b = 12.34,
|
||||||
|
c = [a = true,
|
||||||
|
b = 120]]
|
||||||
|
""")
|
||||||
|
|
||||||
|
block arrays:
|
||||||
|
type
|
||||||
|
AObj = object
|
||||||
|
x: int
|
||||||
|
y: array[3,float]
|
||||||
|
let
|
||||||
|
a = [0.0, 1, 2]
|
||||||
|
b = [a, a, a]
|
||||||
|
o = AObj(x: 42, y: a)
|
||||||
|
c = [o, o, o]
|
||||||
|
d = ["hi", "array", "!"]
|
||||||
|
|
||||||
|
doAssert(repr(a) == "[0.0, 1.0, 2.0]\n")
|
||||||
|
doAssert(repr(b) == "[[0.0, 1.0, 2.0], [0.0, 1.0, 2.0], [0.0, 1.0, 2.0]]\n")
|
||||||
|
doAssert(repr(c) == """
|
||||||
|
[[x = 42,
|
||||||
|
y = [0.0, 1.0, 2.0]], [x = 42,
|
||||||
|
y = [0.0, 1.0, 2.0]], [x = 42,
|
||||||
|
y = [0.0, 1.0, 2.0]]]
|
||||||
|
""")
|
||||||
|
doAssert(repr(d) == "[\"hi\", \"array\", \"!\"]\n")
|
||||||
|
|
||||||
|
block seqs:
|
||||||
|
type
|
||||||
|
AObj = object
|
||||||
|
x: int
|
||||||
|
y: seq[float]
|
||||||
|
let
|
||||||
|
a = @[0.0, 1, 2]
|
||||||
|
b = @[a, a, a]
|
||||||
|
o = AObj(x: 42, y: a)
|
||||||
|
c = @[o, o, o]
|
||||||
|
d = @["hi", "array", "!"]
|
||||||
|
|
||||||
|
doAssert(repr(a) == "@[0.0, 1.0, 2.0]\n")
|
||||||
|
doAssert(repr(b) == "@[@[0.0, 1.0, 2.0], @[0.0, 1.0, 2.0], @[0.0, 1.0, 2.0]]\n")
|
||||||
|
doAssert(repr(c) == """
|
||||||
|
@[[x = 42,
|
||||||
|
y = @[0.0, 1.0, 2.0]], [x = 42,
|
||||||
|
y = @[0.0, 1.0, 2.0]], [x = 42,
|
||||||
|
y = @[0.0, 1.0, 2.0]]]
|
||||||
|
""")
|
||||||
|
doAssert(repr(d) == "@[\"hi\", \"array\", \"!\"]\n")
|
||||||
|
|
||||||
|
block ptrs:
|
||||||
|
type
|
||||||
|
AObj = object
|
||||||
|
x: ptr array[2, AObj]
|
||||||
|
y: int
|
||||||
|
var
|
||||||
|
a = [12.0, 13.0, 14.0]
|
||||||
|
b = addr a[0]
|
||||||
|
c = addr a[2]
|
||||||
|
d = AObj()
|
||||||
|
|
||||||
|
doAssert(repr(a) == "[12.0, 13.0, 14.0]\n")
|
||||||
|
doAssert(repr(b) == "ref 0 --> 12.0\n")
|
||||||
|
doAssert(repr(c) == "ref 2 --> 14.0\n")
|
||||||
|
doAssert(repr(d) == """
|
||||||
|
[x = nil,
|
||||||
|
y = 0]
|
||||||
|
""")
|
||||||
|
|
||||||
|
block ptrs:
|
||||||
|
type
|
||||||
|
AObj = object
|
||||||
|
x: ref array[2, AObj]
|
||||||
|
y: int
|
||||||
|
var
|
||||||
|
a = AObj()
|
||||||
|
|
||||||
|
new(a.x)
|
||||||
|
|
||||||
|
doAssert(repr(a) == """
|
||||||
|
[x = ref 0 --> [[x = nil,
|
||||||
|
y = 0], [x = nil,
|
||||||
|
y = 0]],
|
||||||
|
y = 0]
|
||||||
|
""")
|
||||||
|
|
||||||
|
block procs:
|
||||||
|
proc test(): int =
|
||||||
|
echo "hello"
|
||||||
|
var
|
||||||
|
ptest = test
|
||||||
|
nilproc: proc(): int
|
||||||
|
|
||||||
|
doAssert(repr(test) == "0\n")
|
||||||
|
doAssert(repr(ptest) == "0\n")
|
||||||
|
doAssert(repr(nilproc) == "nil\n")
|
||||||
|
|
||||||
|
block bunch:
|
||||||
|
type
|
||||||
|
AnEnum = enum
|
||||||
|
eA, eB, eC
|
||||||
|
B = object
|
||||||
|
a: string
|
||||||
|
b: seq[char]
|
||||||
|
A = object
|
||||||
|
a: uint32
|
||||||
|
b: int
|
||||||
|
c: float
|
||||||
|
d: char
|
||||||
|
e: AnEnum
|
||||||
|
f: string
|
||||||
|
g: set[char]
|
||||||
|
h: set[int16]
|
||||||
|
i: array[3,string]
|
||||||
|
j: seq[string]
|
||||||
|
k: range[-12..12]
|
||||||
|
l: B
|
||||||
|
m: ref B
|
||||||
|
n: ptr B
|
||||||
|
o: tuple[x: B, y: string]
|
||||||
|
p: proc(b: B): ref B
|
||||||
|
q: cstring
|
||||||
|
|
||||||
|
proc refB(b:B):ref B =
|
||||||
|
new result
|
||||||
|
result[] = b
|
||||||
|
|
||||||
|
var
|
||||||
|
aa: A
|
||||||
|
bb: B = B(a: "inner", b: @['o', 'b', 'j'])
|
||||||
|
cc: A = A(a: 12, b: 1, c: 1.2, d: '\0', e: eC,
|
||||||
|
f: "hello", g: {'A'}, h: {2'i16},
|
||||||
|
i: ["hello", "world", "array"],
|
||||||
|
j: @["hello", "world", "seq"], k: -1,
|
||||||
|
l: bb, m: refB(bb), n: addr bb,
|
||||||
|
o: (bb, "tuple!"), p: refB, q: "cstringtest" )
|
||||||
|
|
||||||
|
doAssert(repr(aa) == """
|
||||||
|
[a = 0,
|
||||||
|
b = 0,
|
||||||
|
c = 0.0,
|
||||||
|
d = '\0',
|
||||||
|
e = eA,
|
||||||
|
f = nil,
|
||||||
|
g = {},
|
||||||
|
h = {},
|
||||||
|
i = [nil, nil, nil],
|
||||||
|
j = nil,
|
||||||
|
k = 0,
|
||||||
|
l = [a = nil,
|
||||||
|
b = nil],
|
||||||
|
m = nil,
|
||||||
|
n = nil,
|
||||||
|
o = [Field0 = [a = nil,
|
||||||
|
b = nil],
|
||||||
|
Field1 = nil],
|
||||||
|
p = nil,
|
||||||
|
q = nil]
|
||||||
|
""")
|
||||||
|
doAssert(repr(cc) == """
|
||||||
|
[a = 12,
|
||||||
|
b = 1,
|
||||||
|
c = 1.2,
|
||||||
|
d = '\0',
|
||||||
|
e = eC,
|
||||||
|
f = "hello",
|
||||||
|
g = {'A'},
|
||||||
|
h = {2},
|
||||||
|
i = ["hello", "world", "array"],
|
||||||
|
j = @["hello", "world", "seq"],
|
||||||
|
k = -1,
|
||||||
|
l = [a = "inner",
|
||||||
|
b = @['o', 'b', 'j']],
|
||||||
|
m = ref 0 --> [a = "inner",
|
||||||
|
b = @['o', 'b', 'j']],
|
||||||
|
n = ref 0 --> [a = "inner",
|
||||||
|
b = @['o', 'b', 'j']],
|
||||||
|
o = [Field0 = [a = "inner",
|
||||||
|
b = @['o', 'b', 'j']],
|
||||||
|
Field1 = "tuple!"],
|
||||||
|
p = 0,
|
||||||
|
q = "cstringtest"]
|
||||||
|
""")
|
||||||
|
|
||||||
|
block another:
|
||||||
|
type
|
||||||
|
Size1 = enum
|
||||||
|
s1a, s1b
|
||||||
|
Size2 = enum
|
||||||
|
s2c=0, s2d=20000
|
||||||
|
Size3 = enum
|
||||||
|
s3e=0, s3f=2000000000
|
||||||
|
|
||||||
|
doAssert(repr([s1a, s1b]) == "[s1a, s1b]\n")
|
||||||
|
doAssert(repr([s2c, s2d]) == "[s2c, s2d]\n")
|
||||||
|
doAssert(repr([s3e, s3f]) == "[s3e, s3f]\n")
|
||||||
|
|
||||||
|
block another2:
|
||||||
|
|
||||||
|
type
|
||||||
|
AnEnum = enum
|
||||||
|
en1, en2, en3, en4, en5, en6
|
||||||
|
|
||||||
|
Point {.final.} = object
|
||||||
|
x, y, z: int
|
||||||
|
s: array[0..1, string]
|
||||||
|
e: AnEnum
|
||||||
|
|
||||||
|
var
|
||||||
|
p: Point
|
||||||
|
q: ref Point
|
||||||
|
s: seq[ref Point]
|
||||||
|
|
||||||
|
p.x = 0
|
||||||
|
p.y = 13
|
||||||
|
p.z = 45
|
||||||
|
p.s[0] = "abc"
|
||||||
|
p.s[1] = "xyz"
|
||||||
|
p.e = en6
|
||||||
|
|
||||||
|
new(q)
|
||||||
|
q[] = p
|
||||||
|
|
||||||
|
s = @[q, q, q, q]
|
||||||
|
|
||||||
|
doAssert(repr(p) == """
|
||||||
|
[x = 0,
|
||||||
|
y = 13,
|
||||||
|
z = 45,
|
||||||
|
s = ["abc", "xyz"],
|
||||||
|
e = en6]
|
||||||
|
""")
|
||||||
|
doAssert(repr(q) == """
|
||||||
|
ref 0 --> [x = 0,
|
||||||
|
y = 13,
|
||||||
|
z = 45,
|
||||||
|
s = ["abc", "xyz"],
|
||||||
|
e = en6]
|
||||||
|
""")
|
||||||
|
doAssert(repr(s) == """
|
||||||
|
@[ref 0 --> [x = 0,
|
||||||
|
y = 13,
|
||||||
|
z = 45,
|
||||||
|
s = ["abc", "xyz"],
|
||||||
|
e = en6], ref 1 --> [x = 0,
|
||||||
|
y = 13,
|
||||||
|
z = 45,
|
||||||
|
s = ["abc", "xyz"],
|
||||||
|
e = en6], ref 2 --> [x = 0,
|
||||||
|
y = 13,
|
||||||
|
z = 45,
|
||||||
|
s = ["abc", "xyz"],
|
||||||
|
e = en6], ref 3 --> [x = 0,
|
||||||
|
y = 13,
|
||||||
|
z = 45,
|
||||||
|
s = ["abc", "xyz"],
|
||||||
|
e = en6]]
|
||||||
|
""")
|
||||||
|
doAssert(repr(en4) == "en4")
|
||||||
|
|
||||||
|
doAssert(repr({'a'..'p'}) == "{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'}")
|
||||||
Loading…
Add table
Add a link
Reference in a new issue