shithub: mc

ref: 6b1a6216b40b804dd9c91c2bd54bee954776acaa
dir: /libstd/introspect.myr/

View raw version
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)
}