ref: a3b2e73283428008eebe4af1e57f41580b877cff
parent: 4e145a71d2753ca1c6f464375f220a145b9f1019
parent: 8337ff18aea527cdb97c66da3b35de994fe1975c
author: Ori Bernstein <[email protected]>
date: Wed May 1 09:09:21 EDT 2013
Merge branch 'master' of git+ssh://git.eigenstate.org/git/ori/mc Conflicts: libstd/util.s
--- a/libstd/Makefile
+++ b/libstd/Makefile
@@ -7,6 +7,7 @@
fmt.myr \
optparse.myr \
rand.myr \
+ slappend.myr \
slurp.myr \
sys.myr \
types.myr \
--- a/libstd/alloc.myr
+++ b/libstd/alloc.myr
@@ -1,13 +1,12 @@
use "die.use"
+use "extremum.use"
use "sys.use"
use "types.use"
-use "extremum.use"
-use "fmt.use"
-/*
+/*
The allocator implementation here is based on Bonwick's slab allocator.
-For small allocations (up to Bucketmax), it works by requesting large,
+For small allocations (up to Bktmax), it works by requesting large,
power of two aligned chunks from the operating system, and breaking
them into a linked list of equal sized chunks. Allocations are then
satisfied by taking the head of the list of chunks. Empty slabs
@@ -14,7 +13,7 @@
are removed from the freelist.
The data structure looks something like this:
- Buckets:
+ Bkts:
[16 byte] -> [slab hdr | chunk -> chunk -> chunk] -> [slab hdr | chunk -> chunk -> chunk]
[32 byte] -> Zslab
[64 byte] -> [slab hdr | chunk -> chunk]
@@ -35,6 +34,9 @@
const bytealloc : (sz:size -> byte#)
const bytefree : (m:byte#, sz:size -> void)
+
+ /* FIXME: This should be automatically exported as a hidden decl. */
+ const samebucket
;;
/* null pointers. only used internally. */
@@ -44,7 +46,7 @@
const Slabsz = 1048576 /* 1 meg slabs */
const Cachemax = 16 /* maximum number of slabs in the cache */
-const Bucketmax = 32768 /* Slabsz / 8; a balance. */
+const Bktmax = 32768 /* Slabsz / 8; a balance. */
const Align = 16 /* minimum allocation alignment */
var buckets : bucket[32] /* excessive */
@@ -93,20 +95,35 @@
}
/* Grows a slice */
-generic slgrow = {sl, len
+generic slgrow = {sl : @a[:], len
var i
var n
var new
+ /* if the slice wouldn't change buckets, we don't need to realloc. */
+ if samebucket(sl.len * sizeof(@a), len * sizeof(@a))
+ -> sl
+ ;;
+
new = slalloc(len)
n = min(len, sl.len)
for i = 0; i < n; i++
new[i] = sl[i]
;;
- slfree(sl)
+ if sl.len > 0
+ slfree(sl)
+ ;;
-> new
}
+const samebucket = {oldsz, newsz
+ if oldsz > 0 && newsz < Bktmax
+ -> bktnum(oldsz) == bktnum(newsz)
+ else
+ -> false
+ ;;
+}
+
/* Allocates a blob that is 'sz' bytes long. Dies if the allocation fails */
const bytealloc = {sz
var i
@@ -113,13 +130,13 @@
var bkt
if !initdone
- for i = 0; i < buckets.len && (Align << i) <= Bucketmax; i++
+ for i = 0; i < buckets.len && (Align << i) <= Bktmax; i++
bktinit(&buckets[i], Align << i)
;;
initdone = 1
;;
- if (sz <= Bucketmax)
+ if (sz <= Bktmax)
bkt = &buckets[bktnum(sz)]
-> bktalloc(bkt)
else
@@ -131,7 +148,7 @@
const bytefree = {m, sz
var bkt
- if (sz < Bucketmax)
+ if (sz < Bktmax)
bkt = &buckets[bktnum(sz)]
bktfree(bkt, m)
else
@@ -259,7 +276,7 @@
var bktsz
bktsz = Align
- for i = 0; bktsz <= Bucketmax; i++
+ for i = 0; bktsz <= Bktmax; i++
if bktsz >= sz
-> i
;;
--- a/libstd/fmt.myr
+++ b/libstd/fmt.myr
@@ -1,3 +1,4 @@
+use "alloc.use"
use "die.use"
use "sys.use"
use "types.use"
@@ -14,26 +15,67 @@
%w - A 16 bit integer
%i - A 32 bit integer
%l - A 64 bit integer
+ %z - A size
%p - A pointer
%c - A char
*/
pkg std =
- const bfmt : (buf : byte[:], fmt : byte[:], args:... -> size)
- const bfmtv : (buf : byte[:], fmt : byte[:], ap:valist -> size)
- const put : (fmt : byte[:], args:... -> size)
+ const put : (fmt : byte[:], args : ... -> size)
+ const putv : (fmt : byte[:], ap : valist -> size)
+ const fatal : (status : int, fmt : byte[:], args : ... -> void)
+ const fatalv : (status : int, fmt : byte[:], ap : valist -> void)
+ const fmt : (fmt : byte[:], args : ... -> byte[:])
+ const fmtv : (fmt : byte[:], ap : valist -> byte[:])
+ const bfmt : (buf : byte[:], fmt : byte[:], args : ... -> size)
+ const bfmtv : (buf : byte[:], fmt : byte[:], ap : valist -> size)
;;
/* Writes a string of text up to 2 kb in size to stdout */
const put = {fmt, args
+ -> putv(fmt, vastart(&args))
+}
+
+/* Writes a string of text up to 2kb long to stdout, using a valist
+ as the source of the arguments */
+const putv = {fmt, ap
var buf : byte[2048]
var n
- n = bfmtv(buf[:], fmt, vastart(&args))
+ n = bfmtv(buf[:], fmt, ap)
write(1, buf[:n])
-> n
}
+/* same as 'put', but exits the program after printing */
+const fatal = {status, fmt, args
+ putv(fmt, vastart(&args))
+ exit(status)
+}
+
+/* same as 'putv', but exits the program after printing */
+const fatalv = {status, fmt, ap
+ putv(fmt, ap)
+ exit(status)
+}
+
+/* formats a string, allocating the slice. FIXME: calculate the
+ size needed. */
+const fmt = {fmt, args
+ -> fmtv(fmt, vastart(&args))
+}
+
+/* formats a string, allocating the slice. FIXME: calculate the
+ size needed. Takes a valist as it's last argument. */
+const fmtv = {fmt, ap
+ var buf
+ var sz
+
+ buf = slalloc(2048)
+ sz = bfmtv(buf, fmt, ap)
+ -> buf[:sz]
+}
+
/* formats a string of text as specified by 'fmt' into 'buf' */
const bfmt = {buf, fmt, args
-> bfmtv(buf, fmt, vastart(&args))
@@ -49,6 +91,7 @@
var w_val : int16
var i_val : int32
var l_val : int64
+ var z_val : size
var p_val : byte#
var c_val : char
@@ -78,6 +121,10 @@
'l':
(l_val, ap) = vanext(ap)
n += intfmt(buf[n:], l_val castto(int64), 10)
+ ;;
+ 'z':
+ (z_val, ap) = vanext(ap)
+ n += intfmt(buf[n:], z_val castto(int64), 10)
;;
'p':
(p_val, ap) = vanext(ap)
--- a/libstd/optparse.myr
+++ b/libstd/optparse.myr
@@ -1,79 +1,127 @@
-use "types.use"
use "alloc.use"
-use "utf.use"
use "die.use"
+use "extremum.use"
+use "fmt.use"
+use "slappend.use"
+use "sys.use"
+use "types.use"
+use "utf.use"
pkg std =
type optctx = struct
- /* data passed in */
- opts : byte[:]
+ /* public variables */
args : byte[:][:]
+ /* data passed in */
+ optstr : byte[:]
+ optargs : byte[:][:]
+
/* state */
+ optdone : bool /* if we've seen '--', everything's an arg */
+ finished : bool /* if we've processed all theoptargs */
argidx : size
curarg : byte[:]
- arglist : byte[:][:]
;;
- const optinit : (opts : byte[:], args : byte[:][:] -> optctx#)
- const optnext : (ctx : optctx# -> char)
- const optarg : (ctx : optctx# -> byte[:])
+ const optinit : (optstr: byte[:],optargs : byte[:][:] -> optctx#)
+ const optnext : (ctx : optctx# -> [char, byte[:]])
+ const optdone : (ctx : optctx# -> bool)
;;
-const optinit = {opts, args
+const optinit = {optstr, optargs
var ctx
ctx = alloc()
- ctx.opts = opts
- ctx.args = args
+ ctx.optstr= optstr
+ ctx.optargs =optargs
+
+ ctx.optdone = false
+ ctx.finished = false
ctx.argidx = 0
- ctx.arglist = [][:]
- nextopt(ctx)
+ ctx.curarg = [][:]
+
+ ctx.args = [][:]
+
+ next(ctx)
-> ctx
}
const optnext = {ctx
var c
+ var arg
+ var valid
+ var tryarg
+ var needarg
- if !ctx.curarg.len
- if !nextopt(ctx)
- -> Badchar
- ;;
- ;;
(c, ctx.curarg) = striter(ctx.curarg)
- -> c
-}
-const optarg = {ctx
- var arg
-
- if ctx.curarg.len > 0
+ (valid, tryarg, needarg) = optinfo(ctx, c)
+ if !valid
+ put("Unexpected argument %c\n", c)
+ exit(1)
+ elif tryarg && ctx.curarg.len > 0
arg = ctx.curarg
ctx.curarg = ctx.curarg[ctx.curarg.len:]
- elif ctx.argidx > ctx.args.len
- arg = ctx.args[ctx.argidx + 1]
+ elif tryarg && ctx.argidx < (ctx.optargs.len - 1)
+ arg = ctx.optargs[ctx.argidx + 1]
ctx.argidx++
- nextopt(ctx)
+ next(ctx)
+ elif needarg
+ put("Expected argument for %c\n", c)
+ exit(1)
else
- die("Arg needed")
+ arg = ""
;;
- -> arg
+
+ if !ctx.curarg.len
+ next(ctx)
+ ;;
+
+ -> (c, arg)
}
-const nextopt = {ctx
+const optdone = {ctx
+ -> !ctx.curarg.len && ctx.finished
+}
+
+const optinfo = {ctx, arg
+ var s
+ var c
+
+ s = ctx.optstr
+ while s.len != 0
+ (c, s) = striter(s)
+ if c == arg
+ (c, s) = striter(s)
+ /* mandatory arg */
+ if c == ':'
+ -> (true, true, true)
+ /* optional arg */
+ elif c == '?'
+ -> (true, true, false)
+ /* no arg */
+ else
+ -> (true, false, false)
+ ;;
+ ;;
+ ;;
+ -> (false, false)
+}
+
+const next = {ctx
var i
- for i = ctx.argidx + 1; i < ctx.args.len; i++
- if decode(ctx.args[i]) == '-'
+ for i = ctx.argidx + 1; i < ctx.optargs.len; i++
+ if !ctx.optdone && decode(ctx.optargs[i]) == '-'
goto foundopt
else
- /* FIXME: implement slappend */
- /* ctx.args = slappend(ctx.args, ctx.args[i]) */
+ ctx.args = slappend(ctx.args, ctx.optargs[i])
;;
;;
+ ctx.finished = true
-> false
:foundopt
ctx.argidx = i
- ctx.curarg = ctx.args[i][1:]
+ ctx.curarg = ctx.optargs[i][1:]
-> true
}
--- /dev/null
+++ b/libstd/slappend.myr
@@ -1,0 +1,11 @@
+use "alloc.use"
+
+pkg std =
+ generic slappend : (sl : @a[:], v : @a -> @a[:])
+;;
+
+generic slappend = {sl, v
+ sl = slgrow(sl, sl.len + 1)
+ sl[sl.len - 1] = v
+ -> sl
+}
--- a/libstd/sys-linux.myr
+++ b/libstd/sys-linux.myr
@@ -371,7 +371,7 @@
extern const syscall : (sc:scno, args:... -> int64)
extern const cstring : (str : byte[:] -> byte#)
- const exit : (status:int64 -> void)
+ const exit : (status:int -> void)
const getpid : ( -> int64)
const kill : (pid:int64, sig:int64 -> int64)
const open : (path:byte[:], opts:fdopt, mode:int64 -> int64)
@@ -385,7 +385,7 @@
const mmap : (addr:byte#, len:size, prot:mprot, flags:mopt, fd:int64, off:off -> byte#)
;;
-const exit = {status; syscall(Sysexit, 1)}
+const exit = {status; syscall(Sysexit, status castto(int64))}
const getpid = {; -> syscall(Sysgetpid, 1)}
const kill = {pid, sig; -> syscall(Syskill, pid, sig)}
const open = {path, opts, mode; -> syscall(Sysopen, cstring(path), opts, mode)}
--- a/libstd/sys-osx.myr
+++ b/libstd/sys-osx.myr
@@ -417,7 +417,7 @@
extern const syscall : (sc:scno, args:... -> int64)
extern const cstring : (str : byte[:] -> byte#)
- const exit : (status:int64 -> void)
+ const exit : (status:int -> void)
const getpid : ( -> int64)
const kill : (pid:int64, sig:int64 -> int64)
const open : (path:byte[:], opts:fdopt, mode:int64 -> int64)
@@ -431,7 +431,7 @@
const mmap : (addr:byte#, len:size, prot:mprot, flags:mopt, fd:int64, off:off -> byte#)
;;
-const exit = {status; syscall(Sysexit, 1)}
+const exit = {status; syscall(Sysexit, status castto(int64))}
const getpid = {; -> syscall(Sysgetpid, 1)}
const kill = {pid, sig; -> syscall(Syskill, pid, sig)}
const open = {path, opts, mode; -> syscall(Sysopen, cstring(path), opts, mode)}
--- a/libstd/test.myr
+++ b/libstd/test.myr
@@ -4,8 +4,9 @@
var x : byte#[1024]
var sz
var i
- var opt
+ var ctx
var o
+ var a
std.put("args.len = %i\n", args.len)
for i = 0; i < args.len; i++
@@ -12,14 +13,15 @@
std.put("args[%i] = %s\n", i, args[i])
;;
- opt = std.optinit("asdf:", args)
- while (o = std.optnext(opt)) != std.Badchar
- std.put("option %c\n", o)
- match o
- 'a': std.put("\targ=%s\n", std.optarg(opt));;
- 'b': std.put("\targ=%s\n", std.optarg(opt));;
- ;;
+ ctx = std.optinit("asdf:g?", args)
+ std.put("arglen = %i\n", ctx.args.len)
+ while !std.optdone(ctx)
+ (o, a) = std.optnext(ctx)
+ std.put("option %c, arg = %s\n", o, a)
;;
+ for i = 0; i < ctx.args.len; i++
+ std.put("arg %s\n", ctx.args[i])
+ ;;
/* try the byte allocator for large variety of sizes. */
--- a/libstd/util.s
+++ b/libstd/util.s
@@ -14,19 +14,19 @@
std$cstring:
movq (%rsp),%r15 /* ret addr */
movq 8(%rsp),%rsi /* src */
- movq %rsp,%rdi /* dest */
+ movq %rsp,%rdi /* dest */
movq %rsp,%rax /* ret val */
movq 16(%rsp),%rcx /* len */
-
- subq $16,%rsp /* compensate for args */
+
+ subq $16,%rsp /* "unpop" the args */
subq %rcx,%rsp /* get stack */
- subq $1,%rsp /* nul */
- andq $(~15),%rsp /* align */
-
+ subq $1,%rsp /* nul */
+ andq $(~15),%rsp /* align */
+
cld
rep movsb
- movb $0,(%rdi) /* terminate */
-
+ movb $0,(%rdi) /* terminate */
+
pushq %r15 /* ret addr */
ret
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -780,7 +780,7 @@
else if (s->decl.isconst)
t = s->decl.type;
else
- fatal(n->line, "Can't match against variables in nterns near %s", ctxstr(st, n));
+ fatal(n->line, "Can't match against non-constant variables near %s", ctxstr(st, n));
} else {
t = mktyvar(n->line);
s = mkdecl(n->line, n->expr.args[0], t);
@@ -1252,6 +1252,7 @@
for (i = 0; i < n; i++) {
t = tf(st, gettype(s, k[i]));
updatetype(s, k[i], t);
+ tyfix(st, k[i], t);
}
free(k);
--- a/parse/use.c
+++ b/parse/use.c
@@ -39,9 +39,9 @@
char *pkg;
Stab *s;
Node *dcl;
- Type *t;
- Node *n;
+ Type *t, *u;
int c;
+ size_t i;
if (fgetc(f) != 'U')
return 0;
@@ -70,9 +70,15 @@
putdcl(s, dcl);
break;
case 'T':
- n = mkname(-1, rdstr(f));
t = tyunpickle(f);
- puttype(s, n, t);
+ assert(t->type == Tyname || t->type == Tygeneric);
+ puttype(s, t->name, t);
+ u = tybase(t);
+ if (u->type == Tyunion) {
+ for (i = 0; i < u->nmemb; i++)
+ putucon(s, u->udecls[i]);
+ }
+
break;
case EOF:
break;
@@ -113,7 +119,7 @@
/* Usefile format:
* U<pkgname>
- * T<typename><pickled-type>
+ * T<pickled-type>
* D<picled-decl>
* G<pickled-decl><pickled-initializer>
* Z
@@ -136,8 +142,8 @@
k = htkeys(st->ty, &n);
for (i = 0; i < n; i++) {
t = gettype(st, k[i]);
+ assert(t->type == Tyname || t->type == Tygeneric);
wrbyte(f, 'T');
- wrstr(f, namestr(k[i]));
typickle(t, f);
}
free(k);
--- a/test/tests
+++ b/test/tests
@@ -80,6 +80,7 @@
B helloworld P Hello-世界
B catfile P Hello-世界
B encodechar P 1世界äa
+B exportcycle E 0
F declmismatch
F infermismatch
# F usedef ## BUGGERED