1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-28 09:31:16 +02:00

Merge pull request #8193 from hercules-ci/dry-strings

Deduplicate string literal rendering, fix 4909
This commit is contained in:
Robert Hensing 2023-04-17 11:19:40 +02:00 committed by GitHub
commit 9af9c260fc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 158 additions and 64 deletions

View file

@ -9,6 +9,7 @@
#include "filetransfer.hh"
#include "function-trace.hh"
#include "profiles.hh"
#include "print.hh"
#include <algorithm>
#include <chrono>
@ -104,18 +105,10 @@ void Value::print(const SymbolTable & symbols, std::ostream & str,
str << integer;
break;
case tBool:
str << (boolean ? "true" : "false");
printLiteralBool(str, boolean);
break;
case tString:
str << "\"";
for (const char * i = string.s; *i; i++)
if (*i == '\"' || *i == '\\') str << "\\" << *i;
else if (*i == '\n') str << "\\n";
else if (*i == '\r') str << "\\r";
else if (*i == '\t') str << "\\t";
else if (*i == '$' && *(i+1) == '{') str << "\\" << *i;
else str << *i;
str << "\"";
printLiteralString(str, string.s);
break;
case tPath:
str << path; // !!! escaping?

View file

@ -3,6 +3,7 @@
#include "eval.hh"
#include "symbol-table.hh"
#include "util.hh"
#include "print.hh"
#include <cstdlib>
@ -60,45 +61,12 @@ Pos::operator std::shared_ptr<AbstractPos>() const
return pos;
}
/* Displaying abstract syntax trees. */
static void showString(std::ostream & str, std::string_view s)
{
str << '"';
for (auto c : s)
if (c == '"' || c == '\\' || c == '$') str << "\\" << c;
else if (c == '\n') str << "\\n";
else if (c == '\r') str << "\\r";
else if (c == '\t') str << "\\t";
else str << c;
str << '"';
}
// FIXME: remove, because *symbols* are abstract and do not have a single
// textual representation; see printIdentifier()
std::ostream & operator <<(std::ostream & str, const SymbolStr & symbol)
{
std::string_view s = symbol;
if (s.empty())
str << "\"\"";
else if (s == "if") // FIXME: handle other keywords
str << '"' << s << '"';
else {
char c = s[0];
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_')) {
showString(str, s);
return str;
}
for (auto c : s)
if (!((c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') ||
c == '_' || c == '\'' || c == '-')) {
showString(str, s);
return str;
}
str << s;
}
return str;
return printIdentifier(str, s);
}
void Expr::show(const SymbolTable & symbols, std::ostream & str) const
@ -118,7 +86,7 @@ void ExprFloat::show(const SymbolTable & symbols, std::ostream & str) const
void ExprString::show(const SymbolTable & symbols, std::ostream & str) const
{
showString(str, s);
printLiteralString(str, s);
}
void ExprPath::show(const SymbolTable & symbols, std::ostream & str) const

78
src/libexpr/print.cc Normal file
View file

@ -0,0 +1,78 @@
#include "print.hh"
namespace nix {
std::ostream &
printLiteralString(std::ostream & str, const std::string_view string)
{
str << "\"";
for (auto i = string.begin(); i != string.end(); ++i) {
if (*i == '\"' || *i == '\\') str << "\\" << *i;
else if (*i == '\n') str << "\\n";
else if (*i == '\r') str << "\\r";
else if (*i == '\t') str << "\\t";
else if (*i == '$' && *(i+1) == '{') str << "\\" << *i;
else str << *i;
}
str << "\"";
return str;
}
std::ostream &
printLiteralBool(std::ostream & str, bool boolean)
{
str << (boolean ? "true" : "false");
return str;
}
std::ostream &
printIdentifier(std::ostream & str, std::string_view s) {
if (s.empty())
str << "\"\"";
else if (s == "if") // FIXME: handle other keywords
str << '"' << s << '"';
else {
char c = s[0];
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_')) {
printLiteralString(str, s);
return str;
}
for (auto c : s)
if (!((c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') ||
c == '_' || c == '\'' || c == '-')) {
printLiteralString(str, s);
return str;
}
str << s;
}
return str;
}
// FIXME: keywords
static bool isVarName(std::string_view s)
{
if (s.size() == 0) return false;
char c = s[0];
if ((c >= '0' && c <= '9') || c == '-' || c == '\'') return false;
for (auto & i : s)
if (!((i >= 'a' && i <= 'z') ||
(i >= 'A' && i <= 'Z') ||
(i >= '0' && i <= '9') ||
i == '_' || i == '-' || i == '\''))
return false;
return true;
}
std::ostream &
printAttributeName(std::ostream & str, std::string_view name) {
if (isVarName(name))
str << name;
else
printLiteralString(str, name);
return str;
}
}

48
src/libexpr/print.hh Normal file
View file

@ -0,0 +1,48 @@
#pragma once
/**
* @file
* @brief Common printing functions for the Nix language
*
* While most types come with their own methods for printing, they share some
* functions that are placed here.
*/
#include <iostream>
namespace nix {
/**
* Print a string as a Nix string literal.
*
* Quotes and fairly minimal escaping are added.
*
* @param s The logical string
*/
std::ostream & printLiteralString(std::ostream & o, std::string_view s);
inline std::ostream & printLiteralString(std::ostream & o, const char * s) {
return printLiteralString(o, std::string_view(s));
}
inline std::ostream & printLiteralString(std::ostream & o, const std::string & s) {
return printLiteralString(o, std::string_view(s));
}
/** Print `true` or `false`. */
std::ostream & printLiteralBool(std::ostream & o, bool b);
/**
* Print a string as an attribute name in the Nix expression language syntax.
*
* Prints a quoted string if necessary.
*/
std::ostream & printAttributeName(std::ostream & o, std::string_view s);
/**
* Print a string as an identifier in the Nix expression language syntax.
*
* FIXME: "identifier" is ambiguous. Identifiers do not have a single
* textual representation. They can be used in variable references,
* let bindings, left-hand sides or attribute names in a select
* expression, or something else entirely, like JSON. Use one of the
* `print*` functions instead.
*/
std::ostream & printIdentifier(std::ostream & o, std::string_view s);
}