about summary refs log tree commit diff
diff options
context:
space:
mode:
authorShea Levy <shea@shealevy.com>2013-12-31T22·57-0500
committerShea Levy <shea@shealevy.com>2013-12-31T22·57-0500
commit6f3a51809a2603574a16573bd46b95e4ff5233bd (patch)
tree5b840b6156d4eff11781e2c12258f36fd4fddac5
parent18fefacf7df570444b332a8a0c2dc4f9d98d4344 (diff)
Fold dynamic binds handling into addAttr
Since addAttr has to iterate through the AttrPath we pass it, it makes
more sense to just iterate through the AttrNames in addAttr instead. As
an added bonus, this allows attrsets where two dynamic attribute paths
have the same static leading part (see added test case for an example
that failed previously).

Signed-off-by: Shea Levy <shea@shealevy.com>
-rw-r--r--src/libexpr/parser.y90
-rw-r--r--tests/lang/eval-okay-dynamic-attrs-2.exp1
-rw-r--r--tests/lang/eval-okay-dynamic-attrs-2.nix1
3 files changed, 37 insertions, 55 deletions
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index aa08e1a63e4d..3bee3b010cf6 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -89,31 +89,47 @@ static void dupAttr(Symbol attr, const Pos & pos, const Pos & prevPos)
 }
 
 
-static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
+static void addAttr(ExprAttrs * attrs, AttrNames & attrNames,
     Expr * e, const Pos & pos)
 {
-    unsigned int n = 0;
-    foreach (AttrPath::const_iterator, i, attrPath) {
-        n++;
-        ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(*i);
-        if (j != attrs->attrs.end()) {
-            if (!j->second.inherited) {
-                ExprAttrs * attrs2 = dynamic_cast<ExprAttrs *>(j->second.e);
-                if (!attrs2 || n == attrPath.size()) dupAttr(attrPath, pos, j->second.pos);
-                attrs = attrs2;
-            } else
-                dupAttr(attrPath, pos, j->second.pos);
-        } else {
-            if (n == attrPath.size())
-                attrs->attrs[*i] = ExprAttrs::AttrDef(e, pos);
-            else {
+    AttrPath path;
+    AttrNames::iterator i;
+    // All attrpaths have at least one attr
+    assert(!attrNames.empty());
+    for (i = attrNames.begin(); i + 1 < attrNames.end(); i++) {
+        if (i->symbol.set()) {
+            path.push_back(i->symbol);
+            ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol);
+            if (j != attrs->attrs.end()) {
+                if (!j->second.inherited) {
+                    ExprAttrs * attrs2 = dynamic_cast<ExprAttrs *>(j->second.e);
+                    if (!attrs2) dupAttr(path, pos, j->second.pos);
+                    attrs = attrs2;
+                } else
+                    dupAttr(path, pos, j->second.pos);
+            } else {
+                path.clear();
                 ExprAttrs * nested = new ExprAttrs;
-                attrs->attrs[*i] = ExprAttrs::AttrDef(nested, pos);
+                attrs->attrs[i->symbol] = ExprAttrs::AttrDef(nested, pos);
                 attrs = nested;
             }
+        } else {
+            ExprAttrs *nested = new ExprAttrs;
+            attrs->dynamicAttrs.push_back(ExprAttrs::DynamicAttrDef(i->expr, nested, pos));
+            attrs = nested;
         }
     }
-    e->setName(attrPath.back());
+    if (i->symbol.set()) {
+        ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol);
+        if (j != attrs->attrs.end()) {
+            dupAttr(path, pos, j->second.pos);
+        } else {
+            attrs->attrs[i->symbol] = ExprAttrs::AttrDef(e, pos);
+            e->setName(i->symbol);
+        }
+    } else {
+        attrs->dynamicAttrs.push_back(ExprAttrs::DynamicAttrDef(i->expr, e, pos));
+    }
 }
 
 
@@ -522,43 +538,7 @@ ind_string_parts
   ;
 
 binds
-  : binds attrpath '=' expr ';'
-    {
-        ExprAttrs *curAttrs = $1;
-        AttrPath path;
-        vector<AttrName>::iterator i;
-        // All attrpaths have at least one attr
-        assert(!$2->empty());
-        for (i = $2->begin(); i + 1 < $2->end(); i++) {
-          if (i->symbol.set()) {
-            path.push_back(i->symbol);
-          } else {
-            ExprAttrs *temp;
-            if (!path.empty()) {
-              temp = curAttrs;
-              curAttrs = new ExprAttrs;
-              addAttr(temp, path, curAttrs, makeCurPos(@2, data));
-            }
-            path.clear();
-
-            temp = curAttrs;
-            curAttrs = new ExprAttrs;
-            temp->dynamicAttrs.push_back(ExprAttrs::DynamicAttrDef(i->expr, curAttrs, makeCurPos(@2, data)));
-          }
-        }
-        if (i->symbol.set()) {
-          path.push_back(i->symbol);
-          addAttr(curAttrs, path, $4, makeCurPos(@2, data));
-        } else {
-          if (!path.empty()) {
-            ExprAttrs *temp = curAttrs;
-            curAttrs = new ExprAttrs;
-            addAttr(temp, path, curAttrs, makeCurPos(@2, data));
-          }
-          curAttrs->dynamicAttrs.push_back(ExprAttrs::DynamicAttrDef(i->expr, $4, makeCurPos(@2, data)));
-        }
-        $$ = $1;
-    }
+  : binds attrpath '=' expr ';' { $$ = $1; addAttr($$, *$2, $4, makeCurPos(@2, data)); }
   | binds INHERIT attrs ';'
     { $$ = $1;
       foreach (AttrPath::iterator, i, *$3) {
diff --git a/tests/lang/eval-okay-dynamic-attrs-2.exp b/tests/lang/eval-okay-dynamic-attrs-2.exp
new file mode 100644
index 000000000000..27ba77ddaf61
--- /dev/null
+++ b/tests/lang/eval-okay-dynamic-attrs-2.exp
@@ -0,0 +1 @@
+true
diff --git a/tests/lang/eval-okay-dynamic-attrs-2.nix b/tests/lang/eval-okay-dynamic-attrs-2.nix
new file mode 100644
index 000000000000..6d57bf854908
--- /dev/null
+++ b/tests/lang/eval-okay-dynamic-attrs-2.nix
@@ -0,0 +1 @@
+{ a."${"b"}" = true; a."${"c"}" = false; }.a.b