shithub: mc

ref: 04d647955b3d83e2fb3731d63887ae499809141e
dir: /libstd/introspect.myr/

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