about summary refs log tree commit diff
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
parent10d33452e289ded93e192c7d99c1da08a52448e1 (diff)
parser: Allow mixed nested and top-level attrpaths
Fixes #2077.
-rw-r--r--src/libexpr/parser.y26
-rw-r--r--tests/lang/parse-fail-mixed-nested-attrs1.nix (renamed from tests/lang/parse-fail-mixed-nested-attrs.nix)2
-rw-r--r--tests/lang/parse-fail-mixed-nested-attrs2.nix4
-rw-r--r--tests/lang/parse-okay-dup-attrs-6.nix (renamed from tests/lang/parse-fail-dup-attrs-6.nix)0
-rw-r--r--tests/lang/parse-okay-nested-attrs.nix4
5 files changed, 28 insertions, 8 deletions
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index ef11dd609217..df4fdf032479 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);
         }
diff --git a/tests/lang/parse-fail-mixed-nested-attrs.nix b/tests/lang/parse-fail-mixed-nested-attrs1.nix
index 458a7c545b97..11e40e66fd1b 100644
--- a/tests/lang/parse-fail-mixed-nested-attrs.nix
+++ b/tests/lang/parse-fail-mixed-nested-attrs1.nix
@@ -1,4 +1,4 @@
 { 
-  x = { y = 3; z = 3; }; 
   x.z = 3; 
+  x = { y = 3; z = 3; }; 
 }
diff --git a/tests/lang/parse-fail-mixed-nested-attrs2.nix b/tests/lang/parse-fail-mixed-nested-attrs2.nix
new file mode 100644
index 000000000000..17da82e5f0c7
--- /dev/null
+++ b/tests/lang/parse-fail-mixed-nested-attrs2.nix
@@ -0,0 +1,4 @@
+{ 
+  x.y.y = 3; 
+  x = { y.y= 3; z = 3; }; 
+}
diff --git a/tests/lang/parse-fail-dup-attrs-6.nix b/tests/lang/parse-okay-dup-attrs-6.nix
index ae6d7a769305..ae6d7a769305 100644
--- a/tests/lang/parse-fail-dup-attrs-6.nix
+++ b/tests/lang/parse-okay-dup-attrs-6.nix
diff --git a/tests/lang/parse-okay-nested-attrs.nix b/tests/lang/parse-okay-nested-attrs.nix
deleted file mode 100644
index fd1001c8cafc..000000000000
--- a/tests/lang/parse-okay-nested-attrs.nix
+++ /dev/null
@@ -1,4 +0,0 @@
-{ 
-  x = { y = 3; z = 3; }; 
-  x.q = 3; 
-}