shithub: mc

Download patch

ref: b51499422cb9bfaf5c533c875fdc30ddbc3d86a4
parent: 0b71df23363b948afdb16b5f08dcbc1508278a6b
author: Ori Bernstein <[email protected]>
date: Tue Oct 14 22:28:15 EDT 2014

Start work on new pattern matching implementation.

    At the moment, it gives useful warnings, so we might as well
    enable it. Later, we'll make it actually generate useful code.

--- a/6/simp.c
+++ b/6/simp.c
@@ -553,6 +553,16 @@
             die("Unsupported type for pattern");
             break;
         /* only valid for string literals */
+        case Tybool: case Tychar: case Tybyte:
+        case Tyint8: case Tyint16: case Tyint32: case Tyint:
+        case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint:
+        case Tyint64: case Tyuint64: case Tylong:  case Tyulong:
+        case Tyflt32: case Tyflt64:
+        case Typtr: case Tyfunc:
+            v = mkexpr(pat->loc, Oeq, pat, val, NULL);
+            v->expr.type = mktype(pat->loc, Tybool);
+            cjmp(s, v, iftrue, iffalse);
+            break;
         case Tyslice:
             lit = pat->expr.args[0];
             if (exprop(pat) != Olit || lit->lit.littype != Lstr)
@@ -583,16 +593,6 @@
             }
             jmp(s, iftrue);
             break;
-        case Tybool: case Tychar: case Tybyte:
-        case Tyint8: case Tyint16: case Tyint32: case Tyint:
-        case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint:
-        case Tyint64: case Tyuint64: case Tylong:  case Tyulong:
-        case Tyflt32: case Tyflt64:
-        case Typtr: case Tyfunc:
-            v = mkexpr(pat->loc, Oeq, pat, val, NULL);
-            v->expr.type = mktype(pat->loc, Tybool);
-            cjmp(s, v, iftrue, iffalse);
-            break;
         /* We got lucky. The structure of tuple, array, and struct literals
          * is the same, so long as we don't inspect the type, so we can
          * share the code*/
@@ -648,6 +648,7 @@
     Node *m;
     size_t i;
 
+    gensimpmatch(n);
     end = genlbl(n->loc);
     val = temp(s, n->matchstmt.val);
     tmp = rval(s, n->matchstmt.val, val);
--- a/opt/Makefile
+++ b/opt/Makefile
@@ -1,6 +1,7 @@
 LIB=libmi.a
 OBJ=cfg.o \
     fold.o \
+    match.o \
     df.o \
 
 DEPS=../parse/libparse.a
--- /dev/null
+++ b/opt/match.c
@@ -1,0 +1,159 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "parse.h"
+#include "opt.h"
+
+typedef struct Dtree Dtree;
+struct Dtree {
+    /* If the values are equal, go to 'sub'. If 'val' is null, anything matches. */
+    Node **val;
+    size_t nval;
+    Dtree **sub;
+    size_t nsub;
+    Dtree *any;
+
+    /* captured variables and action */
+    Node **cap;
+    size_t ncap;
+    Node *act;
+
+};
+
+static Dtree *addpat(Dtree *t, Node *pat, Node ***cap, size_t *ncap);
+
+static Dtree *mkdtree()
+{
+    return zalloc(sizeof(Dtree));
+}
+
+static int uconeq(Node *a, Node *b)
+{
+    return !strcmp(namestr(a), namestr(b));
+}
+
+static Dtree *addunion(Dtree *t, Node *pat, Node ***cap, size_t *ncap)
+{
+    Dtree *sub;
+    size_t i;
+
+    /* if we have the value already... */
+    sub = NULL;
+    for (i = 0; i < t->nval; i++) {
+        if (!t->val[i])
+            fatal(pat, "constructor already matched by earlier variable");
+        if (uconeq(t->val[i], pat->expr.args[0])) {
+            return addpat(t->sub[i], pat->expr.args[1], cap, ncap);
+        }
+    }
+
+    sub = mkdtree();
+    lappend(&t->val, &t->nval, pat->expr.args[0]);
+    lappend(&t->sub, &t->nsub, sub);
+    if (pat->expr.nargs == 2)
+        sub = addpat(sub, pat->expr.args[1], cap, ncap);
+    return sub;
+}
+
+static Dtree *addwild(Dtree *t, Node *var, Node ***cap, size_t *ncap)
+{
+    if (t->any)
+        return t->any;
+    t->any = mkdtree();
+    lappend(cap, ncap, var);
+    return t->any;
+}
+
+static Dtree *addpat(Dtree *t, Node *pat, Node ***cap, size_t *ncap)
+{
+    Type *ty;
+
+    if (pat == NULL)
+        return t;
+    ty = tybase(exprtype(pat));
+    if (exprop(pat) == Ovar)
+        return addwild(t, pat, cap, ncap);
+
+    switch (ty->type) {
+        case Tyunion:
+            t = addunion(t, pat, cap, ncap);
+            break;
+            /*
+        case Tyslice:
+            t = addslice(t, pat);
+            break;
+        case Tytuple:
+            t = addtuple(t, pat);
+            break;
+        case Tyarray:
+            t = addtuple(t, pat);
+            break;
+        case Tystruct:
+            t = addstruct(t, pat);
+
+        case Tybool: case Tychar: case Tybyte:
+        case Tyint8: case Tyint16: case Tyint32: case Tyint:
+        case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint:
+        case Tyint64: case Tyuint64: case Tylong:  case Tyulong:
+        case Tyflt32: case Tyflt64:
+        case Typtr: case Tyfunc:
+            t = addlit(t, pat);
+            break;
+
+            */
+        default:
+            /* Right now, we just use this code for warning. */
+            /*
+            fatal(pat, "unsupported match type %s", tystr(ty));
+            */
+            return NULL;
+            break;
+    }
+
+    return t;
+}
+
+static void checkcomprehensive(Dtree *dt)
+{
+}
+
+static Node *genmatch(Dtree *dt)
+{
+    return NULL;
+}
+
+Node *gensimpmatch(Node *m)
+{
+    Dtree *t, *leaf;
+    Node **pat, **cap;
+    size_t npat, ncap;
+    size_t i;
+
+    t = mkdtree();
+    pat = m->matchstmt.matches;
+    npat = m->matchstmt.nmatches;
+    cap = NULL;
+    ncap = 0;
+    for (i = 0; i < npat; i++) {
+        leaf = addpat(t, pat[i]->match.pat, &cap, &ncap);
+        /* TODO: NULL is returned by unsupported patterns. */
+        if (!leaf)
+            return NULL;
+        if (leaf->act)
+            fatal(pat[i], "pattern matched by earlier case");
+        leaf->act = pat[i]->match.block;
+        leaf->cap = cap;
+        leaf->ncap = ncap;
+    }
+    checkcomprehensive(t);
+    return genmatch(t);
+}
--- a/opt/opt.h
+++ b/opt/opt.h
@@ -33,3 +33,6 @@
 Cfg *mkcfg(Node *fn, Node **nl, size_t nn);
 void dumpcfg(Cfg *c, FILE *fd);
 void check(Cfg *cfg);
+
+/* pattern matching */
+Node *gensimpmatch(Node *m);