[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