shithub: mc

Download patch

ref: 47e2fe4b898f4260414f84424929d8a7e09cd021
parent: 9ab2a5a2a341794f93df6aee3859c90bbae3a9b0
author: Ori Bernstein <[email protected]>
date: Wed Jun 27 19:52:02 EDT 2012

Work towards supporting unions.

    Add ucon type, and work it in. This meant a bit of reworking how
    structs and such work.

--- a/8/reduce.c
+++ b/8/reduce.c
@@ -373,7 +373,7 @@
 {
     Type *ty;
     Node **nl;
-    size_t nn, i;
+    size_t i;
     size_t off;
 
     if (aggr->expr.type->type == Typtr)
@@ -382,9 +382,9 @@
     ty = tybase(ty);
 
     assert(ty->type == Tystruct);
-    nl = aggrmemb(ty, &nn);
+    nl = ty->sdecls;
     off = 0;
-    for (i = 0; i < nn; i++) {
+    for (i = 0; i < ty->nmemb; i++) {
         if (!strcmp(namestr(memb), declname(nl[i])))
             return off;
         off += size(nl[i]);
--- a/parse/gram.y
+++ b/parse/gram.y
@@ -18,6 +18,7 @@
 int yylex(void);
 static Op binop(int toktype);
 static Node *mkpseudodecl(Type *t);
+static void installucons(Stab *st, Type *t);
 Stab *curscope;
 
 %}
@@ -125,11 +126,13 @@
 %type <node> exprln retexpr expr atomicexpr literal asnexpr lorexpr landexpr borexpr
 %type <node> bandexpr cmpexpr unioncons addexpr mulexpr shiftexpr prefixexpr postfixexpr
 %type <node> funclit arraylit name block blockbody stmt label use
-%type <node> decl declbody declcore structelt unionelt
+%type <node> decl declbody declcore structelt
 %type <node> ifstmt forstmt whilestmt elifs optexprln
 %type <node> castexpr
+%type <ucon> unionelt
 
-%type <nodelist> arglist argdefs structbody unionbody params
+%type <nodelist> arglist argdefs structbody params
+%type <uconlist> unionbody
 
 %union {
     struct {
@@ -139,6 +142,11 @@
     } nodelist;
     struct {
         int line;
+        Ucon **ucl;
+        size_t nucl;
+    } uconlist;
+    struct {
+        int line;
         Type **types;
         size_t ntypes;
     } tylist;
@@ -150,6 +158,7 @@
     Node *node;
     Tok  *tok;
     Type *ty;
+    Ucon *ucon;
 }
 
 %%
@@ -170,7 +179,8 @@
             {lappend(&file->file.uses, &file->file.nuses, $1);}
         | package
         | tydef
-            {puttype(file->file.globls, mkname($1.line, $1.name), $1.type);}
+            {puttype(file->file.globls, mkname($1.line, $1.name), $1.type);
+             installucons(file->file.globls, $1.type);}
         | Tendln
         ;
 
@@ -315,22 +325,22 @@
 
 uniondef
         : Tunion unionbody Tendblk
-            {$$ = mktyunion($1->line, $2.nl, $2.nn);}
+            {$$ = mktyunion($1->line, $2.ucl, $2.nucl);}
         ;
 
 unionbody
         : unionelt
-            {$$.nl = NULL; $$.nn = 0;
-             if ($1) {lappend(&$$.nl, &$$.nn, $1);}}
+            {$$.ucl = NULL; $$.nucl = 0;
+             if ($1) {lappend(&$$.ucl, &$$.nucl, $1);}}
         | unionbody unionelt
-            {if ($2) {lappend(&$$.nl, &$$.nn, $2);}}
+            {if ($2) {lappend(&$$.ucl, &$$.nucl, $2);}}
         ;
 
-unionelt
+unionelt /* nb: the ucon union type gets filled in when we have context */
         : Ttick Tident type Tendln
-            {$$ = mkdecl($2->line, mkname($2->line, $2->str), $3);}
+            {$$ = mkucon($2->line, mkname($2->line, $2->str), NULL, $3);}
         | Ttick Tident Tendln
-            {$$ = mkdecl($2->line, mkname($2->line, $2->str), NULL);}
+            {$$ = mkucon($2->line, mkname($2->line, $2->str), NULL, NULL);}
         | visdef Tendln
             {$$ = NULL;}
         | Tendln
@@ -580,6 +590,19 @@
     return mkdecl(-1, mkname(-1, buf), t);
 }
 
+static void installucons(Stab *st, Type *t)
+{
+    Type *b;
+    size_t i;
+
+    b = tybase(t);
+    if (b->type != Tyunion)
+        return;
+    for (i = 0; i < b->nmemb; i++) {
+        b->udecls[i]->utype = t;
+        putucon(st, b->udecls[i]);
+    }
+}
 
 void yyerror(const char *s)
 {
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -87,19 +87,29 @@
 
 static void tyresolve(Type *t)
 {
-    size_t i, nn;
+    size_t i;
     Type *base;
-    Node **n;
 
     if (t->resolved)
         return;
     t->resolved = 1;
-    n = aggrmemb(t, &nn);
-    for (i = 0; i < nn; i++)
-        infernode(n[i], NULL, NULL);
+    if (t->type == Tystruct) {
+        for (i = 0; i < t->nmemb; i++)
+            infernode(t->sdecls[i], NULL, NULL);
+    } else if (t->type == Tyunion) {
+        for (i = 0; i < t->nmemb; i++) {
+            tyresolve(t->udecls[i]->utype);
+            if (t->udecls[i]->etype)
+                tyresolve(t->udecls[i]->etype);
+        }
+    } else if (t->type == Tyarray) {
+        infernode(t->asize, NULL, NULL);
+    }
+
     for (i = 0; i < t->nsub; i++)
         t->sub[i] = tf(t->sub[i]);
     base = tybase(t);
+    /* no-ops if base == t */
     if (t->cstrs)
         bsunion(t->cstrs, base->cstrs);
     else
@@ -720,7 +730,7 @@
 
 static void infercompn(Node *file)
 {
-    size_t i, j, nn;
+    size_t i, j;
     Node *aggr;
     Node *memb;
     Node *n;
@@ -747,10 +757,11 @@
                 found = 1;
             }
         } else {
+            t = tybase(t);
             if (t->type == Typtr)
                 t = tf(t->sub[0]);
-            nl = aggrmemb(t, &nn);
-            for (j = 0; j < nn; j++) {
+            nl = t->sdecls;
+            for (j = 0; j < t->nmemb; j++) {
                 if (!strcmp(namestr(memb), declname(nl[j]))) {
                     unify(n, type(n), decltype(nl[j]));
                     found = 1;
--- a/parse/node.c
+++ b/parse/node.c
@@ -219,6 +219,18 @@
     return n;
 }
 
+Ucon *mkucon(int line, Node *name, Type *ut, Type *et)
+{
+    Ucon *uc;
+
+    uc = zalloc(sizeof(Ucon));
+    uc->line = line;
+    uc->name = name;
+    uc->utype = ut;
+    uc->etype = et;
+    return uc;
+}
+
 Node *mkbool(int line, int val)
 {
     Node *n;
--- a/parse/parse.h
+++ b/parse/parse.h
@@ -10,6 +10,7 @@
 
 typedef struct Tok Tok;
 typedef struct Node Node;
+typedef struct Ucon Ucon;
 typedef struct Stab Stab;
 
 typedef struct Type Type;
@@ -78,10 +79,11 @@
 
     /* Contents of stab.
      * types and values are in separate namespaces. */
-    Htab *ns;
     Htab *dcl;
     Htab *closure; /* the syms we close over */
+    Htab *ns;
     Htab *ty;
+    Htab *uc;
 };
 
 struct Type {
@@ -99,10 +101,18 @@
         Node *asize;   /* array size */
         char *pname;   /* Typaram: name of type parameter */
         Node **sdecls; /* Tystruct: decls in struct */
-        Node **udecls; /* Tyunion: decls in union */
+        Ucon **udecls; /* Tyunion: decls in union */
     };
 };
 
+struct Ucon {
+    int line;
+    size_t id;
+    Node *name;
+    Type *utype;
+    Type *etype;
+};
+
 struct Cstr {
     int cid;    /* unique id */
     char *name;
@@ -194,6 +204,13 @@
         } decl;
 
         struct {
+            long  uid;
+            Node *name;
+            Type *elt;
+            Type *alt;
+        } uelt;
+
+        struct {
             Stab *scope;
             Type *type;
             size_t nargs;
@@ -271,11 +288,13 @@
 void putns(Stab *st, Stab *scope);
 void puttype(Stab *st, Node *n, Type *ty);
 void updatetype(Stab *st, Node *n, Type *t);
-void putdcl(Stab *st, Node *s);
+void putdcl(Stab *st, Node *dcl);
+void putucon(Stab *st, Ucon *uc);
 
 Stab *getns(Stab *st, Node *n);
 Node *getdcl(Stab *st, Node *n);
 Type *gettype(Stab *st, Node *n);
+Ucon *getucon(Stab *st, Node *n);
 
 Stab *curstab(void);
 void pushstab(Stab *st);
@@ -296,7 +315,7 @@
 Type *mktyptr(int line, Type *base);
 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 *mktyunion(int line, Ucon **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);
@@ -332,6 +351,7 @@
 Node *mkdecl(int line, Node *name, Type *ty);
 Node *mklbl(int line, char *lbl);
 Node *mkslice(int line, Node *base, Node *off);
+Ucon *mkucon(int line, Node *name, Type *ut, Type *uet);
 
 /* node util functions */
 char *namestr(Node *name);
@@ -343,7 +363,6 @@
 void setns(Node *n, char *ns);
 void updatens(Stab *st, char *ns);
 Op exprop(Node *n);
-Node **aggrmemb(Type *t, size_t *n);
 
 /* specialize generics */
 Node *specializedcl(Node *n, Type *to, Node **name);
--- a/parse/pickle.c
+++ b/parse/pickle.c
@@ -82,6 +82,33 @@
     return st;
 }
 
+static void wrucon(FILE *fd, Ucon *uc)
+{
+    wrint(fd, uc->line);
+    wrint(fd, uc->id);
+    pickle(uc->name, fd);
+    wrtype(fd, uc->utype);
+    wrtype(fd, uc->etype);
+}
+
+static Ucon *rducon(FILE *fd)
+{
+    Type *ut, *et;
+    Node *name;
+    Ucon *uc;
+    size_t id;
+    int line;
+
+    line = rdint(fd);
+    id = rdint(fd);
+    name = unpickle(fd);
+    ut = rdtype(fd);
+    et = rdtype(fd);
+    uc = mkucon(line, name, ut, et);
+    uc->id = id;
+    return uc;
+}
+
 static void wrsym(FILE *fd, Node *val)
 {
     /* sym */
@@ -150,7 +177,7 @@
         case Tyunion:
             wrint(fd, ty->nmemb);
             for (i = 0; i < ty->nmemb; i++)
-                pickle(ty->udecls[i], fd);
+                wrucon(fd, ty->udecls[i]);
             break;
         case Tyarray:
             wrtype(fd, ty->sub[0]);
@@ -199,7 +226,7 @@
             ty->nmemb = rdint(fd);
             ty->udecls = xalloc(ty->nmemb * sizeof(Node*));
             for (i = 0; i < ty->nmemb; i++)
-                ty->udecls[i] = unpickle(fd);
+                ty->udecls[i] = rducon(fd);
             break;
         case Tyarray:
             ty->sub[0] = rdtype(fd);
--- a/parse/stab.c
+++ b/parse/stab.c
@@ -62,6 +62,7 @@
     st->ns = mkht(namehash, nameeq);
     st->dcl = mkht(namehash, nameeq);
     st->ty = mkht(namehash, nameeq);
+    st->uc = mkht(namehash, nameeq);
     return st;
 }
 
@@ -98,6 +99,18 @@
     return NULL;
 }
 
+Ucon *getucon(Stab *st, Node *n)
+{
+    Ucon *uc;
+    
+    do {
+        if ((uc = htget(st->uc, n)))
+            return uc;
+        st = st->super;
+    } while (st);
+    return NULL;
+}
+
 Cstr *getcstr(Stab *st, Node *n)
 {
     Cstrdefn *c;
@@ -154,6 +167,13 @@
     td->name = n;
     td->type = t;
     htput(st->ty, td->name, td);
+}
+
+void putucon(Stab *st, Ucon *uc)
+{
+    if (getucon(st, uc->name))
+        fatal(uc->line, "union constructor %s already defined", namestr(uc->name));
+    htput(st->uc, uc->name, uc);
 }
 
 void putcstr(Stab *st, Node *n, Cstr *c)
--- a/parse/type.c
+++ b/parse/type.c
@@ -202,7 +202,7 @@
     return t;
 }
 
-Type *mktyunion(int line, Node **decls, size_t ndecls)
+Type *mktyunion(int line, Ucon **decls, size_t ndecls)
 {
     Type *t;
 
@@ -230,18 +230,6 @@
     return t;
 }
 
-Node **aggrmemb(Type *t, size_t *n)
-{
-    t = tybase(t);
-    *n = t->nmemb;
-    switch (t->type) {
-        case Tystruct:  return t->sdecls;               break;
-        case Tyunion:   return t->udecls;               break;
-        case Tyarray:   return &t->asize;               break;
-        default: return NULL;
-    }
-}
-
 static int namefmt(char *buf, size_t len, Node *n)
 {
     char *p;
@@ -314,10 +302,20 @@
 static int fmtunion(char *buf, size_t len, Type *t)
 {
     size_t i;
-    *buf = 0;
-    for (i = 0; i < t->nmemb; i++)
-        dump(t->udecls[i], stdout);
-    return 0;
+    char *end, *p;
+    char *name, *ty;
+
+    p = buf;
+    end = p + len;
+    p += snprintf(p, end - p, "struct ");
+    for (i = 0; i < t->nmemb; i++) {
+        name = namestr(t->udecls[i]->name);
+        ty = tystr(t->udecls[i]->etype);
+        p += snprintf(p, end - p, "`%s %s; ", name, ty);
+        free(ty);
+    }
+    p += snprintf(p, end - p, ";;");
+    return p - buf;
 }
 
 static int tybfmt(char *buf, size_t len, Type *t)