shithub: mc

Download patch

ref: d23b4a240fb0b8ad401081e29230737502d13ad4
parent: dd1dcc663ada21c70e41003564e5c57d671981ac
author: Ori Bernstein <[email protected]>
date: Thu Sep 24 19:21:08 EDT 2015

Error out correctly with closures.

--- a/6/simp.c
+++ b/6/simp.c
@@ -25,6 +25,7 @@
 typedef struct Simp Simp;
 struct Simp {
     int isglobl;
+    Bitset *env;
 
     Node **stmts;
     size_t nstmts;
@@ -345,6 +346,12 @@
     return load(addk(addr(s, sl, tyintptr), Ptrsz));
 }
 
+Node *loadvar(Simp *s, Node *n)
+{
+    if (bshas(s->env, n->expr.did))
+        fatal(n, "closure environment capture has not yet been implemented");
+    return n;
+}
 
 static Node *seqlen(Simp *s, Node *n, Type *ty)
 {
@@ -685,12 +692,10 @@
 {
     size_t i;
 
-    pushstab(n->block.scope);
     for (i = 0; i < n->block.nstmts; i++) {
         n->block.stmts[i] = fold(n->block.stmts[i], 0);
         simp(s, n->block.stmts[i]);
     }
-    popstab();
 }
 
 static Node *simpblob(Simp *s, Node *blob, Node ***l, size_t *nl)
@@ -829,7 +834,7 @@
 
     args = n->expr.args;
     switch (exprop(n)) {
-        case Ovar:      r = n;  break;
+        case Ovar:      r = loadvar(s, n);  break;
         case Oidx:      r = deref(idxaddr(s, args[0], args[1]), NULL); break;
         case Oderef:    r = deref(rval(s, args[0], NULL), NULL); break;
         case Omemb:     r = rval(s, n, NULL); break;
@@ -1458,7 +1463,7 @@
             }
             break;
         case Ovar:
-            r = n;
+            r = loadvar(s, n);
             break;
         case Ogap:
             fatal(n, "'_' may not be an rvalue");
@@ -1675,6 +1680,18 @@
     return 0;
 }
 
+static void collectenv(Simp *s, Node *fn)
+{
+    size_t nenv, i;
+    Node **env;
+
+    s->env = mkbs();
+    env = getclosure(fn->func.scope, &nenv);
+    for (i = 0; i < nenv; i++)
+        bsput(s->env, env[i]->decl.did);
+    free(env);
+}
+
 static Func *simpfn(Simp *s, char *name, Node *dcl)
 {
     Node *n;
@@ -1690,9 +1707,8 @@
     /* unwrap to the function body */
     n = n->expr.args[0];
     n = n->lit.fnval;
-    pushstab(n->func.scope);
+    collectenv(s, n);
     flatten(s, n);
-    popstab();
 
     if (debugopt['f'] || debugopt['F'])
         for (i = 0; i < s->nstmts; i++)
--- a/parse/parse.h
+++ b/parse/parse.h
@@ -488,6 +488,7 @@
 Stab *getns(Node *file, char *n);
 Node *getdcl(Stab *st, Node *n);
 Node *getclosed(Stab *st, Node *n);
+Node **getclosure(Stab *st, size_t *n);
 Type *gettype_l(Stab *st, Node *n);
 Type *gettype(Stab *st, Node *n);
 Node *getimpl(Stab *st, Node *impl);
--- a/parse/stab.c
+++ b/parse/stab.c
@@ -109,6 +109,29 @@
     return NULL;
 }
 
+Node **getclosure(Stab *st, size_t *n)
+{
+    size_t nkeys, i;
+    void **keys;
+    Node **vals;
+
+    while (st && !st->env)
+        st = st->super;
+
+    if (!st) {
+        *n = 0;
+        return NULL;
+    }
+
+    vals = NULL;
+    *n = 0;
+    keys = htkeys(st->env, &nkeys);
+    for (i = 0; i < nkeys; i++)
+        lappend(&vals, n, htget(st->env, keys[i]));
+    free(keys);
+    return vals;
+}
+
 /* 
  * Searches for declarations from current
  * scope, and all enclosing scopes. Does
@@ -127,14 +150,14 @@
     fn = NULL;
     do {
         s = htget(st->dcl, n);
-        if (!fn && st->env)
-            fn = st;
         if (s) {
             /* record that this is in the closure of this scope */
-            if (fn && !n->decl.isglobl)
+            if (fn && !s->decl.isglobl)
                 htput(fn->env, s->decl.name, s);
             return s;
         }
+        if (!fn && st->env)
+            fn = st;
         st = st->super;
     } while (st);
     return NULL;
--- a/test/closure.myr
+++ b/test/closure.myr
@@ -4,5 +4,5 @@
 	var f = {b
 		-> a + b
 	}
-	-> f(13)
+	f(13)
 }