Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quote reserved keywords when printing expressions #8110

Merged
merged 3 commits into from
May 9, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion src/libexpr/eval.cc
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ RootValue allocRootValue(Value * v)
#endif
}


void Value::print(const SymbolTable & symbols, std::ostream & str,
std::set<const void *> * seen) const
{
Expand Down
20 changes: 18 additions & 2 deletions src/libexpr/print.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "print.hh"
#include <unordered_set>

namespace nix {

Expand All @@ -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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, technically reserved keywords would be keywords that aren't in use. I don't think Nix has any of those.
IIRC JavaScript reserved some Java/C/C++ keywords early on, that remain reserved and unused until this day.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Want to rename it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When anyone has time.

{
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];
Expand All @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions src/libexpr/print.hh
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
6 changes: 4 additions & 2 deletions tests/eval.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,21 @@ nix eval --expr 'assert 1 + 2 == 3; true'
[[ $(nix eval int -f "./eval.nix") == 123 ]]
[[ $(nix eval str -f "./eval.nix") == '"foo"' ]]
[[ $(nix eval str --raw -f "./eval.nix") == 'foo' ]]
[[ $(nix eval attr -f "./eval.nix") == '{ foo = "bar"; }' ]]
[[ "$(nix eval attr -f "./eval.nix")" == '{ foo = "bar"; }' ]]
Ericson2314 marked this conversation as resolved.
Show resolved Hide resolved
[[ $(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 ]]

nix-instantiate --eval -E 'assert 1 + 2 == 3; true'
[[ $(nix-instantiate -A int --eval "./eval.nix") == 123 ]]
[[ $(nix-instantiate -A str --eval "./eval.nix") == '"foo"' ]]
[[ $(nix-instantiate -A attr --eval "./eval.nix") == '{ foo = "bar"; }' ]]
[[ "$(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
Expand Down