libexpr: quote reserved keys when printing
This fixes a bug in commands like `nix eval' which would emit invalid attribute sets if they contained reserved keywords such as "assert", "let", etc. These keywords will not be quoted when printed, making them valid expressions. All keywords recognized by the lexer are quoted except "or", which does not require quotation.
This commit is contained in:
parent
4539ab530a
commit
b72bc4a972
4 changed files with 33 additions and 4 deletions
|
@ -94,7 +94,6 @@ RootValue allocRootValue(Value * v)
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Value::print(const SymbolTable & symbols, std::ostream & str,
|
||||
std::set<const void *> * seen) const
|
||||
{
|
||||
|
@ -122,7 +121,13 @@ void Value::print(const SymbolTable & symbols, std::ostream & str,
|
|||
else {
|
||||
str << "{ ";
|
||||
for (auto & i : attrs->lexicographicOrder(symbols)) {
|
||||
str << symbols[i->name] << " = ";
|
||||
// Quote reserved keywords so that the output can be
|
||||
// re-evaluated later without upsetting the lexer.
|
||||
if (isReservedKeyword(symbols[i->name])) {
|
||||
str << "\"" << symbols[i->name] << "\" = ";
|
||||
} else {
|
||||
str << symbols[i->name] << " = ";
|
||||
}
|
||||
i->value->print(symbols, str, seen);
|
||||
str << "; ";
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "print.hh"
|
||||
#include <unordered_set>
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
@ -25,11 +26,26 @@ printLiteralBool(std::ostream & str, bool boolean)
|
|||
return str;
|
||||
}
|
||||
|
||||
// Returns `true' is a string is a reserved keyword which requires quotation
|
||||
// when printing attribute set field names.
|
||||
//
|
||||
// This list should generally be kept in sync with `./lexer.l'.
|
||||
// You can test if a keyword needs to be added by running:
|
||||
// $ nix eval --expr '{ <KEYWORD> = 1; }'
|
||||
// For example `or' doesn't need to be quoted.
|
||||
bool isReservedKeyword(const std::string_view str)
|
||||
{
|
||||
static const std::unordered_set<std::string_view> reservedKeywords = {
|
||||
"if", "then", "else", "assert", "with", "let", "in", "rec", "inherit"
|
||||
};
|
||||
return reservedKeywords.contains(str);
|
||||
}
|
||||
|
||||
std::ostream &
|
||||
printIdentifier(std::ostream & str, std::string_view s) {
|
||||
if (s.empty())
|
||||
str << "\"\"";
|
||||
else if (s == "if") // FIXME: handle other keywords
|
||||
else if (isReservedKeyword(s))
|
||||
str << '"' << s << '"';
|
||||
else {
|
||||
char c = s[0];
|
||||
|
@ -50,10 +66,10 @@ printIdentifier(std::ostream & str, std::string_view s) {
|
|||
return str;
|
||||
}
|
||||
|
||||
// FIXME: keywords
|
||||
static bool isVarName(std::string_view s)
|
||||
{
|
||||
if (s.size() == 0) return false;
|
||||
if (isReservedKeyword(s)) return false;
|
||||
char c = s[0];
|
||||
if ((c >= '0' && c <= '9') || c == '-' || c == '\'') return false;
|
||||
for (auto & i : s)
|
||||
|
|
|
@ -35,6 +35,12 @@ namespace nix {
|
|||
*/
|
||||
std::ostream & printAttributeName(std::ostream & o, std::string_view s);
|
||||
|
||||
/**
|
||||
* Returns `true' is a string is a reserved keyword which requires quotation
|
||||
* when printing attribute set field names.
|
||||
*/
|
||||
bool isReservedKeyword(const std::string_view str);
|
||||
|
||||
/**
|
||||
* Print a string as an identifier in the Nix expression language syntax.
|
||||
*
|
||||
|
|
|
@ -19,6 +19,7 @@ nix eval --expr 'assert 1 + 2 == 3; true'
|
|||
[[ $(nix eval attr -f "./eval.nix") == '{ foo = "bar"; }' ]]
|
||||
[[ $(nix eval attr --json -f "./eval.nix") == '{"foo":"bar"}' ]]
|
||||
[[ $(nix eval int -f - < "./eval.nix") == 123 ]]
|
||||
[[ $(nix eval --expr '{"assert"=1;bar=2;}') == '{ "assert" = 1; bar = 2; }' ]]
|
||||
|
||||
# Check if toFile can be utilized during restricted eval
|
||||
[[ $(nix eval --restrict-eval --expr 'import (builtins.toFile "source" "42")') == 42 ]]
|
||||
|
@ -29,6 +30,7 @@ nix-instantiate --eval -E 'assert 1 + 2 == 3; true'
|
|||
[[ $(nix-instantiate -A attr --eval "./eval.nix") == '{ foo = "bar"; }' ]]
|
||||
[[ $(nix-instantiate -A attr --eval --json "./eval.nix") == '{"foo":"bar"}' ]]
|
||||
[[ $(nix-instantiate -A int --eval - < "./eval.nix") == 123 ]]
|
||||
[[ $(nix-instantiate --eval -E '{"assert"=1;bar=2;}') == '{ "assert" = 1; bar = 2; }' ]]
|
||||
|
||||
# Check that symlink cycles don't cause a hang.
|
||||
ln -sfn cycle.nix $TEST_ROOT/cycle.nix
|
||||
|
|
Loading…
Reference in a new issue