Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions maintainers/flake-module.nix
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@
# Not supported by nixfmt
''^tests/functional/lang/eval-okay-deprecate-cursed-or\.nix$''
''^tests/functional/lang/eval-okay-attrs5\.nix$''
''^tests/functional/lang/eval-fail-dynamic-attrs-inherit\.nix$''
''^tests/functional/lang/eval-fail-dynamic-attrs-inherit-2\.nix$''

# More syntax tests
# These tests, or parts of them, should have been parse-* test cases.
Expand Down
23 changes: 4 additions & 19 deletions src/libexpr/include/nix/expr/nixexpr.hh
Original file line number Diff line number Diff line change
Expand Up @@ -185,28 +185,13 @@ struct ExprFloat : Expr

struct ExprString : Expr
{
std::string s;
Value v;

/**
* This is only for strings already allocated in our polymorphic allocator,
* or that live at least that long (e.g. c++ string literals)
*/
ExprString(const char * s)
{
v.mkStringNoCopy(s);
};

ExprString(std::pmr::polymorphic_allocator<char> & alloc, std::string_view sv)
ExprString(std::string && s)
: s(std::move(s))
{
auto len = sv.length();
if (len == 0) {
v.mkStringNoCopy("");
return;
}
char * s = alloc.allocate(len + 1);
sv.copy(s, len);
s[len] = '\0';
v.mkStringNoCopy(s);
v.mkStringNoCopy(this->s.data());
};

Value * maybeThunk(EvalState & state, Env & env) override;
Expand Down
2 changes: 1 addition & 1 deletion src/libexpr/include/nix/expr/parser-state.hh
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ ParserState::stripIndentation(const PosIdx pos, std::vector<std::pair<PosIdx, st

// Ignore empty strings for a minor optimisation and AST simplification
if (s2 != "") {
es2->emplace_back(i->first, new ExprString(alloc, s2));
es2->emplace_back(i->first, new ExprString(std::move(s2)));
}
};
for (; i != es.end(); ++i, --n) {
Expand Down
2 changes: 1 addition & 1 deletion src/libexpr/nixexpr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ void ExprFloat::show(const SymbolTable & symbols, std::ostream & str) const

void ExprString::show(const SymbolTable & symbols, std::ostream & str) const
{
printLiteralString(str, v.string_view());
printLiteralString(str, s);
}

void ExprPath::show(const SymbolTable & symbols, std::ostream & str) const
Expand Down
71 changes: 32 additions & 39 deletions src/libexpr/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ static Expr * makeCall(PosIdx pos, Expr * fn, Expr * arg) {
std::vector<nix::AttrName> * attrNames;
std::vector<std::pair<nix::AttrName, nix::PosIdx>> * inheritAttrs;
std::vector<std::pair<nix::PosIdx, nix::Expr *>> * string_parts;
std::variant<nix::Expr *, std::string_view> * to_be_string;
std::vector<std::pair<nix::PosIdx, std::variant<nix::Expr *, nix::StringToken>>> * ind_string_parts;
}

Expand All @@ -151,8 +150,7 @@ static Expr * makeCall(PosIdx pos, Expr * fn, Expr * arg) {
%type <inheritAttrs> attrs
%type <string_parts> string_parts_interpolated
%type <ind_string_parts> ind_string_parts
%type <e> path_start
%type <to_be_string> string_parts string_attr
%type <e> path_start string_parts string_attr
%type <id> attr
%token <id> ID
%token <str> STR IND_STR
Expand Down Expand Up @@ -307,13 +305,7 @@ expr_simple
}
| INT_LIT { $$ = new ExprInt($1); }
| FLOAT_LIT { $$ = new ExprFloat($1); }
| '"' string_parts '"' {
std::visit(overloaded{
[&](std::string_view str) { $$ = new ExprString(state->alloc, str); },
[&](Expr * expr) { $$ = expr; }},
*$2);
delete $2;
}
| '"' string_parts '"' { $$ = $2; }
| IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
$$ = state->stripIndentation(CUR_POS, std::move(*$2));
delete $2;
Expand All @@ -324,11 +316,11 @@ expr_simple
$$ = new ExprConcatStrings(CUR_POS, false, $2);
}
| SPATH {
std::string_view path($1.p + 1, $1.l - 2);
std::string path($1.p + 1, $1.l - 2);
$$ = new ExprCall(CUR_POS,
new ExprVar(state->s.findFile),
{new ExprVar(state->s.nixPath),
new ExprString(state->alloc, path)});
new ExprString(std::move(path))});
}
| URI {
static bool noURLLiterals = experimentalFeatureSettings.isEnabled(Xp::NoUrlLiterals);
Expand All @@ -337,7 +329,7 @@ expr_simple
.msg = HintFmt("URL literals are disabled"),
.pos = state->positions[CUR_POS]
});
$$ = new ExprString(state->alloc, $1);
$$ = new ExprString(std::string($1));
}
| '(' expr ')' { $$ = $2; }
/* Let expressions `let {..., body = ...}' are just desugared
Expand All @@ -354,19 +346,19 @@ expr_simple
;

string_parts
: STR { $$ = new std::variant<Expr *, std::string_view>($1); }
| string_parts_interpolated { $$ = new std::variant<Expr *, std::string_view>(new ExprConcatStrings(CUR_POS, true, $1)); }
| { $$ = new std::variant<Expr *, std::string_view>(std::string_view()); }
: STR { $$ = new ExprString(std::string($1)); }
| string_parts_interpolated { $$ = new ExprConcatStrings(CUR_POS, true, $1); }
| { $$ = new ExprString(""); }
;

string_parts_interpolated
: string_parts_interpolated STR
{ $$ = $1; $1->emplace_back(state->at(@2), new ExprString(state->alloc, $2)); }
{ $$ = $1; $1->emplace_back(state->at(@2), new ExprString(std::string($2))); }
| string_parts_interpolated DOLLAR_CURLY expr '}' { $$ = $1; $1->emplace_back(state->at(@2), $3); }
| DOLLAR_CURLY expr '}' { $$ = new std::vector<std::pair<PosIdx, Expr *>>; $$->emplace_back(state->at(@1), $2); }
| STR DOLLAR_CURLY expr '}' {
$$ = new std::vector<std::pair<PosIdx, Expr *>>;
$$->emplace_back(state->at(@1), new ExprString(state->alloc, $1));
$$->emplace_back(state->at(@1), new ExprString(std::string($1)));
$$->emplace_back(state->at(@2), $3);
}
;
Expand Down Expand Up @@ -464,16 +456,15 @@ attrs
: attrs attr { $$ = $1; $1->emplace_back(AttrName(state->symbols.create($2)), state->at(@2)); }
| attrs string_attr
{ $$ = $1;
std::visit(overloaded {
[&](std::string_view str) { $$->emplace_back(AttrName(state->symbols.create(str)), state->at(@2)); },
[&](Expr * expr) {
throw ParseError({
.msg = HintFmt("dynamic attributes not allowed in inherit"),
.pos = state->positions[state->at(@2)]
});
}
}, *$2);
delete $2;
ExprString * str = dynamic_cast<ExprString *>($2);
if (str) {
$$->emplace_back(AttrName(state->symbols.create(str->s)), state->at(@2));
delete str;
} else
throw ParseError({
.msg = HintFmt("dynamic attributes not allowed in inherit"),
.pos = state->positions[state->at(@2)]
});
}
| { $$ = new std::vector<std::pair<AttrName, PosIdx>>; }
;
Expand All @@ -482,20 +473,22 @@ attrpath
: attrpath '.' attr { $$ = $1; $1->push_back(AttrName(state->symbols.create($3))); }
| attrpath '.' string_attr
{ $$ = $1;
std::visit(overloaded {
[&](std::string_view str) { $$->push_back(AttrName(state->symbols.create(str))); },
[&](Expr * expr) { $$->push_back(AttrName(expr)); }
}, *$3);
delete $3;
ExprString * str = dynamic_cast<ExprString *>($3);
if (str) {
$$->push_back(AttrName(state->symbols.create(str->s)));
delete str;
} else
$$->push_back(AttrName($3));
}
| attr { $$ = new std::vector<AttrName>; $$->push_back(AttrName(state->symbols.create($1))); }
| string_attr
{ $$ = new std::vector<AttrName>;
std::visit(overloaded {
[&](std::string_view str) { $$->push_back(AttrName(state->symbols.create(str))); },
[&](Expr * expr) { $$->push_back(AttrName(expr)); }
}, *$1);
delete $1;
ExprString *str = dynamic_cast<ExprString *>($1);
if (str) {
$$->push_back(AttrName(state->symbols.create(str->s)));
delete str;
} else
$$->push_back(AttrName($1));
}
;

Expand All @@ -506,7 +499,7 @@ attr

string_attr
: '"' string_parts '"' { $$ = $2; }
| DOLLAR_CURLY expr '}' { $$ = new std::variant<Expr *, std::string_view>($2); }
| DOLLAR_CURLY expr '}' { $$ = $2; }
;

expr_list
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
error: dynamic attributes not allowed in inherit
at /pwd/lang/eval-fail-dynamic-attrs-inherit-2.nix:5:15:
4| {
5| inherit (a) ${"b" + ""};
| ^
6| }
6 changes: 6 additions & 0 deletions tests/functional/lang/eval-fail-dynamic-attrs-inherit-2.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
let
a.b = 1;
in
{
inherit (a) ${"b" + ""};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
error: dynamic attributes not allowed in inherit
at /pwd/lang/eval-fail-dynamic-attrs-inherit.nix:5:11:
4| {
5| inherit ${"a" + ""};
| ^
6| }
6 changes: 6 additions & 0 deletions tests/functional/lang/eval-fail-dynamic-attrs-inherit.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
let
a = 1;
in
{
inherit ${"a" + ""};
}
5 changes: 5 additions & 0 deletions tests/functional/lang/eval-fail-dynamic-attrs-let-2.err.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error: dynamic attributes not allowed in let
at /pwd/lang/eval-fail-dynamic-attrs-let-2.nix:1:1:
1| let
| ^
2| ${"${"a"}"} = 1;
4 changes: 4 additions & 0 deletions tests/functional/lang/eval-fail-dynamic-attrs-let-2.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
let
${"${"a"}"} = 1;
in
a
5 changes: 5 additions & 0 deletions tests/functional/lang/eval-fail-dynamic-attrs-let-3.err.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error: dynamic attributes not allowed in let
at /pwd/lang/eval-fail-dynamic-attrs-let-3.nix:1:1:
1| let
| ^
2| "${"a"}" = 1;
4 changes: 4 additions & 0 deletions tests/functional/lang/eval-fail-dynamic-attrs-let-3.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
let
"${"a"}" = 1;
in
a
5 changes: 5 additions & 0 deletions tests/functional/lang/eval-fail-dynamic-attrs-let.err.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error: dynamic attributes not allowed in let
at /pwd/lang/eval-fail-dynamic-attrs-let.nix:1:1:
1| let
| ^
2| ${"a" + ""} = 1;
4 changes: 4 additions & 0 deletions tests/functional/lang/eval-fail-dynamic-attrs-let.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
let
${"a" + ""} = 1;
in
a
1 change: 1 addition & 0 deletions tests/functional/lang/eval-okay-dynamic-attrs-3.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ a = 1; attrs = { b = 1; c = 1; d = 1; }; b = 1; c = 1; d = 1; }
14 changes: 14 additions & 0 deletions tests/functional/lang/eval-okay-dynamic-attrs-3.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# dynamic attrs are not generally allowed in `let`, and inherit, but they are if they only contain a string
let
${"a"} = 1;
attrs = rec {
b = c;
${"c"} = d;
d = a;
};
in
{
inherit ${"a"};
inherit attrs;
inherit (attrs) ${"b"} ${"c"} d;
}
Loading