From 1a22abd7c54c3492a5fb3e6a50e4aadb64939551 Mon Sep 17 00:00:00 2001 From: Ryan Burns Date: Sun, 17 Oct 2021 19:49:26 -0700 Subject: [PATCH 1/5] RFC 110: Add "inherit-as-list" language construct Initial MVP implementation for [RFC 110](https://github.com/NixOS/rfcs/pull/110) --- src/libexpr/parser.y | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 8a0a79c964f..3b238a0c98e 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -343,6 +343,15 @@ expr_function }); $$ = new ExprLet($2, $4); } + | INHERIT '(' expr ')' '[' attrs ']' + { auto ret = new ExprList; + ret->elems.reserve($6->size()); + /* !!! Should ensure sharing of the expression in $3. */ + for (auto & i : *$6) { + ret->elems.push_back(new ExprSelect(makeCurPos(@6, data), $3, i.symbol)); + } + $$ = ret; + } | expr_if ; From ea2bb4e028c5c2f285b560bc0e0831599cfa0156 Mon Sep 17 00:00:00 2001 From: Ryan Burns Date: Mon, 18 Oct 2021 21:11:04 -0700 Subject: [PATCH 2/5] Revert "RFC 110: Add "inherit-as-list" language construct" This reverts commit 1a22abd7c54c3492a5fb3e6a50e4aadb64939551. In preparation for revised implementation --- src/libexpr/parser.y | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 3b238a0c98e..8a0a79c964f 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -343,15 +343,6 @@ expr_function }); $$ = new ExprLet($2, $4); } - | INHERIT '(' expr ')' '[' attrs ']' - { auto ret = new ExprList; - ret->elems.reserve($6->size()); - /* !!! Should ensure sharing of the expression in $3. */ - for (auto & i : *$6) { - ret->elems.push_back(new ExprSelect(makeCurPos(@6, data), $3, i.symbol)); - } - $$ = ret; - } | expr_if ; From a29792686925643604f82780c4fe35dafad10c0b Mon Sep 17 00:00:00 2001 From: Ryan Burns Date: Mon, 18 Oct 2021 21:12:08 -0700 Subject: [PATCH 3/5] New implementation, more consistent with existing inherit syntax --- src/libexpr/parser.y | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 8a0a79c964f..3cd66e4e81d 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -80,6 +80,27 @@ static void dupAttr(Symbol attr, const Pos & pos, const Pos & prevPos) }); } +static std::vector uniqueNames(const std::vector& parsed, + const Pos& pos) { + + // Extract all the names and sort them + std::vector names; + names.reserve(parsed.size()); + for (const auto& i : parsed) { + names.push_back(i.symbol); + } + std::sort(names.begin(), names.end()); + + // Now that they are sorted, duplicates will be adjacent + const auto found = std::adjacent_find(names.begin(), names.end()); + if (found != names.end()) { + // Same as { inherit } - can this provide better position info? + dupAttr(*found, pos, pos); + } + + return names; +} + static void addAttr(ExprAttrs * attrs, AttrPath & attrPath, Expr * e, const Pos & pos) @@ -550,6 +571,25 @@ string_attr expr_list : expr_list expr_select { $$ = $1; $1->elems.push_back($2); /* !!! dangerous */ } + | expr_list INHERIT attrs ';' + { + // This is syntactic sugar for `attrValues { inherit attrs; }` + const auto names = uniqueNames(*$3, makeCurPos(@3, data)); + $$->elems.reserve($$->elems.size() + names.size()); + for (auto & s : names) { + $$->elems.push_back(new ExprVar(makeCurPos(@3, data), s)); + } + } + | expr_list INHERIT '(' expr ')' attrs ';' + { + // This is syntactic sugar for `attrValues { inherit (expr) attrs; }` + const auto names = uniqueNames(*$6, makeCurPos(@6, data)); + $$->elems.reserve($$->elems.size() + names.size()); + for (auto & s : names) { + /* !!! Should ensure sharing of the expression in $4. */ + $$->elems.push_back(new ExprSelect(makeCurPos(@6, data), $4, s)); + } + } | { $$ = new ExprList; } ; From e3dbc74ca2831fe719ca1c79febc3d8e010b0c2b Mon Sep 17 00:00:00 2001 From: Ryan Burns Date: Tue, 19 Oct 2021 19:38:26 -0700 Subject: [PATCH 4/5] Simplify desugared form Before: ``` [ inherit (attrs) a b c; ] := builtins.attrValues { inherit (attrs) a b c; } ``` After: ``` [ inherit (attrs) a b c; ] := [ attrs.a attrs.b attrs.c ]; ``` The previous desugaring has some potentially nice properties such as non-significant ordering and no-duplicate enforcement, but was ultimately deemed unintuitive and too surprising in practical use. --- src/libexpr/parser.y | 37 ++++++------------------------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 3cd66e4e81d..5b4486bb797 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -80,27 +80,6 @@ static void dupAttr(Symbol attr, const Pos & pos, const Pos & prevPos) }); } -static std::vector uniqueNames(const std::vector& parsed, - const Pos& pos) { - - // Extract all the names and sort them - std::vector names; - names.reserve(parsed.size()); - for (const auto& i : parsed) { - names.push_back(i.symbol); - } - std::sort(names.begin(), names.end()); - - // Now that they are sorted, duplicates will be adjacent - const auto found = std::adjacent_find(names.begin(), names.end()); - if (found != names.end()) { - // Same as { inherit } - can this provide better position info? - dupAttr(*found, pos, pos); - } - - return names; -} - static void addAttr(ExprAttrs * attrs, AttrPath & attrPath, Expr * e, const Pos & pos) @@ -573,21 +552,17 @@ expr_list : expr_list expr_select { $$ = $1; $1->elems.push_back($2); /* !!! dangerous */ } | expr_list INHERIT attrs ';' { - // This is syntactic sugar for `attrValues { inherit attrs; }` - const auto names = uniqueNames(*$3, makeCurPos(@3, data)); - $$->elems.reserve($$->elems.size() + names.size()); - for (auto & s : names) { - $$->elems.push_back(new ExprVar(makeCurPos(@3, data), s)); + $$->elems.reserve($$->elems.size() + $3->size()); + for (auto & i : *$3) { + $$->elems.push_back(new ExprVar(makeCurPos(@3, data), i.symbol)); } } | expr_list INHERIT '(' expr ')' attrs ';' { - // This is syntactic sugar for `attrValues { inherit (expr) attrs; }` - const auto names = uniqueNames(*$6, makeCurPos(@6, data)); - $$->elems.reserve($$->elems.size() + names.size()); - for (auto & s : names) { + $$->elems.reserve($$->elems.size() + $6->size()); + for (auto & i : *$6) { /* !!! Should ensure sharing of the expression in $4. */ - $$->elems.push_back(new ExprSelect(makeCurPos(@6, data), $4, s)); + $$->elems.push_back(new ExprSelect(makeCurPos(@6, data), $4, i.symbol)); } } | { $$ = new ExprList; } From a6068614abc602a5a88d584a4bdb7936f644a2f5 Mon Sep 17 00:00:00 2001 From: Ryan Burns Date: Fri, 29 Jul 2022 00:31:36 -0700 Subject: [PATCH 5/5] Revise to list-like syntax proposed by Synthetica9 The new syntax is ``` attrs.[ a b c ] ``` as sugar for ``` [ attrs.a attrs.b attrs.c ] ``` --- src/libexpr/parser.y | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 5b4486bb797..49f762c77b7 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -385,6 +385,16 @@ expr_select { $$ = new ExprSelect(CUR_POS, $1, *$3, 0); } | expr_simple '.' attrpath OR_KW expr_select { $$ = new ExprSelect(CUR_POS, $1, *$3, $5); } + | expr_simple '.' '[' attrs ']' + { + auto lst = new ExprList; + lst->elems.reserve($4->size()); + for (auto & i : *$4) { + /* !!! Should ensure sharing of the expression in $4. */ + lst->elems.push_back(new ExprSelect(makeCurPos(@4, data), $1, i.symbol)); + } + $$ = lst; + } | /* Backwards compatibility: because Nixpkgs has a rarely used function named ‘or’, allow stuff like ‘map or [...]’. */ expr_simple OR_KW @@ -550,21 +560,6 @@ string_attr expr_list : expr_list expr_select { $$ = $1; $1->elems.push_back($2); /* !!! dangerous */ } - | expr_list INHERIT attrs ';' - { - $$->elems.reserve($$->elems.size() + $3->size()); - for (auto & i : *$3) { - $$->elems.push_back(new ExprVar(makeCurPos(@3, data), i.symbol)); - } - } - | expr_list INHERIT '(' expr ')' attrs ';' - { - $$->elems.reserve($$->elems.size() + $6->size()); - for (auto & i : *$6) { - /* !!! Should ensure sharing of the expression in $4. */ - $$->elems.push_back(new ExprSelect(makeCurPos(@6, data), $4, i.symbol)); - } - } | { $$ = new ExprList; } ;