[augeas-devel] augeas: master - Path expressions: add union operator

David Lutterkort lutter at fedoraproject.org
Wed Oct 21 13:35:08 UTC 2009


Gitweb:        http://git.fedorahosted.org/git/augeas.git?p=augeas.git;a=commitdiff;h=68d07dbb3b9354bbad12a047e269e162d8e1f554
Commit:        68d07dbb3b9354bbad12a047e269e162d8e1f554
Parent:        f1803bfee5cadaec4cfb58add9bb57fdc631ae62
Author:        David Lutterkort <lutter at redhat.com>
AuthorDate:    Wed Oct 21 15:27:19 2009 +0200
Committer:     David Lutterkort <lutter at redhat.com>
CommitterDate: Wed Oct 21 15:27:19 2009 +0200

Path expressions: add union operator

Nodesets can now be unioned with the '|' operator

Fixes ticket #89
---
 doc/xpath.txt     |    3 ++-
 src/pathx.c       |   52 ++++++++++++++++++++++++++++++++++++++++++++++++----
 tests/xpath.tests |   12 ++++++++++++
 3 files changed, 62 insertions(+), 5 deletions(-)

diff --git a/doc/xpath.txt b/doc/xpath.txt
index fa0b643..cd12ebe 100644
--- a/doc/xpath.txt
+++ b/doc/xpath.txt
@@ -128,7 +128,8 @@ RelationalExpr ::= AdditiveExpr (RelationalOp AdditiveExpr)?
 RelationalOp ::= ">" | "<" | ">=" | "<="
 AdditiveExpr ::= MultiplicativeExpr (AdditiveOp MultiplicativeExpr)*
 AdditiveOp   ::= '+' | '-'
-MultiplicativeExpr ::= PathExpr ('*' PathExpr)*
+MultiplicativeExpr ::= UnionExpr ('*' UnionExpr)*
+UnionExpr ::= PathExpr ("|" PathExpr)*
 
 Literal ::= '"' /[^"]* / '"' | "'" /[^']* / "'"
 Number       ::= /[0-9]+/
diff --git a/src/pathx.c b/src/pathx.c
index 89e2663..e5eb8fe 100644
--- a/src/pathx.c
+++ b/src/pathx.c
@@ -84,7 +84,8 @@ enum binary_op {
     OP_STAR,       /* '*'  */
     OP_AND,        /* 'and' */
     OP_OR,         /* 'or' */
-    OP_RE_MATCH     /* '=~' */
+    OP_RE_MATCH,   /* '=~' */
+    OP_UNION       /* '|' */
 };
 
 struct pred {
@@ -823,6 +824,27 @@ static bool eval_re_match_str(struct state *state, struct regexp *rx,
     return r == strlen(str);
 }
 
+static void eval_union(struct state *state) {
+    value_ind_t vind = make_value(T_NODESET, state);
+    struct value *r = pop_value(state);
+    struct value *l = pop_value(state);
+    struct nodeset *res = NULL;
+
+    assert(l->tag == T_NODESET);
+    assert(r->tag == T_NODESET);
+
+    CHECK_ERROR;
+
+    res = clone_nodeset(l->nodeset, state);
+    CHECK_ERROR;
+    for (int i=0; i < r->nodeset->used; i++) {
+        ns_add(res, r->nodeset->nodes[i], state);
+        CHECK_ERROR;
+    }
+    state->value_pool[vind].nodeset = res;
+    push_value(vind, state);
+}
+
 static void eval_re_match(struct state *state) {
     struct value *rx  = pop_value(state);
     struct value *v = pop_value(state);
@@ -875,6 +897,9 @@ static void eval_binary(struct expr *expr, struct state *state) {
     case OP_OR:
         eval_and_or(state, expr->op);
         break;
+    case OP_UNION:
+        eval_union(state);
+        break;
     case OP_RE_MATCH:
         eval_re_match(state);
         break;
@@ -1163,6 +1188,8 @@ static void check_app(struct expr *expr, struct state *state) {
  * '=~'       : T_STRING  -> T_REGEXP  -> T_BOOLEAN
  *              T_NODESET -> T_REGEXP  -> T_BOOLEAN
  *
+ * '|'        : T_NODESET -> T_NODESET -> T_NODESET
+ *
  * Any type can be coerced to T_BOOLEAN (see coerce_to_bool)
  */
 static void check_binary(struct expr *expr, struct state *state) {
@@ -1197,6 +1224,10 @@ static void check_binary(struct expr *expr, struct state *state) {
         ok =  (l == T_NUMBER && r == T_NUMBER);
         res = T_NUMBER;
         break;
+    case OP_UNION:
+        ok = (l == T_NODESET && r == T_NODESET);
+        res = T_NODESET;
+        break;
     case OP_AND:
     case OP_OR:
         ok = 1;
@@ -1868,14 +1899,27 @@ static void parse_path_expr(struct state *state) {
 }
 
 /*
- * MultiplicativeExpr ::= PathExpr ('*' PathExpr)*
+ * UnionExpr ::= PathExpr ('|' PathExpr)*
  */
-static void parse_multiplicative_expr(struct state *state) {
+static void parse_union_expr(struct state *state) {
     parse_path_expr(state);
     CHECK_ERROR;
-    while (match(state, '*')) {
+    while (match(state, '|')) {
         parse_path_expr(state);
         CHECK_ERROR;
+        push_new_binary_op(OP_UNION, state);
+    }
+}
+
+/*
+ * MultiplicativeExpr ::= UnionExpr ('*' UnionExpr)*
+ */
+static void parse_multiplicative_expr(struct state *state) {
+    parse_union_expr(state);
+    CHECK_ERROR;
+    while (match(state, '*')) {
+        parse_union_expr(state);
+        CHECK_ERROR;
         push_new_binary_op(OP_STAR, state);
     }
 }
diff --git a/tests/xpath.tests b/tests/xpath.tests
index 0f4b0f7..a6eef82 100644
--- a/tests/xpath.tests
+++ b/tests/xpath.tests
@@ -221,3 +221,15 @@ test regexp1 /files/etc/sysconfig/network-scripts/*[label() =~ regexp('.*-eth0')
 
 test regexp2 /files/etc/hosts/*[* =~ regexp('127\..*')]
      /files/etc/hosts/1
+
+# Union of nodesets
+test union (/files/etc/yum.conf | /files/etc/yum.repos.d/*)/*/gpgcheck
+     /files/etc/yum.conf/main/gpgcheck = 1
+     /files/etc/yum.repos.d/fedora-updates.repo/updates/gpgcheck = 1
+     /files/etc/yum.repos.d/fedora-updates.repo/updates-debuginfo/gpgcheck = 1
+     /files/etc/yum.repos.d/fedora-updates.repo/updates-source/gpgcheck = 1
+     /files/etc/yum.repos.d/fedora.repo/fedora/gpgcheck = 1
+     /files/etc/yum.repos.d/fedora.repo/fedora-debuginfo/gpgcheck = 1
+     /files/etc/yum.repos.d/fedora.repo/fedora-source/gpgcheck = 1
+     /files/etc/yum.repos.d/remi.repo/remi/gpgcheck = 1
+     /files/etc/yum.repos.d/remi.repo/remi-test/gpgcheck = 1




More information about the augeas-devel mailing list