forked from lix-project/lix
Deduplicate string literal rendering, fix 4909
This commit is contained in:
parent
8f0ec323ea
commit
4e0804c920
|
@ -40,6 +40,7 @@ extern "C" {
|
||||||
#include "markdown.hh"
|
#include "markdown.hh"
|
||||||
#include "local-fs-store.hh"
|
#include "local-fs-store.hh"
|
||||||
#include "progress-bar.hh"
|
#include "progress-bar.hh"
|
||||||
|
#include "value/print.hh"
|
||||||
|
|
||||||
#if HAVE_BOEHMGC
|
#if HAVE_BOEHMGC
|
||||||
#define GC_INCLUDE_NEW
|
#define GC_INCLUDE_NEW
|
||||||
|
@ -894,17 +895,6 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::ostream & printStringValue(std::ostream & str, const char * string) {
|
|
||||||
str << "\"";
|
|
||||||
for (const char * i = string; *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 str << *i;
|
|
||||||
str << "\"";
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// FIXME: lot of cut&paste from Nix's eval.cc.
|
// FIXME: lot of cut&paste from Nix's eval.cc.
|
||||||
|
@ -922,12 +912,14 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nBool:
|
case nBool:
|
||||||
str << ANSI_CYAN << (v.boolean ? "true" : "false") << ANSI_NORMAL;
|
str << ANSI_CYAN;
|
||||||
|
printLiteral(str, v.boolean);
|
||||||
|
str << ANSI_NORMAL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nString:
|
case nString:
|
||||||
str << ANSI_WARNING;
|
str << ANSI_WARNING;
|
||||||
printStringValue(str, v.string.s);
|
printLiteral(str, v.string.s);
|
||||||
str << ANSI_NORMAL;
|
str << ANSI_NORMAL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -967,7 +959,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
|
||||||
if (isVarName(i.first))
|
if (isVarName(i.first))
|
||||||
str << i.first;
|
str << i.first;
|
||||||
else
|
else
|
||||||
printStringValue(str, i.first.c_str());
|
printLiteral(str, i.first);
|
||||||
str << " = ";
|
str << " = ";
|
||||||
if (seen.count(i.second))
|
if (seen.count(i.second))
|
||||||
str << "«repeated»";
|
str << "«repeated»";
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "filetransfer.hh"
|
#include "filetransfer.hh"
|
||||||
#include "function-trace.hh"
|
#include "function-trace.hh"
|
||||||
#include "profiles.hh"
|
#include "profiles.hh"
|
||||||
|
#include "value/print.hh"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
@ -104,18 +105,10 @@ void Value::print(const SymbolTable & symbols, std::ostream & str,
|
||||||
str << integer;
|
str << integer;
|
||||||
break;
|
break;
|
||||||
case tBool:
|
case tBool:
|
||||||
str << (boolean ? "true" : "false");
|
printLiteral(str, boolean);
|
||||||
break;
|
break;
|
||||||
case tString:
|
case tString:
|
||||||
str << "\"";
|
printLiteral(str, string.s);
|
||||||
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 << "\"";
|
|
||||||
break;
|
break;
|
||||||
case tPath:
|
case tPath:
|
||||||
str << path; // !!! escaping?
|
str << path; // !!! escaping?
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
#include "symbol-table.hh"
|
#include "symbol-table.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
#include "value/print.hh"
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
@ -62,18 +63,6 @@ Pos::operator std::shared_ptr<AbstractPos>() const
|
||||||
|
|
||||||
/* Displaying abstract syntax trees. */
|
/* 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 << '"';
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream & operator <<(std::ostream & str, const SymbolStr & symbol)
|
std::ostream & operator <<(std::ostream & str, const SymbolStr & symbol)
|
||||||
{
|
{
|
||||||
std::string_view s = symbol;
|
std::string_view s = symbol;
|
||||||
|
@ -85,7 +74,7 @@ std::ostream & operator <<(std::ostream & str, const SymbolStr & symbol)
|
||||||
else {
|
else {
|
||||||
char c = s[0];
|
char c = s[0];
|
||||||
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_')) {
|
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_')) {
|
||||||
showString(str, s);
|
printLiteral(str, s);
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
for (auto c : s)
|
for (auto c : s)
|
||||||
|
@ -93,7 +82,7 @@ std::ostream & operator <<(std::ostream & str, const SymbolStr & symbol)
|
||||||
(c >= 'A' && c <= 'Z') ||
|
(c >= 'A' && c <= 'Z') ||
|
||||||
(c >= '0' && c <= '9') ||
|
(c >= '0' && c <= '9') ||
|
||||||
c == '_' || c == '\'' || c == '-')) {
|
c == '_' || c == '\'' || c == '-')) {
|
||||||
showString(str, s);
|
printLiteral(str, s);
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
str << s;
|
str << s;
|
||||||
|
@ -118,7 +107,7 @@ void ExprFloat::show(const SymbolTable & symbols, std::ostream & str) const
|
||||||
|
|
||||||
void ExprString::show(const SymbolTable & symbols, std::ostream & str) const
|
void ExprString::show(const SymbolTable & symbols, std::ostream & str) const
|
||||||
{
|
{
|
||||||
showString(str, s);
|
printLiteral(str, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprPath::show(const SymbolTable & symbols, std::ostream & str) const
|
void ExprPath::show(const SymbolTable & symbols, std::ostream & str) const
|
||||||
|
|
26
src/libexpr/value/print.cc
Normal file
26
src/libexpr/value/print.cc
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#include "value/print.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
std::ostream &
|
||||||
|
printLiteral(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 &
|
||||||
|
printLiteral(std::ostream & str, bool boolean) {
|
||||||
|
str << (boolean ? "true" : "false");
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
30
src/libexpr/value/print.hh
Normal file
30
src/libexpr/value/print.hh
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#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 & printLiteral(std::ostream & o, std::string_view s);
|
||||||
|
inline std::ostream & printLiteral(std::ostream & o, const char * s) {
|
||||||
|
return printLiteral(o, std::string_view(s));
|
||||||
|
}
|
||||||
|
inline std::ostream & printLiteral(std::ostream & o, const std::string & s) {
|
||||||
|
return printLiteral(o, std::string_view(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Print `true` or `false`. */
|
||||||
|
std::ostream & printLiteral(std::ostream & o, bool b);
|
||||||
|
}
|
|
@ -313,6 +313,15 @@ Derivation parseDerivation(const Store & store, std::string && s, std::string_vi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print a derivation string literal to an std::string.
|
||||||
|
*
|
||||||
|
* This syntax does not generalize to the expression language, which needs to
|
||||||
|
* escape `$`.
|
||||||
|
*
|
||||||
|
* @param res Where to print to
|
||||||
|
* @param s Which logical string to print
|
||||||
|
*/
|
||||||
static void printString(std::string & res, std::string_view s)
|
static void printString(std::string & res, std::string_view s)
|
||||||
{
|
{
|
||||||
boost::container::small_vector<char, 64 * 1024> buffer;
|
boost::container::small_vector<char, 64 * 1024> buffer;
|
||||||
|
|
|
@ -79,6 +79,14 @@ testReplResponse '
|
||||||
"result: ${a}"
|
"result: ${a}"
|
||||||
' "result: 2"
|
' "result: 2"
|
||||||
|
|
||||||
|
# check dollar escaping https://github.com/NixOS/nix/issues/4909
|
||||||
|
# note the escaped \,
|
||||||
|
# \\
|
||||||
|
# because the second argument is a regex
|
||||||
|
testReplResponse '
|
||||||
|
"$" + "{hi}"
|
||||||
|
' '"\\${hi}"'
|
||||||
|
|
||||||
testReplResponse '
|
testReplResponse '
|
||||||
drvPath
|
drvPath
|
||||||
' '".*-simple.drv"' \
|
' '".*-simple.drv"' \
|
||||||
|
|
Loading…
Reference in a new issue