From 4ec43bed5e1f6077402301aeee125870f755267b Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Tue, 25 Oct 2022 01:56:42 -0700 Subject: fix(tvix/eval): quote keys which are not valid identifiers The impl Display for NixAttrs needs to wrap double quotes around any keys which are not valid Nix identifiers. This commit does that, and adds a test (which fails prior to this commit and passes after this commit). Change-Id: Ie31ce91e8637cb27073f23f115db81feefdc6424 Reviewed-on: https://cl.tvl.fyi/c/depot/+/7084 Autosubmit: Adam Joseph Reviewed-by: tazjin Tested-by: BuildkiteCI --- .../tvix_tests/eval-okay-escapify-integer-keys.exp | 1 + .../tvix_tests/eval-okay-escapify-integer-keys.nix | 1 + tvix/eval/src/value/string.rs | 25 +++++++++++++++++++++- 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 tvix/eval/src/tests/tvix_tests/eval-okay-escapify-integer-keys.exp create mode 100644 tvix/eval/src/tests/tvix_tests/eval-okay-escapify-integer-keys.nix diff --git a/tvix/eval/src/tests/tvix_tests/eval-okay-escapify-integer-keys.exp b/tvix/eval/src/tests/tvix_tests/eval-okay-escapify-integer-keys.exp new file mode 100644 index 000000000000..aa98a082a8ac --- /dev/null +++ b/tvix/eval/src/tests/tvix_tests/eval-okay-escapify-integer-keys.exp @@ -0,0 +1 @@ +{ "3" = 3; } diff --git a/tvix/eval/src/tests/tvix_tests/eval-okay-escapify-integer-keys.nix b/tvix/eval/src/tests/tvix_tests/eval-okay-escapify-integer-keys.nix new file mode 100644 index 000000000000..aa98a082a8ac --- /dev/null +++ b/tvix/eval/src/tests/tvix_tests/eval-okay-escapify-integer-keys.nix @@ -0,0 +1 @@ +{ "3" = 3; } diff --git a/tvix/eval/src/value/string.rs b/tvix/eval/src/value/string.rs index 4caef653f2cc..66697a7f2f4f 100644 --- a/tvix/eval/src/value/string.rs +++ b/tvix/eval/src/value/string.rs @@ -118,7 +118,13 @@ impl NixString { match escaped { // A borrowed string is unchanged and can be returned as // is. - Cow::Borrowed(_) => escaped, + Cow::Borrowed(_) => { + if is_valid_nix_identifier(&escaped) { + escaped + } else { + Cow::Owned(format!("\"{}\"", escaped)) + } + } // An owned string has escapes, and needs the outer quotes // for display. @@ -152,6 +158,23 @@ fn nix_escape_char(ch: char, next: Option<&char>) -> Option<&'static str> { } } +/// Return true if this string can be used as an identifier in Nix. +fn is_valid_nix_identifier(s: &str) -> bool { + // adapted from rnix-parser's tokenizer.rs + let mut chars = s.chars(); + match chars.next() { + Some('a'..='z' | 'A'..='Z' | '_') => (), + _ => return false, + } + for c in chars { + match c { + 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '-' => (), + _ => return false, + } + } + return true; +} + /// Escape a Nix string for display, as most user-visible representation /// are escaped strings. /// -- cgit 1.4.1