add an ExprPrinter class, like ValuePrinter

To be used Shortly

Change-Id: I9def7975aa55f251eb8486391677771f7352d7ce
This commit is contained in:
Qyriad 2024-06-22 21:17:41 -06:00
parent 59bf6825ef
commit 139cfdfb53
2 changed files with 36 additions and 0 deletions

View file

@ -574,4 +574,10 @@ fmt_internal::HintFmt & fmt_internal::HintFmt::operator%(const ValuePrinter & va
return *this; return *this;
} }
std::ostream & operator<<(std::ostream & output, ExprPrinter const & printer)
{
printer.expr.show(printer.state.symbols, output);
return output;
}
} }

View file

@ -15,6 +15,8 @@
namespace nix { namespace nix {
struct Expr;
class EvalState; class EvalState;
struct Value; struct Value;
@ -50,6 +52,12 @@ void printValue(EvalState & state, std::ostream & str, Value & v, PrintOptions o
/** /**
* A partially-applied form of `printValue` which can be formatted using `<<` * A partially-applied form of `printValue` which can be formatted using `<<`
* without allocating an intermediate string. * without allocating an intermediate string.
* This class should not outlive the eval state or it will UAF.
* FIXME: This should take `nix::ref`s, to avoid that, but our eval methods all have
* EvalState &, not ref<EvalState>, and constructing a new shared_ptr to data that
* already has a shared_ptr is a much bigger footgun. In the current architecture of
* libexpr, using a ValuePrinter after an EvalState has been destroyed would be
* pretty hard.
*/ */
class ValuePrinter { class ValuePrinter {
friend std::ostream & operator << (std::ostream & output, const ValuePrinter & printer); friend std::ostream & operator << (std::ostream & output, const ValuePrinter & printer);
@ -73,4 +81,26 @@ std::ostream & operator<<(std::ostream & output, const ValuePrinter & printer);
template<> template<>
fmt_internal::HintFmt & fmt_internal::HintFmt::operator%(const ValuePrinter & value); fmt_internal::HintFmt & fmt_internal::HintFmt::operator%(const ValuePrinter & value);
/**
* A partially-applied form of Expr::show(), which can be formatted using `<<`
* without allocating an intermediate string.
* This class should not outlive the eval state or it will UAF.
* FIXME: This should take `nix::ref`s, to avoid that, but our eval methods all have
* EvalState &, not ref<EvalState>, and constructing a new shared_ptr to data that
* already has a shared_ptr is a much bigger footgun. In the current architecture of
* libexpr, using an ExprPrinter after an EvalState has been destroyed would be
* pretty hard.
*/
class ExprPrinter
{
/** The eval state used to get symbols. */
EvalState const & state;
/** The expression to print. */
Expr const & expr;
public:
ExprPrinter(EvalState const & state, Expr const & expr) : state(state), expr(expr) { }
friend std::ostream & operator << (std::ostream & output, ExprPrinter const & printer);
};
} }