#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 #include "fmt.hh" #include "print-options.hh" #include "print-elided.hh" namespace nix { struct Expr; class EvalState; struct Value; /** 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); /** * 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. * * 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); void printValue(EvalState & state, std::ostream & str, Value & v, PrintOptions options = PrintOptions {}); /** * A partially-applied form of `printValue` 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, 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 { friend std::ostream & operator << (std::ostream & output, const ValuePrinter & printer); private: EvalState & state; Value & value; PrintOptions options; public: ValuePrinter(EvalState & state, Value & value, PrintOptions options = PrintOptions {}) : state(state), value(value), options(options) { } }; std::ostream & operator<<(std::ostream & output, const ValuePrinter & printer); /** * `ValuePrinter` does its own ANSI formatting, so we don't color it * magenta. */ template<> 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, 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); }; }