ref: 6b1a6216b40b804dd9c91c2bd54bee954776acaa
parent: c1ad3758cdccebead9fafd8bdecf6caa5071fe19
author: Ori Bernstein <ori@eigenstate.org>
date: Tue May 19 20:06:07 EDT 2015
Add first cut at introspection API.
--- a/6/gengas.c
+++ b/6/gengas.c
@@ -539,7 +539,7 @@
fprintf(fd, "\t.quad %s\n", b->ref);
break;
case Btbytes:
- writebytes(fd, b->bytes.buf, b->bytes.len + 1);
+ writebytes(fd, b->bytes.buf, b->bytes.len);
break;
case Btseq:
for (i = 0; i < b->seq.nsub; i++)
--- a/6/typeinfo.c
+++ b/6/typeinfo.c
@@ -123,10 +123,12 @@
static void unionmemb(Blob ***sub, size_t *nsub, Ucon *ucon)
{
namevec(sub, nsub, ucon->name);
- if (ucon->etype)
+ if (ucon->etype) {
lappend(sub, nsub, tydescsub(ucon->etype));
- else
+ } else {
+ lappend(sub, nsub, mkblobi(Btimin, 1));
lappend(sub, nsub, mkblobi(Bti8, Tybad));
+ }
}
Blob *tydescsub(Type *ty)
--- a/libstd/bld.sub
+++ b/libstd/bld.sub
@@ -47,6 +47,7 @@
hassuffix.myr
htab.myr
intparse.myr
+ introspect.myr
ipparse.myr
mk.myr
mkpath.myr
--- /dev/null
+++ b/libstd/introspect.myr
@@ -1,0 +1,258 @@
+use "types.use"
+use "die.use"
+use "fmt.use"
+
+pkg std =
+ type typeinfo = 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[:]
+ ;;
+
+ generic typeof : (v : @a -> byte[:])
+ const typesof : (vl : ... -> typecursor)
+ const typeinfo : (e : byte[:] -> typeinfo)
+
+ const tcnext : (t : typecursor# -> byte[:])
+ const ncnext : (t : namecursor# -> (byte[:], byte[:]))
+;;
+
+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
+ var tc
+
+ tc = typesof(v)
+ -> tcnext(&tc)
+}
+
+const typesof = {a : ...
+ var e
+
+ e = getenc(&a castto(byte##))
+ /* we encode the arg pack type as a tuple of the types passed */
+ std.assert(e[0] == Enctuple, "typesof wrong base type")
+ -> lentypecursor(e[1:])
+}
+
+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 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
+
+ (val, sz) = getipacked(p#[:8])
+ -> p#[sz:sz+val]
+}
+
+const typeinfo = {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
+ /* for now */
+
+ /* compound types */
+ | Encptr: -> `Typtr getsub(ti[1:])
+ | Encfunc: -> `Tyfunc lentypecursor(ti[1:])
+ | Encslice: -> `Tyslice getsub(ti[1:])
+ | Encarray:
+ (len, sz) = getipacked(ti[1:])
+ -> `Tyarray (len, getsub(ti[sz+1:]))
+
+
+ /* aggregate types */
+ | Enctuple: -> `Tytuple lentypecursor(ti[1:])
+ | Encstruct: -> `Tystruct lennamecursor(ti[1:])
+ | Encunion: -> `Tyunion lennamecursor(ti[1:])
+ | Encname: -> `Tyname nameinfo(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##)
+ -> typeinfo(getenc(p))
+ | other: std.fatal("unsupported type %b\n", other)
+ ;;
+}
+
+const nameinfo = {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[:]
+ var mask, val, len, i
+
+ mask = 0x80
+ val = 0
+ len = 1
+ while p[0] & mask != mask << 1
+ len++
+ mask >>= 1
+ mask |= 0x80
+ ;;
+
+ for i = 0; i < len; i++
+ val |= (p[i] castto(size)) << (i*7)
+ ;;
+ -> (val, len)
+}