about summary refs log tree commit diff
path: root/src/libexpr/parser.y
diff options
context:
space:
mode:
authorFélix Baylac-Jacqué <felix@alternativebit.fr>2018-04-18T16·39+0200
committerFélix Baylac-Jacqué <felix@alternativebit.fr>2018-04-18T16·44+0200
commit00584bb0915ee21fb01e9390a901161bdd988197 (patch)
tree27643cb3166fa8d9c989572313623a960ae47ac0 /src/libexpr/parser.y
parent10d33452e289ded93e192c7d99c1da08a52448e1 (diff)
parser: Allow mixed nested and top-level attrpaths
Fixes #2077.
Diffstat (limited to 'src/libexpr/parser.y')
-rw-r--r--src/libexpr/parser.y26
1 files changed, 23 insertions, 3 deletions
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index ef11dd6092..df4fdf0324 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -83,7 +83,9 @@ static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
     AttrPath::iterator i;
     // All attrpaths have at least one attr
     assert(!attrPath.empty());
-    for (i = attrPath.begin(); i + 1 < attrPath.end(); i++) {
+    // Checking attrPath validity.
+    // ===========================
+    for (i = attrPath.begin(); i + 1 < attrPath.end(); i++) { 
         if (i->symbol.set()) {
             ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol);
             if (j != attrs->attrs.end()) {
@@ -104,11 +106,29 @@ static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
             attrs = nested;
         }
     }
-    if (i->symbol.set()) {
+    // Expr insertion.
+    // ==========================
+    if (i->symbol.set()) { 
         ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol);
         if (j != attrs->attrs.end()) {
-            dupAttr(attrPath, pos, j->second.pos);
+            // This attr path is already defined. However, if both
+            // e and the expr pointed by the attr path are two attribute sets,
+            // we want to merge them.
+            // Otherwise, throw an error.
+            ExprAttrs* ae = dynamic_cast<ExprAttrs *>(e);
+            ExprAttrs* jAttrs = dynamic_cast<ExprAttrs *>(j->second.e);
+            if (jAttrs && ae) {
+                for (auto ad: ae->attrs) {
+                    ExprAttrs::AttrDefs::iterator j2 = jAttrs->attrs.find(ad.first);
+                    if (j2 != jAttrs->attrs.end()) // Attr already defined in iAttrs, error.
+                        dupAttr(ad.first, j2->second.pos, ad.second.pos);
+                    jAttrs->attrs[ad.first] = ad.second;
+                }
+            } else {
+                dupAttr(attrPath, pos, j->second.pos);
+            }
         } else {
+            // This attr path is not defined. Let's create it.
             attrs->attrs[i->symbol] = ExprAttrs::AttrDef(e, pos);
             e->setName(i->symbol);
         }