shithub: mc

Download patch

ref: 6e03c31865cf9167ec3e8743ed3700b3e7bcba2d
parent: 916167a53d09c9852020c5c75bfe2fe6744ddb0a
parent: 2acbf18832cedf7acdc3f6640d343b5f0feb1398
author: Ori Bernstein <[email protected]>
date: Wed Jun 20 07:47:02 EDT 2012

Merge branch 'master' of git+ssh://mimir.eigenstate.org/git/ori/mc2

Conflicts:
	8/main.c

--- a/8/isel.c
+++ b/8/isel.c
@@ -803,7 +803,7 @@
 
     is.curbb = is.bb[0];
     prologue(&is, fn->stksz);
-    for (j = 0; j < fn->cfg->nbb; j++) {
+    for (j = 0; j < fn->cfg->nbb - 1; j++) {
         is.curbb = is.bb[j];
         for (i = 0; i < fn->cfg->bb[j]->nnl; i++) {
             /* put in a comment that says where this line comes from */
@@ -817,7 +817,5 @@
     epilogue(&is);
     regalloc(&is);
 
-    if (debug)
-        writeasm(stdout, &is, fn);
     writeasm(fd, &is, fn);
 }
--- a/8/main.c
+++ b/8/main.c
@@ -12,11 +12,12 @@
 #include "parse.h"
 #include "opt.h"
 #include "asm.h"
+#include "platform.h"
 
 /* FIXME: move into one place...? */
 Node *file;
 int debug;
-int asmonly;
+char debugopt[128];
 char *outfile;
 char **incpaths;
 size_t nincpaths;
@@ -23,41 +24,27 @@
 
 static void usage(char *prog)
 {
-    printf("%s [-h] [-o outfile] inputs\n", prog);
+    printf("%s [-h] [-o outfile] [-d[dbgopts]] inputs\n", prog);
     printf("\t-h\tPrint this help\n");
     printf("\t-I path\tAdd 'path' to use search path\n");
-    printf("\t-d\tPrint debug dumps\n");
+    printf("\t-d\tPrint debug dumps. Recognized options: f r p i\n");
+    printf("\t\t\tno options: print most common debug information\n");
+    printf("\t\t\tf: additionally log folded trees\n");
+    printf("\t\t\tl: additionally log lowered pre-cfg trees\n");
+    printf("\t\t\tT: additionally log tree immediately\n");
+    printf("\t\t\tr: additionally log register allocation activity\n");
     printf("\t-o\tOutput to outfile\n");
     printf("\t-S\tGenerate assembly instead of object code\n");
 }
 
-char *outfmt(char *buf, size_t sz, char *infile, char *outfile)
+static void assem(char *f)
 {
-    char *p, *suffix;
-    size_t len;
+    char objfile[1024];
+    char cmd[1024];
 
-    if (outfile) {
-        snprintf(buf, sz, "%s", outfile);
-        return buf;
-    }
-
-    if (asmonly)
-        suffix = ".s";
-    else
-        suffix = ".o";
-
-    p = strrchr(infile, '.');
-    if (p)
-        len = (p - infile);
-    else
-        len = strlen(infile);
-    if (len + strlen(suffix) >= sz)
-        die("Output file name too long");
-    buf[0] = '\0';
-    strncat(buf, infile, len);
-    strcat(buf, suffix);
-
-    return buf;
+    swapsuffix(objfile, 1024, f, ".s", ".o");
+    snprintf(cmd, 1024, Asmcmd, objfile, f);
+    system(cmd);
 }
 
 int main(int argc, char **argv)
@@ -67,7 +54,7 @@
     Stab *globls;
     char buf[1024];
 
-    while ((opt = getopt(argc, argv, "dhSo:I:")) != -1) {
+    while ((opt = getopt(argc, argv, "d::hSo:I:")) != -1) {
         switch (opt) {
             case 'o':
                 outfile = optarg;
@@ -77,11 +64,10 @@
                 exit(0);
                 break;
             case 'd':
-                debug++;
+                debug = 1;
+                while (optarg && *optarg)
+                    debugopt[*optarg++ & 0x7f] = 1;
                 break;
-            case 'S':
-                asmonly++;
-                break;
             case 'I':
                 lappend(&incpaths, &nincpaths, optarg);
                 break;
@@ -102,7 +88,7 @@
         yyparse();
 
         /* before we do anything to the parse */
-        if (debug)
+        if (debugopt['T'])
             dump(file, stdout);
         infer(file);
         /* after all processing */
@@ -109,7 +95,9 @@
         if (debug)
             dump(file, stdout);
 
-        gen(file, outfmt(buf, 1024, argv[i], outfile));
+        swapsuffix(buf, 1024, argv[i], ".myr", ".s");
+        gen(file, buf);
+        assem(buf);
     }
 
     return 0;
--- a/8/platform.h
+++ b/8/platform.h
@@ -1,8 +1,9 @@
 #if defined(__APPLE__) && defined(__MACH__)
 /* for OSX */
+#   define Asmcmd "as -arch i386 -g -o %s %s"
 #   define Fprefix "_"
 #else
 /* Default to linux */
+#   define Asmcmd "as --32 -g -o %s %s"
 #   define Fprefix ""
 #endif
-#define Assembler "as --32 -g -o %s -"
--- a/8/ra.c
+++ b/8/ra.c
@@ -539,7 +539,7 @@
     size_t i, j;
     int has;
 
-    if (debug) {
+    if (debugopt['r']) {
 	printf("Combine ");
 	locprint(stdout, locmap[u]);
 	printf(" ==> ");
@@ -709,7 +709,7 @@
 	found = 0;
 	for (i = 0; i < K; i++) {
 	    if (!taken[i]) {
-		if (debug) {
+		if (debugopt['r']) {
 		    locprint(stdout, n);
 		    printf(" ==> %s\n", regnames[regmap[i][n->mode]]);
 		}
@@ -749,7 +749,7 @@
 	liveness(s);
 	build(s);
 	mkworklist(s);
-	if (debug)
+	if (debugopt['r'])
 	    dumpasm(s, stdout);
 	do {
 	    if (s->nwlsimp)
--- a/8/reduce.c
+++ b/8/reduce.c
@@ -56,6 +56,7 @@
 static Node *zero;
 static Node *ptrsz;
 static Type *tyword;
+static Type *tyvoid;
 
 static Type *base(Type *t)
 {
@@ -204,8 +205,7 @@
             return 2;
         case Tyint: case Tyint32:
         case Tyuint: case Tyuint32:
-        case Typtr: case Tyenum:
-        case Tyfunc:
+        case Typtr: case Tyfunc:
             return 4;
 
         case Tyint64: case Tylong:
@@ -347,10 +347,10 @@
 
     n = mkname(lit->line, genlblstr(lbl, 128));
     t = mkdecl(lit->line, n, lit->expr.type);
-    r = mkexpr(lit->line, Ovar, t, NULL);
-    t->decl.init = lit;
+    r = mkexpr(lit->line, Ovar, n, NULL);
+    r->expr.type = lit->expr.type;
     r->expr.did = t->decl.did;
-    r->expr.type = t->expr.type;
+    t->decl.init = lit;
     htput(s->globls, t, strdup(lbl));
     lappend(&s->blobs, &s->nblobs, t);
     return r;
@@ -529,11 +529,27 @@
     return r;
 }
 
+static Node *visit(Simp *s, Node *n)
+{
+    size_t i;
+    Node *r;
+
+    for (i = 0; i < n->expr.nargs; i++)
+        n->expr.args[i] = rval(s, n->expr.args[i]);
+    if (ispure(n)) {
+        r = n;
+    } else {
+        r = temp(s, n);
+        append(s, store(r, n));
+    }
+    return r;
+}
+
 static Node *rval(Simp *s, Node *n)
 {
     Node *r; /* expression result */
     Node *t, *u, *v; /* temporary nodes */
-    size_t i;
+    Type *ty;
     Node **args;
     const Op fusedmap[] = {
         [Oaddeq]        = Oadd,
@@ -665,15 +681,19 @@
               r = store(t, u);
             }
             break;
-        default:
-            for (i = 0; i < n->expr.nargs; i++)
-                n->expr.args[i] = rval(s, n->expr.args[i]);
-            if (ispure(n)) {
-                r = n;
-            } else {
+        case Ocall:
+            if (size(n) > 4) {
                 r = temp(s, n);
-                append(s, store(r, n));
+                ty = mktyptr(n->line, exprtype(r));
+                linsert(&args[0]->expr.args, &n->expr.nargs, 1, addr(r, ty));
+                linsert(&args[0]->expr.type->sub, &n->expr.type->nsub, 1, ty);
+                args[0]->expr.type->sub[0] = tyvoid;
+                n->expr.type = tyvoid;
             }
+            r = visit(s, n);
+            break;
+        default:
+            r = visit(s, n);
     }
     return r;
 }
@@ -683,7 +703,7 @@
     assert(n->type == Ndecl);
     s->stksz += size(n);
     if (debug)
-        printf("DECLARE %s(%ld) at %zd\n", declname(n), n->decl.did, s->stksz);
+        printf("declare %s(%ld) at %zd\n", declname(n), n->decl.did, s->stksz);
     htput(s->locs, n, (void*)s->stksz);
 }
 
@@ -691,7 +711,7 @@
 {
     assert(n->type == Ndecl);
     if (debug)
-        printf("DECLARE %s(%ld) at %zd\n", declname(n), n->decl.did, -(s->argsz + 8));
+        printf("declare %s(%ld) at %zd\n", declname(n), n->decl.did, -(s->argsz + 8));
     htput(s->locs, n, (void*)-(s->argsz + 8));
     s->argsz += size(n);
 }
@@ -778,6 +798,8 @@
     if(debug)
         printf("\n\nfunction %s\n", name);
 
+    if (!n->decl.init)
+        return NULL;
     /* set up the simp context */
     /* unwrap to the function body */
     n = n->expr.args[0];
@@ -790,12 +812,12 @@
     for (i = 0; i < s->nstmts; i++) {
         if (s->stmts[i]->type != Nexpr)
             continue;
-        if (debug) {
+        if (debugopt['f']) {
             printf("FOLD FROM ----------\n");
             dump(s->stmts[i], stdout);
         }
         s->stmts[i] = fold(s->stmts[i]);
-        if (debug) {
+        if (debugopt['f']) {
             printf("FOLD TO ------------\n");
             dump(s->stmts[i], stdout);
             printf("END ----------------\n");
@@ -850,11 +872,13 @@
     s.nblobs = *nblob;
 
     if (isconstfn(dcl)) {
-        f = lowerfn(&s, name, dcl->decl.init);
-        lappend(fn, nfn, f);
+        if (!dcl->decl.isextern) {
+            f = lowerfn(&s, name, dcl->decl.init);
+            lappend(fn, nfn, f);
+        }
     } else {
         if (dcl->decl.init && exprop(dcl->decl.init) == Olit)
-            lappend(blob, nblob, dcl);
+            lappend(&s.blobs, &s.nblobs, dcl);
         else
             die("We don't lower globls with nonlit inits yet...");
     }
@@ -871,10 +895,10 @@
     size_t nn, nfn, nblob;
     size_t i;
     FILE *fd;
-    char cmd[1024];
 
     /* declare useful constants */
     tyword = mkty(-1, Tyint);
+    tyvoid = mkty(-1, Tyvoid);
     one = word(-1, 1);
     zero = word(-1, 0);
     ptrsz = word(-1, 4);
@@ -903,21 +927,19 @@
         }
     }
 
-    sprintf(cmd, Assembler, out);
-    if (asmonly)
-      fd = fopen(out, "w");
-    else
-      fd = popen(cmd, "w");
+    fd = fopen(out, "w");
     if (!fd)
         die("Couldn't open fd %s", out);
 
+    if (debug) {
+        for (i = 0; i < nblob; i++)
+            genblob(stdout, blob[i], globls);
+        for (i = 0; i < nfn; i++)
+            genasm(stdout, fn[i], globls);
+    }
     for (i = 0; i < nblob; i++)
         genblob(fd, blob[i], globls);
     for (i = 0; i < nfn; i++)
         genasm(fd, fn[i], globls);
-    fflush(fd);
-    if (asmonly)
-      fclose(fd);
-    else
-      pclose(fd);
+    fclose(fd);
 }
--- a/mk/c.mk
+++ b/mk/c.mk
@@ -16,18 +16,14 @@
 all: subdirs $(BIN) $(LIB) $(EXTRA)
 install: subdirs-install install-bin install-lib install-hdr install-pc
 
-$(LIB): $(OBJ) libs
+$(LIB): $(OBJ) $(DEPS)
 	$(AR) -rcs $@ $(OBJ)
 
-$(BIN): $(OBJ) $(EXTRADEP) libs
+$(BIN): $(OBJ) $(EXTRADEP) $(DEPS)
 	$(CC) -o $@ $(OBJ) $(_LIBSRCHPATHS) $(_LIBPATHS)
 
-libs: $(DEPS)
-	@for i in $(dir $(DEPS)); do (\
-	    cd $$i && \
-	    $(MAKE) || \
-	    exit 1 \
-	) || exit 1; done
+$(DEPS):
+	@cd $(dir $@) && $(MAKE)
 
 subdirs:
 	@for i in $(SUB); do (\
--- a/parse/gram.y
+++ b/parse/gram.y
@@ -18,7 +18,7 @@
 int yylex(void);
 static Op binop(int toktype);
 Stab *curscope;
-//int n = 0;
+
 %}
 
 %token<tok> Terror
@@ -83,7 +83,6 @@
 %token<tok> Tchrlit
 %token<tok> Tboollit
 
-%token<tok> Tenum    /* enum */
 %token<tok> Tstruct  /* struct */
 %token<tok> Tunion   /* union */
 %token<tok> Ttyparam /* @typename */
@@ -113,7 +112,7 @@
 
 %start module
 
-%type <ty> type structdef uniondef enumdef compoundtype functype funcsig
+%type <ty> type structdef uniondef compoundtype functype funcsig
 %type <ty> generictype
 
 %type <tok> asnop cmpop addop mulop shiftop
@@ -123,11 +122,11 @@
 %type <node> exprln retexpr expr atomicexpr literal asnexpr lorexpr landexpr borexpr
 %type <node> bandexpr cmpexpr addexpr mulexpr shiftexpr prefixexpr postfixexpr
 %type <node> funclit arraylit name block blockbody stmt label use
-%type <node> decl declbody declcore structelt enumelt unionelt
+%type <node> decl declbody declcore structelt unionelt
 %type <node> ifstmt forstmt whilestmt elifs optexprln
 %type <node> castexpr
 
-%type <nodelist> arglist argdefs structbody enumbody unionbody params
+%type <nodelist> arglist argdefs structbody unionbody params
 
 %union {
     struct {
@@ -207,10 +206,11 @@
         | pkgbody pkgitem
         ;
 
-pkgitem : decl {putdcl(file->file.exports, $1);}
-        | tydef {puttype(file->file.exports, 
-                         mkname($1.line, $1.name),
-                         $1.type);}
+pkgitem : decl 
+            {putdcl(file->file.exports, $1);
+            if ($1->decl.init)
+                 lappend(&file->file.stmts, &file->file.nstmts, $1);}
+        | tydef {puttype(file->file.exports, mkname($1.line, $1.name), $1.type);}
         | visdef {die("Unimplemented visdef");}
         | Tendln
         ;
@@ -248,7 +248,6 @@
 
 type    : structdef
         | uniondef
-        | enumdef
         | compoundtype
         | generictype
         | Tellipsis {$$ = mkty($1->line, Tyvalist);}
@@ -283,6 +282,10 @@
              $$.nn = 0; lappend(&$$.nl, &$$.nn, $1);}
         | argdefs Tcomma declcore
             {lappend(&$$.nl, &$$.nn, $3);}
+        | /* empty */
+            {$$.line = line;
+             $$.nl = NULL;
+             $$.nn = 0;}
         ;
 
 structdef
@@ -323,24 +326,6 @@
             {$$ = NULL; die("unionelt impl");}
         | visdef Tendln
             {$$ = NULL;}
-        | Tendln
-            {$$ = NULL;}
-        ;
-
-enumdef : Tenum enumbody Tendblk
-            {$$ = mktyenum($1->line, $2.nl, $2.nn);}
-        ;
-
-enumbody: enumelt
-            {$$.nl = NULL; $$.nn = 0; if ($1) lappend(&$$.nl, &$$.nn, $1);}
-        | enumbody enumelt
-            {if ($2) {lappend(&$$.nl, &$$.nn, $2);}}
-        ;
-
-enumelt : Tident Tendln
-            {$$ = NULL; die("enumelt impl");}
-        | Tident Tasn exprln
-            {$$ = NULL; die("enumelt impl");}
         | Tendln
             {$$ = NULL;}
         ;
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -455,6 +455,9 @@
     if (n->decl.init) {
         inferexpr(n->decl.init, NULL, NULL);
         unify(n, type(n), type(n->decl.init));
+    } else {
+        if (n->decl.isconst && !n->decl.isextern)
+            fatal(n->line, "non-extern \"%s\" has no initializer", ctxstr(n));
     }
 }
 
@@ -474,9 +477,7 @@
 
 static void infernode(Node *n, Type *ret, int *sawret)
 {
-    void **k;
-    size_t i, nk;
-    Type *ty;
+    size_t i;
     Node *d;
     Node *s;
 
@@ -486,15 +487,7 @@
         case Nfile:
             pushstab(n->file.globls);
             /* exports allow us to specify types later in the body, so we
-             * need to patch the types in. */
-            k = htkeys(file->file.exports->ty, &nk);
-            for (i = 0; i < nk; i++) {
-                ty = gettype(file->file.globls, k[i]);
-                if (!ty) 
-                    fatal(((Node*)k[i])->line, "Exported type %s not declared", namestr(k[i]));
-                updatetype(file->file.exports, k[i], tf(ty));
-            }
-            free(k);
+             * need to patch the types in if they don't have a definition */
             inferstab(n->file.globls);
             inferstab(n->file.exports);
 	    for (i = 0; i < n->file.nstmts; i++) {
@@ -564,21 +557,16 @@
 static Type *tyfix(Node *ctx, Type *t)
 {
     static Type *tyint;
-    static Type *tyfloat;
     size_t i;
     char buf[1024];
 
     if (!tyint)
         tyint = mkty(-1, Tyint);
-    if (!tyfloat)
-        tyfloat = mkty(-1, Tyfloat64);
 
     t = tf(t);
     if (t->type == Tyvar) {
         if (hascstr(t, cstrtab[Tcint]) && cstrcheck(t, tyint))
             return tyint;
-        if (hascstr(t, cstrtab[Tcnum]) && cstrcheck(t, tyfloat))
-            return tyfloat;
     } else {
         if (t->type == Tyarray)
             typesub(t->asize);
@@ -728,11 +716,62 @@
     }
 }
 
+void mergeexports(Node *file)
+{
+    Stab *exports, *globls;
+    size_t i, nk;
+    void **k;
+    /* local, global version */
+    Node *nl, *ng;
+    Type *tl, *tg;
+
+    exports = file->file.exports;
+    globls = file->file.globls;
+
+    pushstab(globls);
+    k = htkeys(exports->ty, &nk);
+    for (i = 0; i < nk; i++) {
+        tl = gettype(exports, k[i]);
+        nl = k[i];
+        if (tl) {
+            tg = gettype(globls, nl);
+            if (!tg)
+                puttype(globls, nl, tl);
+            else
+                fatal(nl->line, "Exported type %s double-declared on line %d", namestr(nl), tg->line);
+        } else {
+            tg = gettype(globls, nl);
+            if (tg) 
+                updatetype(exports, nl, tf(tg));
+            else
+                fatal(nl->line, "Exported type %s not declared", namestr(nl));
+        }
+    }
+    free(k);
+
+    k = htkeys(exports->dcl, &nk);
+    for (i = 0; i < nk; i++) {
+        nl = getdcl(exports, k[i]);
+        ng = getdcl(globls, k[i]);
+        /* if an export has an initializer, it shouldn't be declared in the
+         * body */
+        if (nl->decl.init && ng)
+            fatal(nl->line, "Export %s double-defined on line %d", ctxstr(nl), ng->line);
+        if (!ng)
+            putdcl(globls, nl);
+        else
+            unify(nl, type(ng), type(nl));
+    }
+    free(k);
+    popstab();
+}
+
 void infer(Node *file)
 {
     assert(file->type == Nfile);
 
     loaduses(file);
+    mergeexports(file);
     infernode(file, NULL, NULL);
     infercompn(file);
     checkcast(file);
--- a/parse/node.c
+++ b/parse/node.c
@@ -279,7 +279,6 @@
     switch (t->type) {
         case Tystruct: return t->sdecls; break;
         case Tyunion: return t->udecls; break;
-        case Tyenum: return t->edecls; break;
         case Tyarray: return &t->asize; break;
         default: return NULL;
     }
--- a/parse/parse.h
+++ b/parse/parse.h
@@ -94,7 +94,7 @@
     int resolved;     /* Have we resolved the subtypes? Idempotent, but slow to repeat. */
     Bitset *cstrs;    /* the type constraints matched on this type */
     size_t nsub;      /* For compound types */
-    size_t nmemb;     /* for aggregate types (struct, union, enum) */
+    size_t nmemb;     /* for aggregate types (struct, union) */
     Type **sub;       /* sub-types; shared by all composite types */
     union {
         Node *name;    /* Tyname: unresolved name */
@@ -102,7 +102,6 @@
         char *pname;   /* Typaram: name of type parameter */
         Node **sdecls; /* Tystruct: decls in struct */
         Node **udecls; /* Tyunion: decls in union */
-        Node **edecls; /* Tyenum: decls in enum */
     };
 };
 
@@ -297,7 +296,6 @@
 Type *mktyfunc(int line, Node **args, size_t nargs, Type *ret);
 Type *mktystruct(int line, Node **decls, size_t ndecls);
 Type *mktyunion(int line, Node **decls, size_t ndecls);
-Type *mktyenum(int line, Node **decls, size_t ndecls);
 Cstr *mkcstr(int line, char *name, Node **memb, size_t nmemb, Node **funcs, size_t nfuncs);
 Type *tylike(Type *t, Ty ty); /* constrains tyvar t like it was builtin ty */
 int   istysigned(Type *t);
@@ -363,6 +361,7 @@
 
 /* convenience funcs */
 void lappend(void *l, size_t *len, void *n); /* ugly hack; nl is void* because void*** is incompatible with T*** */
+void linsert(void *l, size_t *len, size_t idx, void *n);
 void *lpop(void *l, size_t *len);
 void ldel(void *l, size_t *len, size_t idx);
 void lfree(void *l, size_t *len);
@@ -395,8 +394,12 @@
 void wrbool(FILE *fd, int val);
 int rdbool(FILE *fd);
 
+/* suffix replacement */
+char *swapsuffix(char *buf, size_t sz, char *s, char *suf, char *swap);
+
 /* Options to control the compilation */
 extern int debug;
+extern char debugopt[128];
 extern int asmonly;
 extern char *outfile;
 extern char **incpaths;
--- a/parse/pickle.c
+++ b/parse/pickle.c
@@ -152,11 +152,6 @@
             for (i = 0; i < ty->nmemb; i++)
                 pickle(ty->udecls[i], fd);
             break;
-        case Tyenum:
-            wrint(fd, ty->nmemb);
-            for (i = 0; i < ty->nmemb; i++)
-                pickle(ty->edecls[i], fd);
-            break;
         case Tyarray:
             wrtype(fd, ty->sub[0]);
             pickle(ty->asize, fd);
@@ -205,12 +200,6 @@
             ty->udecls = xalloc(ty->nmemb * sizeof(Node*));
             for (i = 0; i < ty->nmemb; i++)
                 ty->udecls[i] = unpickle(fd);
-            break;
-        case Tyenum:
-            ty->nmemb = rdint(fd);
-            ty->edecls = xalloc(ty->nmemb * sizeof(Node*));
-            for (i = 0; i < ty->nmemb; i++)
-                ty->edecls[i] = unpickle(fd);
             break;
         case Tyarray:
             ty->sub[0] = rdtype(fd);
--- a/parse/stab.c
+++ b/parse/stab.c
@@ -108,7 +108,7 @@
 
     d = getdcl(st, s->decl.name);
     if (d)
-        fatal(s->line, "%s already declared (line %d", namestr(s->decl.name), d->line);
+        fatal(s->line, "%s already declared (on line %d)", namestr(s->decl.name), d->line);
     if (st->name)
         setns(s->decl.name, namestr(st->name));
     htput(st->dcl, s->decl.name, s);
--- a/parse/tok.c
+++ b/parse/tok.c
@@ -141,7 +141,6 @@
         {"match",       Tmatch},
         {"default",     Tdefault},
         {"goto",        Tgoto},
-        {"enum",        Tenum},
         {"struct",      Tstruct},
         {"union",       Tunion},
         {"const",       Tconst},
--- a/parse/type.c
+++ b/parse/type.c
@@ -162,6 +162,7 @@
     Type *t;
 
     t = mkty(line, Tystruct);
+    t->nsub = 0;
     t->nmemb = ndecls;
     t->sdecls = memdup(decls, ndecls*sizeof(Node *));
     return t;
@@ -177,16 +178,6 @@
     return t;
 }
 
-Type *mktyenum(int line, Node **decls, size_t ndecls)
-{
-    Type *t;
-
-    t = mkty(line, Tyenum);
-    t->nmemb = ndecls;
-    t->edecls = decls;
-    return t;
-}
-
 int istysigned(Type *t)
 {
     switch (t->type) {
@@ -258,8 +249,8 @@
     end = p + len;
     p += snprintf(p, end - p, "struct ");
     for (i = 0; i < t->nmemb; i++) {
-        name = declname(t->edecls[i]);
-        ty = tystr(decltype(t->edecls[i]));
+        name = declname(t->sdecls[i]);
+        ty = tystr(decltype(t->sdecls[i]));
         p += snprintf(p, end - p, "%s:%s; ", name, ty);
         free(ty);
     }
@@ -272,19 +263,10 @@
     size_t i;
     *buf = 0;
     for (i = 0; i < t->nmemb; i++)
-        dump(t->sdecls[i], stdout);
+        dump(t->udecls[i], stdout);
     return 0;
 }
 
-static int fmtenum(char *buf, size_t len, Type *t)
-{
-    size_t i;
-    *buf = 0;
-    for (i = 0; i < t->nmemb; i++)
-        dump(t->sdecls[i], stdout);
-    return 0;
-}
-
 static int tybfmt(char *buf, size_t len, Type *t)
 {
     size_t i;
@@ -374,7 +356,6 @@
             break;
         case Tystruct:  p += fmtstruct(p, end - p, t);  break;
         case Tyunion:   p += fmtunion(p, end - p, t);   break;
-        case Tyenum:    p += fmtenum(p, end - p, t);    break;
         case Ntypes:
             die("Ntypes is not a type");
             break;
@@ -432,10 +413,6 @@
     tycstrs[Tyslice][0] = cstrtab[Tctest];
     tycstrs[Tyslice][1] = cstrtab[Tcslice];
     tycstrs[Tyslice][2] = cstrtab[Tcidx];
-
-    /* enum :: tcint, tcnum */
-    tycstrs[Tyenum][0] = cstrtab[Tcint];
-    tycstrs[Tyenum][1] = cstrtab[Tcnum];
 
     /* array :: tcidx, tcslice */
     tycstrs[Tyarray][0] = cstrtab[Tcidx];
--- a/parse/types.def
+++ b/parse/types.def
@@ -38,5 +38,4 @@
 Ty(Tyname, NULL)
 Ty(Tystruct, NULL)
 Ty(Tyunion, NULL)
-Ty(Tyenum, NULL)
 Ty(Ntypes, NULL)
--- a/parse/use.c
+++ b/parse/use.c
@@ -118,7 +118,7 @@
 
     k = htkeys(st->ty, &n);
     for (i = 0; i < n; i++) {
-	t = htget(st->ty, k[i]);
+	t = gettype(st, k[i]);
 	wrbyte(f, 'T');
         wrstr(f, namestr(k[i]));
 	typickle(t, f);
--- a/parse/util.c
+++ b/parse/util.c
@@ -129,6 +129,20 @@
     return v;
 }
 
+void linsert(void *p, size_t *len, size_t idx, void *v)
+{
+    void ***pl, **l;
+    size_t i;
+
+    pl = p;
+    *pl = xrealloc(*pl, (*len + 1)*sizeof(void*));
+    l = *pl;
+    for (i = idx; i < *len; i++)
+        l[i + 1] = l[i];
+    l[idx] = v;
+    (*len)++;
+}
+
 void ldel(void *l, size_t *len, size_t idx)
 {
     void ***pl;
@@ -322,5 +336,30 @@
 int rdbool(FILE *fd)
 {
     return rdbyte(fd);
+}
+
+char *swapsuffix(char *buf, size_t sz, char *s, char *suf, char *swap)
+{
+    size_t slen, suflen, swaplen;
+
+    slen = strlen(s);
+    suflen = strlen(suf);
+    swaplen = strlen(swap);
+
+    if (slen < suflen)
+        return NULL;
+    if (slen + swaplen >= sz)
+        die("swapsuffix: buf too small");
+
+    buf[0] = '\0';
+    if (suflen < slen && !strcmp(suf, &s[slen - suflen])) {
+        strncat(buf, s, slen - suflen);
+        strcat(buf, swap);
+    } else {
+        strncat(buf, s, slen);
+        strcat(buf, swap);
+    }
+
+    return buf;
 }
 
--- a/test/Makefile
+++ b/test/Makefile
@@ -1,11 +1,12 @@
 # don't build anything for 'all'
 all: 
+	$(MAKE) -C ..
 
 check:
 	./test.sh
 .PHONY: clean
 clean:
-	@for i in `awk '{print $$1}' tests`; do \
+	@for i in `awk '/^[A-Z]/{print $$2}' tests`; do \
 	    echo rm -f $$i; \
 	    rm -f $$i; \
 	done
--- /dev/null
+++ b/test/arraylen.myr
@@ -1,0 +1,5 @@
+const main = {
+	var a : int[12]
+
+	-> a.len
+}
--- /dev/null
+++ b/test/generic.myr
@@ -1,0 +1,13 @@
+generic max = {a:@a::tcnum, b::@a::tcnum
+	if (a > b)
+		-> a
+	else
+		-> b
+	;;
+}
+
+const main = {
+	max('a', 'b')
+	-> max(1, 2)
+}
+
--- /dev/null
+++ b/test/hello/Makefile
@@ -1,0 +1,11 @@
+# don't build anything for 'all'
+all: 
+	./bld.sh
+.PHONY: clean
+clean:
+	@for i in `awk '{print $$1}' tests`; do \
+	    echo rm -f $$i; \
+	    rm -f $$i; \
+	done
+
+install:
--- /dev/null
+++ b/test/hello/bld.sh
@@ -1,0 +1,36 @@
+#!/bin/bash
+
+# We have no dependency handling yet, so this is done via
+# a shell script. Also, we want to rebuild everything for
+# testing purposes on every run as things stand.
+
+export PATH=.:$PATH
+export MC=../../8/8m
+export MU=../../util/muse
+export CC=cc
+export ASOPT="-g"
+
+function use {
+    N=`basename $1 .myr`
+
+    echo $MU $1 -o $N.use && \
+    $MU $1 -o $N.use
+}
+
+function build {
+    N=`basename $1 .myr`
+
+    echo $MC $1 && \
+    $MC $1 -I.
+}
+
+function assem {
+    $CC $ASOPT -m32 -c $1
+}
+
+assem syscall.s
+use sys.myr
+build sys.myr
+build hello.myr
+
+$CC -m32 -o hello sys.o hello.o syscall.o
--- /dev/null
+++ b/test/hello/hello.myr
@@ -1,0 +1,5 @@
+use "sys.use"
+
+const main = {
+	sys.write(1, "Hello world\n")
+}
--- /dev/null
+++ b/test/hello/sys.myr
@@ -1,0 +1,69 @@
+
+pkg sys =
+	type scno = int
+	type fdopt = int
+	type statbuf = struct
+		 dev     : uint
+		 ino     : uint
+		 mode    : uint16
+		 nlink   : uint16
+		 uid     : uint16
+		 gid     : uint16
+		 rdev    : uint
+		 size    : uint
+		 blksize : uint
+		 blocks  : uint
+		 atime   : uint
+		 atimens : uint
+		 mtime   : uint
+		 mtimens : uint
+		 ctime   : uint
+		 ctimens : uint
+		 _unused1: uint
+		 _unused2: uint
+	;;
+
+	const Rdonly  	: fdopt = 0x0
+	const Wronly  	: fdopt = 0x1
+	const Rdwr    	: fdopt = 0x2
+	const Append  	: fdopt = 0x80
+	const Creat   	: fdopt = 0x40
+	const Nofollow	: fdopt = 0x20000
+	const Ndelay  	: fdopt = 0x800
+	const Trunc   	: fdopt = 0x200
+
+	const Sysexit	: scno = 1
+	const Sysread	: scno = 3
+	const Syswrite	: scno = 4
+	const Sysopen	: scno = 5
+	const Sysclose	: scno = 6
+	const Syscreat	: scno = 8
+	const Syslseek	: scno = 19
+	const Sysfstat	: scno = 108
+	const Syskill	: scno = 37
+	const Sysgetpid	: scno = 20
+
+	extern const syscall : (sc:scno, count:int, args:... -> int)
+
+	const exit	: (status:int -> int)
+	const getpid	: ( -> int)
+	const kill	: (pid:int, sig:int -> int)
+	const open	: (path:char[,], opts:fdopt -> int)
+	const close	: (fd:int -> int)
+	const creat	: (path:char[,], mode:int -> int)
+	const read	: (fd:int, buf:char[,] -> int)
+	const write	: (fd:int, buf:char[,] -> int)
+	const lseek	: (fd:int, off:uint, whence:int -> int)
+	const fstat	: (fd:int, sb:statbuf* -> int)
+;;
+
+const exit	= {status;		-> syscall(Sysexit, 1);}
+const getpid	= {;			-> syscall(Sysgetpid, 1);}
+const kill	= {pid, sig;		-> syscall(Syskill,  2, pid, sig);}
+const open	= {path, opts:fdopt;	-> syscall(Sysopen,  2, path castto(char*), opts);}
+const close	= {fd;			-> syscall(Sysclose, 1, fd);}
+const creat	= {path, mode;		-> syscall(Syscreat, 2, path castto(char*), mode);}
+const read	= {fd, buf;		-> syscall(Sysread,  3, fd, buf castto(char*), buf.len);}
+const write	= {fd, buf;		-> syscall(Syswrite, 3, fd, buf castto(char*), buf.len);}
+const lseek	= {fd, off:uint, whence;-> syscall(Syslseek, 2, fd, off, whence);}
+const fstat	= {fd, sb;		-> syscall(Sysfstat, 2, fd, sb);}
--- /dev/null
+++ b/test/hello/syscall.s
@@ -1,0 +1,24 @@
+.globl sys$syscall
+sys$syscall:
+	pushl %ebp
+	movl %esp,%ebp
+	movl 12(%ebp),%eax #count
+        shl  $2,%eax
+	jmp  *.jmptab(%eax)
+.jmptab:
+	.long .a0
+	.long .a1
+	.long .a2
+	.long .a3
+	.long .a4
+.a5:	movl 32(%ebp),%edi
+.a4:	movl 28(%ebp),%esi
+.a3:	movl 24(%ebp),%edx
+.a2:	movl 20(%ebp),%ecx
+.a1:	movl 16(%ebp),%ebx
+	/* 12(%ebp) holds nargs */
+.a0:	movl 8(%ebp),%eax
+        int $0x80
+	movl %ebp,%esp
+	popl %ebp
+	ret
--- /dev/null
+++ b/test/slicelen.myr
@@ -1,0 +1,7 @@
+const main = {
+	var a : int[8]
+	var s
+
+	s = a[1,6]
+	-> s.len
+}
--- /dev/null
+++ b/test/str.myr
@@ -1,0 +1,6 @@
+const main = {
+	var str
+
+	str = "asdf"
+	-> str[3]
+}
--- /dev/null
+++ b/test/structret.myr
@@ -1,0 +1,19 @@
+type pair = struct
+	a : int
+	b : int
+;;
+
+const f = {
+	var s
+
+	s.a = 12
+	s.b = 30
+	-> s
+}
+
+const main = {
+	var s : pair
+
+	s = f()
+	-> s.a + s.b
+}
--- a/test/tests
+++ b/test/tests
@@ -21,15 +21,18 @@
 B bsr     	E       5
 B struct1	E	12
 B struct	E	42
+B structasn	E       42
+B structret	E	42
 B array		E	7
 B arraylen	E	12
+B slice		E	7
+B slicelen	E	5
 B call		E	42
+B voidcall	E	12
 B callbig	E	42
 B loop		E	45
 B fib		E	21
-B slice		E	7
 B float   	E       1
-B structasn	E       42
 B log-and 	E       0
 B log-or  	E       1
 B str   	E       102
--- /dev/null
+++ b/test/voidcall.myr
@@ -1,0 +1,10 @@
+const f = {
+	var a
+
+	a = a + 1
+}
+
+const main = {
+	f()
+	-> 12
+}
--- a/util/muse.c
+++ b/util/muse.c
@@ -15,6 +15,7 @@
 Node *file;
 char *outfile;
 int debug;
+char debugopt[128];
 char **incpaths;
 size_t nincpaths;
 
@@ -32,13 +33,12 @@
 {
     int opt;
     int i;
-    Stab *s;
     Stab *globls;
     Node *rdback;
     FILE *tmp;
     FILE *f;
 
-    while ((opt = getopt(argc, argv, "dho:")) != -1) {
+    while ((opt = getopt(argc, argv, "d::ho:I:")) != -1) {
         switch (opt) {
             case 'o':
                 outfile = optarg;
@@ -45,7 +45,9 @@
                 break;
             case 'h':
             case 'd':
-                debug++;
+                debug = 1;
+                while (optarg && *optarg)
+                    debugopt[*optarg++ & 0x7f] = 1;
                 break;
 	    case 'I':
 		lappend(&incpaths, &nincpaths, optarg);
@@ -68,7 +70,7 @@
 
         infer(file);
 	/* before we do anything to the parse */
-        if (debug) {
+        if (debugopt['p']) {
             /* test storing tree to file */
             tmp = fopen("a.pkl", "w");
             pickle(file, tmp);
@@ -86,9 +88,6 @@
 	f = fopen(outfile, "w");
 	writeuse(file, f);
 	fclose(f);
-        s = mkstab();
-	readuse(mkuse(-1, outfile, 1), s);
-        dumpstab(s, stdout);
     }
 
     return 0;