shithub: mc

Download patch

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