summaryrefslogtreecommitdiff
path: root/lib/std/varargs.myr
diff options
context:
space:
mode:
Diffstat (limited to 'lib/std/varargs.myr')
-rw-r--r--lib/std/varargs.myr105
1 files changed, 105 insertions, 0 deletions
diff --git a/lib/std/varargs.myr b/lib/std/varargs.myr
new file mode 100644
index 0000000..c2ed1b2
--- /dev/null
+++ b/lib/std/varargs.myr
@@ -0,0 +1,105 @@
+use "types.use"
+use "introspect.use"
+use "sleq.use"
+use "die.use"
+
+pkg std =
+ type valist
+
+ const vastart : (args : ...# -> valist)
+ const vatype : (ap : valist# -> byte[:])
+ const vabytes : (ap : valist# -> byte[:])
+ generic vanext : (ap : valist# -> @a)
+;;
+
+type valist = struct
+ args : byte#
+ tc : typecursor
+;;
+
+/*
+ * a valist is really just a pointer to the varargs.
+ * we assume that these sit on the stack nicely,
+ * and don't need special handling to get to.
+ *
+ * This will be a problem when we switch to a
+ * register based convention. We might want to
+ * force varargs onto the stack regardless.
+ */
+const vastart = {args
+ var tc, a, ip
+
+ /*
+ 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]
+}
+
+const vatype = {ap
+ -> tcpeek(&ap.tc)
+}
+
+const vabytes = {ap
+ var sl
+ var ti, align, sz
+ var p
+
+ ti = typeinfo(tcpeek(&ap.tc))
+
+ /* apply the alignment to the arg pointer */
+ align = ti.align castto(intptr)
+ p = ap.args castto(intptr)
+ p = (p + align - 1) & ~(align - 1)
+ ap.args = p castto(byte#)
+
+ sl = ap.args[:ti.size]
+ tcnext(&ap.tc)
+
+ sz = ti.size castto(intptr)
+ ap.args = ((p castto(intptr)) + sz) castto(byte#)
+
+ -> sl
+}
+
+const inspectarg = {x
+}
+
+generic vanext = {ap -> @a
+ var v : @a
+ var ti
+ var align
+ var p
+
+ ti = typeinfo(tcpeek(&ap.tc))
+
+ /* apply the alignment to the arg pointer */
+ align = ti.align castto(intptr)
+ inspectarg(align)
+ p = ap.args castto(intptr)
+ p = (p + align - 1) & ~(align - 1)
+ ap.args = p castto(byte#)
+
+ v = (ap.args castto(@a#))#
+ /* TODO: check for type mismatch */
+ tcnext(&ap.tc)
+
+ /* only move on after we read through the value */
+ ap.args = ((p castto(intptr)) + sizeof(@a)) castto(byte#)
+ -> v
+}