[augeas-devel] [PATCH 3/3] * src/syntax.c: typecheck and eval of match expressions

David Lutterkort lutter at redhat.com
Sat Feb 21 07:52:24 UTC 2009


---
 src/syntax.c |   94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 94 insertions(+), 0 deletions(-)

diff --git a/src/syntax.c b/src/syntax.c
index d639be1..1b82f63 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -196,6 +196,8 @@ static void free_term(struct term *term) {
     case A_CONCAT:
     case A_APP:
     case A_LET:
+    case A_MATCH:
+    case A_BRANCH:
         unref(term->left, term);
         unref(term->right, term);
         break;
@@ -1092,6 +1094,61 @@ static int check_value(struct value *v) {
     return 1;
 }
 
+/* Check a match expression
+ *
+ * We require that the patterns in thebranches are of type T_STRING, and
+ * that the last clause is a catch-all match, since don't want to deal with
+ * failed matches at runtime.
+ */
+
+static int check_match(struct term *match, struct ctx *ctx) {
+    int result = 1;
+    struct type *allowed[] = { (struct type *) t_string };
+    struct term *branches = match->right;
+
+    result = (require_exp_type(match->left, ctx, 1, allowed) != NULL);
+
+    list_for_each(t, branches) {
+        if (t->left == NULL) {
+            if (t->next != NULL) {
+                syntax_error(t->next->info, "useless branch in match");
+                result = 0;
+            }
+        } else {
+            if (result && t->next == NULL) {
+                syntax_error(match->info,
+                             "pattern matching is not exhaustive");
+                result = 0;
+            } else {
+                result &= (require_exp_type(t->left, ctx, 1, allowed) != NULL);
+            }
+        }
+        result &= check_exp(t->right, ctx);
+        if (result)
+            t->type = ref(t->right->type);
+    }
+    if (! result)
+        return result;
+
+    branches->type = ref(branches->right->type);
+    list_for_each(tm, branches->next) {
+        struct type *ty = NULL;
+        ty = type_join(branches->type, tm->type);
+        if (ty == NULL) {
+            type_error2(tm->info,
+                        "incompatible types in match branches %s and %s",
+                        branches->type, tm->type);
+            result = 0;
+        } else {
+            unref(branches->type, type);
+            branches->type = ty;
+        }
+    }
+    if (result)
+        match->type = ref(branches->type);
+    return result;
+}
+
 /* Return 1 if TERM passes, 0 otherwise */
 static int check_exp(struct term *term, struct ctx *ctx) {
     int result = 1;
@@ -1206,6 +1263,9 @@ static int check_exp(struct term *term, struct ctx *ctx) {
             }
         }
         break;
+    case A_MATCH:
+        result = check_match(term, ctx); /* Also handles A_BRANCH */
+        break;
     default:
         assert(0);
         break;
@@ -1549,6 +1609,37 @@ static struct value *compile_rep(struct term *rep, struct ctx *ctx) {
     return v;
 }
 
+static struct value *compile_match(struct term *match, struct ctx *ctx) {
+    struct value *s = NULL;
+    struct term *vexp = NULL;
+
+    s = compile_exp(match->left->info, match->left, ctx);
+    if (EXN(s))
+        return s;
+
+    list_for_each(branch, match->right) {
+        struct value *p = NULL;
+        if (branch->left == NULL) {
+            vexp = branch->right;
+            break;
+        }
+        p = compile_exp(branch->left->info, branch->left, ctx);
+        if (EXN(p)) {
+            unref(s, value);
+            return p;
+        }
+        if (STREQ(p->string->str, s->string->str)) {
+            unref(p, value);
+            vexp = branch->right;
+            break;
+        }
+        unref(p, value);
+    }
+    unref(s, value);
+
+    return compile_exp(vexp->info, vexp, ctx);
+}
+
 static struct value *compile_exp(struct info *info,
                                  struct term *exp, struct ctx *ctx) {
     struct value *v = NULL;
@@ -1588,6 +1679,9 @@ static struct value *compile_exp(struct info *info,
     case A_REP:
         v = compile_rep(exp, ctx);
         break;
+    case A_MATCH:
+        v = compile_match(exp, ctx);
+        break;
     default:
         assert(0);
         break;
-- 
1.6.0.6




More information about the augeas-devel mailing list