summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOri Bernstein <ori@eigenstate.org>2013-05-01 13:09:21 -0400
committerOri Bernstein <ori@eigenstate.org>2013-05-01 13:09:21 -0400
commita3b2e73283428008eebe4af1e57f41580b877cff (patch)
tree2318cccbcfe04a97f0c4be7c1c6da9028d4158f3
parent4e145a71d2753ca1c6f464375f220a145b9f1019 (diff)
parent8337ff18aea527cdb97c66da3b35de994fe1975c (diff)
downloadmc-a3b2e73283428008eebe4af1e57f41580b877cff.tar.gz
Merge branch 'master' of git+ssh://git.eigenstate.org/git/ori/mc
Conflicts: libstd/util.s
-rw-r--r--libstd/Makefile1
-rw-r--r--libstd/alloc.myr41
-rw-r--r--libstd/fmt.myr55
-rw-r--r--libstd/optparse.myr118
-rw-r--r--libstd/slappend.myr11
-rw-r--r--libstd/sys-linux.myr4
-rw-r--r--libstd/sys-osx.myr4
-rw-r--r--libstd/test.myr18
-rw-r--r--libstd/util.s16
-rw-r--r--parse/infer.c3
-rw-r--r--parse/use.c18
-rw-r--r--test/tests1
12 files changed, 212 insertions, 78 deletions
diff --git a/libstd/Makefile b/libstd/Makefile
index 07cdf65..3482cab 100644
--- a/libstd/Makefile
+++ b/libstd/Makefile
@@ -7,6 +7,7 @@ MYRSRC= \
fmt.myr \
optparse.myr \
rand.myr \
+ slappend.myr \
slurp.myr \
sys.myr \
types.myr \
diff --git a/libstd/alloc.myr b/libstd/alloc.myr
index 7ab8a68..e87b859 100644
--- a/libstd/alloc.myr
+++ b/libstd/alloc.myr
@@ -1,20 +1,19 @@
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
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 @@ pkg std =
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 Zchunk = 0 castto(chunk#)
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,33 +95,48 @@ generic slfree = {sl
}
/* 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
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 bytealloc = {sz
const bytefree = {m, sz
var bkt
- if (sz < Bucketmax)
+ if (sz < Bktmax)
bkt = &buckets[bktnum(sz)]
bktfree(bkt, m)
else
@@ -259,7 +276,7 @@ const bktnum = {sz
var bktsz
bktsz = Align
- for i = 0; bktsz <= Bucketmax; i++
+ for i = 0; bktsz <= Bktmax; i++
if bktsz >= sz
-> i
;;
diff --git a/libstd/fmt.myr b/libstd/fmt.myr
index ca77d28..4aba857 100644
--- 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 @@ use "extremum.use"
%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 @@ const bfmtv = {buf, fmt, ap
var w_val : int16
var i_val : int32
var l_val : int64
+ var z_val : size
var p_val : byte#
var c_val : char
@@ -79,6 +122,10 @@ const bfmtv = {buf, fmt, ap
(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)
n += intfmt(buf[n:], p_val castto(int64), 16)
diff --git a/libstd/optparse.myr b/libstd/optparse.myr
index 0bd1cfa..c06c6f5 100644
--- 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 = ""
+ ;;
+
+ if !ctx.curarg.len
+ next(ctx)
+ ;;
+
+ -> (c, arg)
+}
+
+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)
+ ;;
+ ;;
;;
- -> arg
+ -> (false, false)
}
-const nextopt = {ctx
+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
}
diff --git a/libstd/slappend.myr b/libstd/slappend.myr
new file mode 100644
index 0000000..eebdc5d
--- /dev/null
+++ b/libstd/slappend.myr
@@ -0,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
+}
diff --git a/libstd/sys-linux.myr b/libstd/sys-linux.myr
index e5aef80..70732c9 100644
--- a/libstd/sys-linux.myr
+++ b/libstd/sys-linux.myr
@@ -371,7 +371,7 @@ pkg std =
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 @@ pkg std =
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)}
diff --git a/libstd/sys-osx.myr b/libstd/sys-osx.myr
index 5ecc4a7..323045d 100644
--- a/libstd/sys-osx.myr
+++ b/libstd/sys-osx.myr
@@ -417,7 +417,7 @@ pkg std =
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 @@ pkg std =
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)}
diff --git a/libstd/test.myr b/libstd/test.myr
index b0ad950..4b142b7 100644
--- a/libstd/test.myr
+++ b/libstd/test.myr
@@ -4,22 +4,24 @@ const main = {args : byte[:][:]
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++
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. */
diff --git a/libstd/util.s b/libstd/util.s
index f56ea42..5e21575 100644
--- a/libstd/util.s
+++ b/libstd/util.s
@@ -14,19 +14,19 @@ _std$cstring:
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
diff --git a/parse/infer.c b/parse/infer.c
index e58c4dd..e05d7e8 100644
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -780,7 +780,7 @@ static void inferpat(Inferstate *st, Node *n, Node *val, Node ***bind, size_t *n
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 @@ static void stabsub(Inferstate *st, Stab *s)
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);
diff --git a/parse/use.c b/parse/use.c
index cd41da1..4b2226a 100644
--- a/parse/use.c
+++ b/parse/use.c
@@ -39,9 +39,9 @@ int loaduse(FILE *f, Stab *st)
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 @@ int loaduse(FILE *f, Stab *st)
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 @@ void readuse(Node *use, Stab *st)
/* Usefile format:
* U<pkgname>
- * T<typename><pickled-type>
+ * T<pickled-type>
* D<picled-decl>
* G<pickled-decl><pickled-initializer>
* Z
@@ -136,8 +142,8 @@ void writeuse(FILE *f, Node *file)
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);
diff --git a/test/tests b/test/tests
index 6171a95..e15c9f6 100644
--- a/test/tests
+++ b/test/tests
@@ -80,6 +80,7 @@ B infer-named E 99
B helloworld P Hello-世界
B catfile P Hello-世界
B encodechar P 1世界äa
+B exportcycle E 0
F declmismatch
F infermismatch
# F usedef ## BUGGERED