Permalink
Fetching contributors…
Cannot retrieve contributors at this time
390 lines (320 sloc) 6.91 KB
use "types"
use "die"
pkg std =
type typedesc = union
`Tynone
/* atomic types */
`Tyvoid
`Tybool
`Tychar
`Tyint8
`Tyint16
`Tyint
`Tyint32
`Tyint64
`Tybyte
`Tyuint8
`Tyuint16
`Tyuint
`Tyuint32
`Tyuint64
`Tyflt32
`Tyflt64
`Tyvalist
/* compound types */
`Typtr byte[:]
`Tyfunc typecursor
`Tyslice byte[:]
`Tyarray (size, byte[:])
/* aggregate types */
`Tytuple typecursor
`Tystruct typecursor
`Tyunion typecursor
/* name info */
`Tyname (byte[:], byte[:])
;;
type typecursor = struct
nelt : size
rem : byte[:]
isnamed : bool
isiter : bool
;;
type typeinfo = struct
size : size
align : size
;;
generic typeof : (v : @a -> byte[:])
const typeenc : (p : ...# -> typecursor)
const typeenccursor : (e : byte[:] -> typecursor)
const typedesc : (e : byte[:] -> typedesc)
const typeinfo : (e : byte[:] -> typeinfo)
const tcnext : (t : typecursor# -> byte[:])
const tcpeek : (t : typecursor# -> byte[:])
const ncpeek : (t : typecursor# -> (byte[:], byte[:]))
const ncnext : (t : typecursor# -> (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 Encbyte : byte = 9
const Encuint8 : byte = 10
const Encuint16 : byte = 11
const Encuint : byte = 12
const Encuint32 : byte = 13
const Encuint64 : byte = 14
const Encflt32 : byte = 15
const Encflt64 : byte = 16
const Encvalist : byte = 17
/* compound types */
const Encptr : byte = 18
const Encfunc : byte = 19
const Encslice : byte = 20
const Encarray : byte = 21
/* aggregate types */
const Enctuple : byte = 22
const Encstruct : byte = 23
const Encunion : byte = 24
const Encname : byte = 28
const Encindname :byte = 28 | 0x80
generic typeof = {v : @a -> byte[:]
var tc
tc = typesof(v)
-> tcnext(&tc)
}
const typeenc = {ap : ...#
var e
e = getenc((ap : byte##))
e = skiptypeinfo(e[1:])
-> lentypecursor(e)
}
const typeenccursor = {e
-> [.nelt=1, .rem=e, .isiter=false]
}
const typesof : (a : ... -> typecursor) = {a : ...
-> typeenc(&a)
}
const tcnext = {tc
var enc
(_, enc) = ncnext(tc)
-> enc
}
const tcpeek = {tc
var enc
(_, enc) = ncpeek(tc)
-> enc
}
const ncpeek = {tc
var name, enc, rem
var n, sz
if tc.rem.len == 0 || tc.nelt == 0
-> ("", "")
elif !tc.isiter
-> ("", tc.rem)
;;
n = 0
sz = 0
name = ""
rem = tc.rem
if tc.isnamed
/* get the name */
(n, sz) = getipacked(tc.rem)
name = rem[sz:sz+n]
rem = rem[sz+n:]
;;
/* and the type */
(n, sz) = getipacked(rem)
enc = rem[sz:sz+n]
-> (name, enc)
}
const ncnext = {tc
var n, sz, name, enc
if tc.rem.len == 0 || tc.nelt == 0
-> ("", "")
elif !tc.isiter
/* a bit of a trick, if we want to fake arrays */
tc.nelt--
-> ("", tc.rem)
;;
n = 0
sz = 0
name = ""
if tc.isnamed
/* get the name */
(n, sz) = getipacked(tc.rem)
name = tc.rem[sz:sz+n]
tc.rem = tc.rem[sz+n:]
;;
/* and the type */
(n, sz) = getipacked(tc.rem)
enc = tc.rem[sz:sz+n]
tc.rem = tc.rem[sz+n:]
-> (name, enc)
}
const getenc = {p : byte##
var val, sz, x
(val, sz) = getipacked(p#[:8])
x = (&sz : 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
| Encbyte: -> `Tybyte
| Encuint8: -> `Tyuint8
| Encuint16: -> `Tyuint16
| Encuint: -> `Tyuint
| Encuint32: -> `Tyuint32
| Encuint64: -> `Tyuint64
| 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:] : 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]
| 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]
| 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:] : 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:], .isnamed=false, .isiter=true]
}
const lennamecursor = {e
var n, sz
(n, sz) = getipacked(e)
-> [.nelt=n, .rem=e[sz:], .isnamed=true, .isiter=true]
}
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, shift, i
mask = 0x80
val = 0
len = 1
shift = 8 - len
while p[0] & mask != mask << 1
len++
mask >>= 1
mask |= 0x80
;;
shift = 8 - len
val = (p[0] : size) & ~(~0 << shift)
for i = 1; i < len; i++
val |= (p[i] : size) << (i*8 - len)
;;
-> (val, len)
}