ref: ea50af981b8a0472e2e3588c31c51ae927098949
parent: 53f937aeaa1ad2320f61c63933e24f2f6f1f326f
author: Ori Bernstein <[email protected]>
date: Fri Jun 5 19:05:51 EDT 2015
Work towards better varargs. We now capture and check types!
--- a/libstd/fmt.myr
+++ b/libstd/fmt.myr
@@ -1,15 +1,16 @@
use sys
-
use "alloc.use"
+use "chartype.use"
use "die.use"
+use "extremum.use"
+use "fltfmt.use"
+use "introspect.use"
+use "sleq.use"
+use "syswrap-ss.use"
+use "syswrap.use"
use "types.use"
use "utf.use"
-use "syswrap.use"
-use "syswrap-ss.use"
use "varargs.use"
-use "extremum.use"
-use "chartype.use"
-use "fltfmt.use"
/*
printf-like functions. These use a different syntax from the C printf,
--- a/libstd/introspect.myr
+++ b/libstd/introspect.myr
@@ -1,6 +1,6 @@
use "types.use"
use "die.use"
-use "fmt.use"
+use sys
pkg std =
type typedesc = union
@@ -59,15 +59,18 @@
;;
generic typeof : (v : @a -> byte[:])
- const typesof : (vl : ... -> typecursor)
+ 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
@@ -104,7 +107,7 @@
const Encname : byte = 30
const Encindname :byte = 30 | 0x80
-generic typeof = {v : @a
+generic typeof = {v : @a -> byte[:]
var tc
tc = typesof(v)
@@ -111,15 +114,17 @@
-> tcnext(&tc)
}
-const typesof = {a : ...
+const typeenc = {ap : ...#
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")
+ 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
@@ -133,6 +138,16 @@
-> 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
@@ -154,9 +169,10 @@
const getenc = {p : byte##
- var val, sz
+ var val, sz, x
(val, sz) = getipacked(p#[:8])
+ x = &sz castto(byte#)
-> p#[sz:sz+val]
}
@@ -218,7 +234,7 @@
p = ti[1:] castto(byte##)
-> typedesc(getenc(p))
| _:
- std.fatal("unknown type encoding")
+ std.die("unknown type encoding")
;;
}
@@ -263,7 +279,7 @@
p = ti[1:] castto(byte##)
-> typeinfo(getenc(p))
| _:
- std.fatal("unknown type encoding")
+ std.die("unknown type encoding")
;;
}
--- a/libstd/strbuf.myr
+++ b/libstd/strbuf.myr
@@ -34,6 +34,7 @@
const mkbufsb = {buf
var sb
+
sb = zalloc()
sb.buf = buf
sb.fixed = true
--- a/libstd/varargs.myr
+++ b/libstd/varargs.myr
@@ -1,4 +1,7 @@
use "types.use"
+use "introspect.use"
+use "sleq.use"
+use "die.use"
pkg std =
type valist
@@ -7,7 +10,10 @@
generic vanext : (ap : valist -> (@a, valist))
;;
-type valist = byte#
+type valist = struct
+ args : byte#
+ tc : typecursor
+;;
/*
* a valist is really just a pointer to the varargs.
@@ -19,10 +25,28 @@
* force varargs onto the stack regardless.
*/
const vastart = {args
- var ap, dump : byte#
+ var tc, a, ip
- (dump, ap) = vanext(args castto(valist))
- -> ap
+ /*
+ pull out the args. These are on the stacks like so:
+
+ [ required ]
+ [ args ]
+ ---variadic---
+ [ typeinfo ] --> type description
+ ------------
+ [ variadic ]
+ [ args ]
+ [ here ]
+
+ &args points to the typeinfo, &args + sizeof(void#)
+ points to the rest argument.
+ */
+
+ tc = typeenc(args)
+ ip = (args castto(intptr)) + sizeof(byte#)
+ a = ip castto(byte#)
+ -> [.args = a, .tc = tc]
}
generic vanext = {ap -> (@a, valist)
@@ -43,13 +67,20 @@
;;
/* apply the alignment to the arg pointer */
- p = ap castto(intptr)
+ p = ap.args castto(intptr)
p = (p + align - 1) & ~(align - 1)
- ap = p castto(valist)
+ ap.args = p castto(byte#)
- v = (ap castto(@a#))#
+ v = (ap.args castto(@a#))#
+ /* TODO: checked.
+ Right now, too much is broken with named types.
+ if !sleq(typeof(v), tcnext(&ap.tc))
+ std.die("wrong type from valist\n")
+ ;;
+ */
+
/* only move on after we read through the value */
- ap = ((p castto(intptr)) + sizeof(@a)) castto(valist)
+ ap.args = ((p castto(intptr)) + sizeof(@a)) castto(byte#)
-> (v, ap)
}