ref: 46f0325e0e0d5e49b6bcf926e45449f3397eaa47
dir: /libstd/introspect.myr/
use "types.use" use "die.use" pkg std = type typedesc = union `Tynone /* atomic types */ `Tyvoid `Tybool `Tychar `Tyint8 `Tyint16 `Tyint `Tyint32 `Tyint64 `Tylong `Tybyte `Tyuint8 `Tyuint16 `Tyuint `Tyuint32 `Tyuint64 `Tyulong `Tyflt32 `Tyflt64 `Tyvalist /* compound types */ `Typtr byte[:] `Tyfunc typecursor `Tyslice byte[:] `Tyarray (size, byte[:]) /* aggregate types */ `Tytuple typecursor `Tystruct namecursor `Tyunion namecursor /* name info */ `Tyname (byte[:], byte[:]) ;; type typecursor = struct nelt : size rem : byte[:] ;; type namecursor = struct nelt : size rem : byte[:] ;; type typeinfo = struct size : size align : size ;; generic typeof : (v : @a -> byte[:]) const typeenc : (p : ...# -> typecursor) const typedecode : (e : byte[:] -> typedesc) const typedesc : (e : byte[:] -> typedesc) const typeinfo : (e : byte[:] -> typeinfo) const tcnext : (t : typecursor# -> byte[:]) const tcpeek : (t : typecursor# -> byte[:]) const ncnext : (t : namecursor# -> (byte[:], byte[:])) ;; extern const put : (fmt : byte[:], args : ... -> size) const Encnone : byte = 0 const Encvoid : byte = 1 const Encbool : byte = 2 const Encchar : byte = 3 const Encint8 : byte = 4 const Encint16 : byte = 5 const Encint : byte = 6 const Encint32 : byte = 7 const Encint64 : byte = 8 const Enclong : byte = 9 const Encbyte : byte = 10 const Encuint8 : byte = 11 const Encuint16 : byte = 12 const Encuint : byte = 13 const Encuint32 : byte = 14 const Encuint64 : byte = 15 const Enculong : byte = 16 const Encflt32 : byte = 17 const Encflt64 : byte = 18 const Encvalist : byte = 19 /* compound types */ const Encptr : byte = 20 const Encfunc : byte = 21 const Encslice : byte = 22 const Encarray : byte = 23 /* aggregate types */ const Enctuple : byte = 24 const Encstruct : byte = 25 const Encunion : byte = 26 const Encname : byte = 30 const Encindname :byte = 30 | 0x80 generic typeof = {v : @a -> byte[:] var tc tc = typesof(v) -> tcnext(&tc) } const typeenc = {ap : ...# var e e = getenc(ap castto(byte##)) e = skiptypeinfo(e[1:]) -> lentypecursor(e) } const typesof : (a : ... -> typecursor) = {a : ... -> typeenc(&a) } const tcnext = {tc var n, sz, cur if tc.rem.len == 0 -> "" ;; (n, sz) = getipacked(tc.rem) cur = tc.rem[sz:sz+n] tc.rem = tc.rem[sz+n:] -> cur } const tcpeek = {tc var n, sz if tc.rem.len == 0 -> "" ;; (n, sz) = getipacked(tc.rem) -> tc.rem[sz:sz+n] } const ncnext = {nc var n, sz, name, enc if nc.rem.len == 0 -> ("", "") ;; /* get the name */ (n, sz) = getipacked(nc.rem) name = nc.rem[sz:sz+n] nc.rem = nc.rem[sz+n:] /* and the type */ (n, sz) = getipacked(nc.rem) enc = nc.rem[sz:sz+n] nc.rem = nc.rem[sz+n:] -> (name, enc) } const getenc = {p : byte## var val, sz, x (val, sz) = getipacked(p#[:8]) x = &sz castto(byte#) -> p#[sz:sz+val] } const typedesc = {ti var len,sz, p match ti[0] | Encnone: -> `Tynone | Encvoid: -> `Tyvoid | Encbool: -> `Tybool | Encchar: -> `Tychar | Encint8: -> `Tyint8 | Encint16: -> `Tyint16 | Encint: -> `Tyint | Encint32: -> `Tyint32 | Encint64: -> `Tyint64 | Enclong: -> `Tylong | Encbyte: -> `Tybyte | Encuint8: -> `Tyuint8 | Encuint16: -> `Tyuint16 | Encuint: -> `Tyuint | Encuint32: -> `Tyuint32 | Encuint64: -> `Tyuint64 | Enculong: -> `Tyulong | Encflt32: -> `Tyflt32 | Encflt64: -> `Tyflt64 | Encvalist: -> `Tyvalist /* compound types */ | Encptr: -> `Typtr getsub(ti[1:]) | Encfunc: -> `Tyfunc lentypecursor(ti[1:]) | Encslice: -> `Tyslice getsub(ti[1:]) | Encarray: ti = skiptypeinfo(ti[1:]) (len, sz) = getipacked(ti) -> `Tyarray (len, getsub(ti[sz:])) /* aggregate types */ | Enctuple: ti = skiptypeinfo(ti[1:]) -> `Tytuple lentypecursor(ti) | Encstruct: ti = skiptypeinfo(ti[1:]) -> `Tystruct lennamecursor(ti) | Encunion: ti = skiptypeinfo(ti[1:]) -> `Tyunion lennamecursor(ti) | Encname: -> `Tyname namedesc(ti[1:]) | Encindname: /* ugly hack: the slice contains a pointer to the value, so if we cast it to a byte##, we can pull the indirect value out of the pointer. */ p = ti[1:] castto(byte##) -> typedesc(getenc(p)) | _: std.die("unknown type encoding") ;; } const typeinfo = {ti var p match ti[0] | Encnone: -> [.size=0, .align=1] | Encvoid: -> [.size=0, .align=1] | Encbool: -> [.size=0, .align=1] | Encchar: -> [.size=4, .align=4] | Encint8: -> [.size=1, .align=1] | Encint16: -> [.size=2, .align=2] | Encint: -> [.size=4, .align=4] | Encint32: -> [.size=4, .align=4] | Encint64: -> [.size=8, .align=8] | Enclong: -> [.size=8, .align=8] | Encbyte: -> [.size=1, .align=1] | Encuint8: -> [.size=1, .align=1] | Encuint16: -> [.size=2, .align=2] | Encuint: -> [.size=4, .align=4] | Encuint32: -> [.size=4, .align=4] | Encuint64: -> [.size=8, .align=8] | Enculong: -> [.size=8, .align=8] | Encflt32: -> [.size=4, .align=4] | Encflt64: -> [.size=8, .align=8] | Encvalist: -> [.size=8, .align=8] /* compound types */ | Encptr: -> [.size=8, .align=8] | Encfunc: -> [.size=8, .align=8] | Encslice: -> [.size=16, .align=8] | Encarray: -> gettypeinfo(ti[1:]) | Enctuple: -> gettypeinfo(ti[1:]) | Encstruct: -> gettypeinfo(ti[1:]) | Encunion: -> gettypeinfo(ti[1:]) | Encname: -> getnameinfo(ti[1:]) | Encindname: p = ti[1:] castto(byte##) -> typeinfo(getenc(p)) | _: std.die("unknown type encoding") ;; } const gettypeinfo = {e var size, align, sz (size, sz) = getipacked(e) /* size */ e = e[sz:] (align, sz) = getipacked(e) /* align */ -> [.size = size, .align = align] } const skiptypeinfo = {e var ignore, sz (ignore, sz) = getipacked(e) /* size */ e = e[sz:] (ignore, sz) = getipacked(e) /* align */ -> e[sz:] } const getnameinfo = {e var n, name, sz, enc (n, sz) = getipacked(e) name = e[sz:n+sz] e = e[n+sz:] (n, sz) = getipacked(e) enc = e[sz:n+sz] -> typeinfo(enc) } const namedesc = {e var n, sz, name, enc (n, sz) = getipacked(e) name = e[sz:n+sz] e = e[n+sz:] (n, sz) = getipacked(e) enc = e[sz:n+sz] -> (name, enc) } const lentypecursor = {e var n, sz (n, sz) = getipacked(e) -> [.nelt=n, .rem=e[sz:]] } const lennamecursor = {e var n, sz (n, sz) = getipacked(e) -> [.nelt=n, .rem=e[sz:]] } const getsub = {e var n, sz (n, sz) = getipacked(e) -> e[sz:sz+n] } const getipacked : (p : byte[:] -> (size, size)) = {p : byte[:] var mask, val, len, i mask = 0x80 val = 0 len = 1 while p[0] & mask != mask << 1 len++ mask >>= 1 mask |= 0x80 ;; val = (p[0] castto(size)) & ~(1 << (8 - len)) for i = 1; i < len; i++ val |= (p[i] castto(size)) << (i*8 - len) ;; -> (val, len) }