pretty printing -- copmlete for xo::ast::GeneralizedExpression

This commit is contained in:
Roland Conybeare 2025-07-19 11:47:03 -05:00
commit 2e0846823b
67 changed files with 1230 additions and 478 deletions

View file

@ -101,7 +101,7 @@ namespace xo {
virtual void attach_envs(bp<Environment> p) override;
virtual void display(std::ostream & os) const override;
virtual std::uint32_t pretty_print(ppstate * pps, bool upto) const override;
virtual std::uint32_t pretty_print(const ppindentinfo & ppii) const override;
private:
Apply(TypeDescr apply_valuetype,

View file

@ -40,6 +40,7 @@ namespace xo {
virtual void attach_envs(bp<Environment> p) override;
virtual void display(std::ostream & os) const override;
virtual std::uint32_t pretty_print(const ppindentinfo & ppii) const override;
private:
AssignExpr(const rp<Variable> & lhs,

View file

@ -6,6 +6,7 @@
#pragma once
#include "ConstantInterface.hpp"
#include "pretty_expression.hpp"
#include <type_traits>
namespace xo {
@ -70,11 +71,17 @@ namespace xo {
if (value_td_)
os << xtag("type", value_td_->short_name());
else
os << xtag("type", "nullptr");;
os << xtag("type", "nullptr");
os << xtag("value", value_);
os << ">";
}
virtual std::uint32_t pretty_print(const ppindentinfo & ppii) const override {
return ppii.pps()->pretty_struct(ppii, "Constant",
rtag("type", print::quot(this->valuetype()->short_name())),
refrtag("value", value_));
}
private:
explicit Constant(TypeDescr x_type, const T & x)
: ConstantInterface(exprtype::constant, x_type),

View file

@ -66,6 +66,7 @@ namespace xo {
}
virtual void display(std::ostream & os) const override;
virtual std::uint32_t pretty_print(const ppindentinfo & ppii) const override;
protected:
ConvertExpr(TypeDescr dest_type,

View file

@ -76,7 +76,7 @@ namespace xo {
}
virtual void display(std::ostream & os) const override;
virtual std::uint32_t pretty_print(ppstate * pps, bool upto) const override;
virtual std::uint32_t pretty_print(const ppindentinfo & ppii) const override;
protected:
/**

View file

@ -7,8 +7,10 @@
#include "xo/refcnt/Refcounted.hpp"
#include "binding_path.hpp"
#include "xo/indentlog/print/pretty.hpp"
namespace xo {
namespace ast {
class Expression;
@ -35,6 +37,7 @@ namespace xo {
virtual bp<Expression> lookup_var(const std::string & vname) const = 0;
virtual void print(std::ostream & os) const = 0;
virtual std::uint32_t pretty_print(const xo::print::ppindentinfo & ppii) const = 0;
};
inline std::ostream &

View file

@ -22,6 +22,7 @@ namespace xo {
public:
using TypeDescr = xo::reflect::TypeDescr;
using ppstate = xo::print::ppstate;
using ppindentinfo = xo::print::ppindentinfo;
public:
GeneralizedExpression(exprtype extype, TypeDescr valuetype)
@ -35,7 +36,7 @@ namespace xo {
/** human-readable string representation **/
virtual std::string display_string() const;
/** pretty printing support. See [xo-indentlog/xo/indentlog/pretty.hpp] **/
virtual std::uint32_t pretty_print(ppstate * pps, bool upto) const;
virtual std::uint32_t pretty_print(const ppindentinfo & ppii) const = 0;
protected:
/** useful when scaffolding expressions in a parser **/
@ -59,4 +60,4 @@ namespace xo {
} /*namespace xo*/
/** end GeneralizedExpression.hpp **/
/* end GeneralizedExpression.hpp */

View file

@ -42,6 +42,7 @@ namespace xo {
}
virtual void print(std::ostream & os) const override;
virtual std::uint32_t pretty_print(const xo::print::ppindentinfo & ppii) const override;
private:
GlobalEnv();

View file

@ -6,7 +6,7 @@
#pragma once
#include "Expression.hpp"
#include <vector>
//#include <vector>
#include <string>
//#include <cstdint>
@ -102,6 +102,7 @@ namespace xo {
#endif
virtual void display(std::ostream & os) const override;
virtual std::uint32_t pretty_print(const ppindentinfo & ppi) const override;
private:
/**

View file

@ -98,7 +98,7 @@ namespace xo {
virtual void attach_envs(bp<Environment> p) override;
virtual void display(std::ostream & os) const override;
virtual std::uint32_t pretty_print(ppstate * pps, bool upto) const override;
virtual std::uint32_t pretty_print(const ppindentinfo & ppii) const override;
protected:
/** create type description for lambda with arguments @p argv

View file

@ -79,6 +79,7 @@ namespace xo {
}
virtual void print(std::ostream & os) const override;
virtual std::uint32_t pretty_print(const print::ppindentinfo & ppii) const override;
private:
LocalEnv(const std::vector<rp<Variable>> & argv, const rp<Environment> & parent_env);
@ -103,12 +104,6 @@ namespace xo {
};
} /*namespace ast*/
#ifndef ppdetail_atomic
namespace print {
PPDETAIL_ATOMIC(xo::ast::LocalEnv);
}
#endif
} /*namespace xo*/

View file

@ -6,9 +6,10 @@
#pragma once
#include "PrimitiveInterface.hpp"
#include "pretty_expression.hpp"
#include "llvmintrinsic.hpp"
#include "xo/reflect/Reflect.hpp"
//#include <cstdint>
#include "xo/indentlog/print/quoted.hpp"
extern "C" {
/* these symbols needed to link primitives */
@ -90,6 +91,53 @@ namespace xo {
<< ">";
}
virtual std::uint32_t pretty_print(const ppindentinfo & ppii) const override {
/* 1. rtag instead of refrtag:
* print::quot() is a temporary rvalue; lifetime ends before control enters pretty_struct()
*
* 2. value cast to void*:
* we don't have pretty printer for native function pointers anyway
* + simplifies ppdetail_atomic
*/
return ppii.pps()->pretty_struct(ppii, "Primitive",
refrtag("name", name_),
rtag("type", print::quot(this->valuetype()->short_name())),
refrtag("value", (void*)(this->value())));
#ifdef OBSOLETE
ppstate * pps = ppii.pps();
if (ppii.upto()) {
if (!pps->print_upto("<Primitive"))
return false;
if (!pps->print_upto_tag("name", name_))
return false;
if (!pps->print_upto_tag("type", print::quot(this->value_td()->short_name())))
return false;
if (!pps->print_upto_tag("value", (void*)(this->value())))
return false;
pps->write(">");
return true;
} else {
pps->write("<Primitive");
pps->newline_pretty_tag(ppii.ci1(), "name", name_);
pps->newline_pretty_tag(ppii.ci1(), "type", print::quot(this->value_td()->short_name()));
/* don't have pretty printer for native function pointers anyway
* + simplifies ppdetail_atomic
*/
pps->newline_pretty_tag(ppii.ci1(), "value", (void*)this->value());
pps->write(">");
return false;
}
#endif
}
private:
Primitive(TypeDescr fn_type,
const std::string & name,

View file

@ -6,7 +6,6 @@
#pragma once
#include "Expression.hpp"
//#include <cstdint>
namespace xo {
namespace ast {
@ -38,7 +37,7 @@ namespace xo {
// ----- from GeneralizedExpression ----
virtual void display(std::ostream & os) const override;
virtual std::uint32_t pretty_print(ppstate * pps, bool upto) const override;
virtual std::uint32_t pretty_print(const ppindentinfo & ppii) const override;
private:
/** sequence of expressions; evaluate in left-to-right order.
@ -49,5 +48,4 @@ namespace xo {
} /*namespace xo*/
/** end Sequence.hpp **/

View file

@ -65,6 +65,7 @@ namespace xo {
virtual void attach_envs(bp<Environment> /*p*/) override;
virtual void display(std::ostream & os) const override;
virtual std::uint32_t pretty_print(const ppindentinfo & ppii) const override;
private:
Variable(const std::string & name,

View file

@ -6,7 +6,6 @@
#pragma once
#include "xo/indentlog/print/pretty.hpp"
#include "xo/indentlog/print/pretty_tag.hpp"
#include "xo/refcnt/pretty_refcnt.hpp"
#include "Expression.hpp"
@ -14,23 +13,17 @@ namespace xo {
namespace print {
template<>
struct ppdetail<xo::ast::GeneralizedExpression> {
static bool print_upto(ppstate * pps, const xo::ast::GeneralizedExpression & x) {
return x.pretty_print(pps, true);
}
static void print_pretty(ppstate * pps, const xo::ast::GeneralizedExpression & x) {
x.pretty_print(pps, false);
static bool print_pretty(const ppindentinfo & ppii,
const xo::ast::GeneralizedExpression & x) {
return x.pretty_print(ppii);
}
};
template <>
struct ppdetail<xo::ast::Expression> {
static bool print_upto(ppstate * pps, const xo::ast::Expression & x) {
return x.pretty_print(pps, true);
}
static void print_pretty(ppstate * pps, const xo::ast::Expression & x) {
x.pretty_print(pps, false);
static bool print_pretty(const ppindentinfo & ppii,
const xo::ast::Expression & x) {
return x.pretty_print(ppii);
}
};
}

View file

@ -0,0 +1,18 @@
/* @file pretty_localenv.hpp */
#pragma once
#include "xo/indentlog/print/pretty.hpp"
#include "xo/refcnt/pretty_refcnt.hpp"
#include "LocalEnv.hpp"
namespace xo {
namespace print {
template <>
struct ppdetail<xo::ast::LocalEnv> {
static bool print_pretty(const ppindentinfo & ppii, const xo::ast::LocalEnv & x) {
return x.pretty_print(ppii);
}
};
}
}

View file

@ -0,0 +1,20 @@
/* file pretty_variable.hpp
*
* author: Roland Conybeare, Jul 2025
*/
#pragma once
#include "pretty_expression.hpp"
#include "Variable.hpp"
namespace xo {
namespace print {
template <>
struct ppdetail<xo::ast::Variable> {
static bool print_pretty(const ppindentinfo & ppii, const xo::ast::Expression & x) {
return x.pretty_print(ppii);
}
};
}
}

View file

@ -3,7 +3,9 @@
#include "Apply.hpp"
#include "Primitive.hpp"
#include "exprtype.hpp"
#include "pretty_expression.hpp"
#include "xo/indentlog/print/vector.hpp"
#include "xo/indentlog/print/pretty_vector.hpp"
#include <cstdint>
namespace xo {
@ -77,39 +79,35 @@ namespace xo {
}
std::uint32_t
Apply::pretty_print(ppstate * pps, bool upto) const
Apply::pretty_print(const ppindentinfo & ppii) const
{
if (upto) {
std::uint32_t saved = pps->pos();
return ppii.pps()->pretty_struct(ppii, "Apply",
refrtag("fn", fn_),
refrtag("argv", argv_));
if (!pps->has_margin())
return false;
#ifdef OBSOLETE
ppstate * pps = ppii.pps();
if (ppii.upto()) {
if (!pps->print_upto("<Apply"))
return false;
if (!pps->print_upto(xtag("fn", fn_)))
if (!pps->print_upto_tag("fn", fn_))
return false;
if (!pps->print_upto(xtag("argv", argv_)))
if (!pps->print_upto_tag("argv", argv_))
return false;
return pps->scan_no_newline(saved);
return true;
} else {
std::uint32_t ci0 = pps->lpos();
std::uint32_t ci1 = ci0 + pps->indent_width();
pps->write("<Apply");
pps->newline_indent(ci1);
pps->pretty(xtag("fn", fn_));
pps->newline_indent(ci1);
pps->pretty(xtag("argv", argv_));
pps->newline_pretty_tag(ppii.ci1(), "fn", fn_);
pps->newline_pretty_tag(ppii.ci1(), "argv", argv_);
pps->write(">");
return false;
}
#endif
}
} /*namespace ast*/

View file

@ -4,7 +4,10 @@
*/
#include "AssignExpr.hpp"
#include "pretty_expression.hpp"
#include "pretty_variable.hpp"
#include "xo/indentlog/print/tag.hpp"
#include <cstdint>
namespace xo {
namespace ast {
@ -86,6 +89,13 @@ namespace xo {
<< xtag("rhs", rhs_)
<< ">";
}
std::uint32_t
AssignExpr::pretty_print(const ppindentinfo & ppii) const {
return ppii.pps()->pretty_struct(ppii, "AssignExpr",
refrtag("lhs", lhs_),
refrtag("rhs", rhs_));
}
} /*namespace ast*/
} /*namespace xo*/

View file

@ -4,6 +4,7 @@
*/
#include "ConvertExpr.hpp"
#include "pretty_expression.hpp"
namespace xo {
namespace ast {
@ -31,6 +32,13 @@ namespace xo {
<< ">";
}
std::uint32_t
ConvertExpr::pretty_print(const ppindentinfo & ppii) const {
return ppii.pps()->pretty_struct(ppii, "Convert",
rtag("dest_type", print::quot(this->valuetype()->short_name())),
refrtag("arg", arg_));
}
// ----- ConvertExprAccess -----
rp<ConvertExprAccess>

View file

@ -6,7 +6,6 @@
#include "DefineExpr.hpp"
#include "Variable.hpp"
#include "pretty_expression.hpp"
#include "xo/indentlog/print/pretty_tag.hpp"
#include <cstdint>
namespace xo {
@ -65,39 +64,33 @@ namespace xo {
} /*display*/
std::uint32_t
DefineExpr::pretty_print(ppstate * pps, bool upto) const
DefineExpr::pretty_print(const ppindentinfo & ppii) const
{
if (upto) {
std::uint32_t saved = pps->pos();
return ppii.pps()->pretty_struct(ppii, "Define",
refrtag("name", lhs_name_),
refrtag("rhs", rhs_));
if (!pps->has_margin())
return false;
#ifdef OBSOLETE
ppstate * pps = ppii.pps();
if (ppii.upto()) {
if (!pps->print_upto("<Define"))
return false;
if (!pps->print_upto(xtag("name", lhs_name_)))
if (!pps->print_upto_tag("name", lhs_name_))
return false;
if (!pps->print_upto_tag("rhs", rhs_))
return false;
if (!pps->print_upto(xtag("rhs", rhs_)))
return false;
return pps->scan_no_newline(saved);
return true;
} else {
std::uint32_t ci0 = pps->lpos();
std::uint32_t ci1 = ci0 + pps->indent_width();
pps->write("<Define");
pps->newline_indent(ci1);
pps->pretty(xtag("name", lhs_name_));
pps->newline_indent(ci1);
pps->pretty(xtag("rhs", rhs_));
pps->newline_pretty_tag(ppii.ci1(), "name", lhs_name_);
pps->newline_pretty_tag(ppii.ci1(), "rhs", rhs_);
pps->write(">");
return false;
}
#endif
}
// ----- DefineExprAccess -----

View file

@ -11,19 +11,28 @@ namespace xo {
return tostr(*this);
}
#ifdef SUPERSEDED // currently all derived expression types support pretty printing
std::uint32_t
GeneralizedExpression::pretty_print(ppstate * pps, bool upto) const {
GeneralizedExpression::pretty_print(const ppindentinfo & ppii) const {
// Slooooow fallback for subtypes that don't implement pretty printing support
// Currently have support for:
// - Variable
// - Lambda
// - DefineExpr
// - Sequence
// - Apply
// - Primitive
// - IfExpr
ppstate * pps = ppii.pps();
std::uint32_t saved = pps->pos();
pps->write(display_string());
if (upto && !pps->has_margin())
if (ppii.upto() && !pps->has_margin())
return false;
return upto ? pps->scan_no_newline(saved) : true;
return ppii.upto() ? pps->scan_no_newline(saved) : true;
}
#endif
} /*namespace ast*/
} /*namespace xo*/

View file

@ -20,7 +20,33 @@ namespace xo {
void
GlobalEnv::print(std::ostream & os) const {
os << "<globalenv" << xtag("size", global_map_.size()) << ">";
os << "<GlobalEnv"
<< xtag("size", global_map_.size())
<< ">";
}
std::uint32_t
GlobalEnv::pretty_print(const xo::print::ppindentinfo & ppii) const
{
using xo::print::ppstate;
ppstate * pps = ppii.pps();
if (ppii.upto()) {
if (!pps->print_upto("<GlobalEnv"))
return false;
if (!pps->print_upto_tag("size", global_map_.size()))
return false;
pps->write(">");
return true;
} else {
pps->write("<GlobalEnv");
pps->newline_pretty_tag(ppii.ci1(), "size", global_map_.size());
pps->write(">");
return false;
}
}
} /*namespace ast*/
} /*namespace xo*/

View file

@ -1,7 +1,9 @@
/* @file IfExpr.cpp */
#include "IfExpr.hpp"
#include "xo/indentlog/print/vector.hpp"
#include "pretty_expression.hpp"
#include "pretty_variable.hpp"
//#include "xo/indentlog/print/vector.hpp"
namespace xo {
namespace ast {
@ -38,6 +40,14 @@ namespace xo {
<< xtag("when_false", when_false_)
<< ">";
} /*display*/
std::uint32_t
IfExpr::pretty_print(const ppindentinfo & ppii) const {
return ppii.pps()->pretty_struct(ppii, "IfExpr",
refrtag("test", test_),
refrtag("when_true", when_true_),
refrtag("when_false", when_false_));
}
} /*namespace ast*/
} /*namespace xo*/

View file

@ -3,11 +3,11 @@
#include "Lambda.hpp"
#include "exprtype.hpp"
#include "pretty_expression.hpp"
#include "pretty_variable.hpp"
#include "xo/reflect/TypeDescr.hpp"
#include "xo/reflect/function/FunctionTdx.hpp"
#include "xo/indentlog/print/vector.hpp"
#include "xo/indentlog/print/pretty_vector.hpp"
#include "xo/indentlog/print/pretty_tag.hpp"
#include <map>
#include <sstream>
@ -322,47 +322,38 @@ namespace xo {
} /*display*/
std::uint32_t
Lambda::pretty_print(ppstate * pps, bool upto) const
Lambda::pretty_print(const ppindentinfo & ppii) const
{
if (upto) {
std::uint32_t saved = pps->pos();
return ppii.pps()->pretty_struct(ppii, "Lambda",
refrtag("name", name_),
refrtag("argv", local_env_->argv()),
refrtag("body", body_));
if (!pps->has_margin())
return false;
#ifdef OBSOLETE
ppstate * pps = ppii.pps();
if (ppii.upto()) {
if (!pps->print_upto("<Lambda"))
return false;
if (!pps->print_upto(xtag("name", name_)))
if (!pps->print_upto_tag("name", name_))
return false;
if (!pps->print_upto(xtag("argv", local_env_->argv())))
if (!pps->print_upto_tag("argv", local_env_->argv()))
return false;
if (!pps->print_upto(xtag("body", body_)))
if (!pps->print_upto_tag("body", body_))
return false;
pps->write(">");
return pps->scan_no_newline(saved);
return true;
} else {
std::uint32_t ci0 = pps->lpos();
std::uint32_t ci1 = ci0 + pps->indent_width();
pps->write("<Lambda");
pps->newline_indent(ci1);
pps->pretty(xtag("name", name_));
pps->newline_indent(ci1);
pps->pretty(xtag("argv", local_env_->argv()));
pps->newline_indent(ci1);
pps->pretty(xtag("body", body_));
pps->newline_pretty_tag(ppii.ci1(), "name", name_);
pps->newline_pretty_tag(ppii.ci1(), "argv", local_env_->argv());
pps->newline_pretty_tag(ppii.ci1(), "body", body_);
pps->write(">");
return false;
}
#endif
}
// ----- Lambda Access -----
@ -413,5 +404,4 @@ namespace xo {
} /*namespace ast*/
} /*namespace xo*/
/* end Lambda.cpp */

View file

@ -4,8 +4,11 @@
*/
#include "LocalEnv.hpp"
#include "pretty_variable.hpp"
#include "xo/indentlog/print/pretty_vector.hpp"
#include "xo/indentlog/print/vector.hpp"
namespace xo {
namespace ast {
rp<LocalEnv>
@ -112,6 +115,33 @@ namespace xo {
<< xtag("argv", argv_)
<< ">";
}
std::uint32_t
LocalEnv::pretty_print(const xo::print::ppindentinfo & ppii) const {
using xo::print::ppstate;
ppstate * pps = ppii.pps();
if (ppii.upto()) {
if (!pps->print_upto("<LocalEnv"))
return false;
if (!pps->print_upto_tag("this", (void*)this))
return false;
if (!pps->print_upto_tag("argv", argv_))
return false;
pps->write(">");
return true;
} else {
pps->write("<LocalEnv");
pps->newline_pretty_tag(ppii.ci1(), "this", (void*)this);
pps->newline_pretty_tag(ppii.ci1(), "argv", argv_);
pps->write(">");
return false;
}
}
} /*namespace ast*/
} /*namespace xo*/

View file

@ -74,14 +74,11 @@ namespace xo {
}
std::uint32_t
Sequence::pretty_print(ppstate * pps, bool upto) const
Sequence::pretty_print(const ppindentinfo & ppii) const
{
if (upto) {
std::uint32_t saved = pps->pos();
if (!pps->has_margin())
return false;
ppstate * pps = ppii.pps();
if (ppii.upto()) {
if (!pps->print_upto("<Sequence"))
return false;
@ -91,8 +88,7 @@ namespace xo {
return false;
std::string i_str = tostr("[", i, "]");
if (!pps->print_upto(xtag(i_str.c_str(), expr_i)))
if (!pps->print_upto_tag(i_str.c_str(), expr_i))
return false;
++i;
}
@ -100,19 +96,18 @@ namespace xo {
if (!pps->has_margin())
return false;
return pps->scan_no_newline(saved);
} else {
std::uint32_t ci0 = pps->lpos();
std::uint32_t ci1 = ci0 + pps->indent_width();
pps->write(">");
return true;
} else {
pps->write("<Sequence");
std::size_t i = 0;
for (const auto & expr_i : expr_v_) {
std::string i_str = tostr("[", i, "]");
pps->newline_indent(ci1);
pps->pretty(xtag(i_str.c_str(), expr_i));
pps->newline_pretty_tag(ppii.ci1(),
i_str.c_str(),
expr_i);
++i;
}

View file

@ -2,6 +2,7 @@
#include "Variable.hpp"
#include "Environment.hpp"
#include "pretty_expression.hpp"
namespace xo {
namespace ast {
@ -37,6 +38,59 @@ namespace xo {
os << xtag("type", "nullptr");
os << ">";
} /*display*/
std::uint32_t
Variable::pretty_print(const ppindentinfo & ppii) const {
/* 1. rtag instead of refrtag:
* print::quot() is a temporary rvalue; lifetime ends before control enters pretty_struct()
*/
return ppii.pps()->pretty_struct(ppii, "Variable",
refrtag("name", name_),
rtag("type", print::quot(this->valuetype()
? this->valuetype()->short_name()
: "nullptr")));
#ifdef OBSOLETE
ppstate * pps = ppii.pps();
if (ppii.upto()) {
if (!pps->print_upto("<Variable"))
return false;
if (!pps->print_upto_tag("name", name_))
return false;
if (this->valuetype()) {
if (!pps->print_upto_tag("type", this->valuetype()->short_name()))
return false;
} else {
if (!pps->print_upto_tag("type", "nullptr"))
return false;
}
pps->write(">");
return true;
} else {
pps->write("<Variable");
pps->newline_pretty_tag(ppii.ci1(), "name", name_);
/* use tag instead of rtag for type,
* since not guaranteed to print machine-readably
*/
if (this->valuetype()) {
pps->newline_indent(ppii.ci1());
pps->pretty(xtag("type", this->valuetype()->short_name()));
} else {
pps->newline_pretty_tag(ppii.ci1(), "type", "nullptr");
}
pps->write(">");
return false;
}
#endif
}
} /*namespace ast*/
} /*namespace xo*/

View file

@ -636,6 +636,7 @@ namespace xo {
return ((s1 <=> s2) == std::strong_ordering::equal);
}
///@}
} /*namespace xo*/
/** end flatstring.hpp **/

View file

@ -0,0 +1,28 @@
/** @file flatstring_pretty.hpp
*
* Author: Roland Conybeare, Jul 2025
**/
#pragma once
#include "flatstring.hpp"
#include "flatstring_iostream.hpp"
#include "xo/indentlog/print/ppdetail_atomic.hpp"
namespace xo {
#ifndef ppdetail_atomic
namespace print {
struct ppindentinfo;
template <std::size_t N>
struct ppdetail<flatstring<N>> {
static bool print_pretty(const ppindentinfo & ppii,
const flatstring<N> & x) {
return ppdetail_atomic<flatstring<N>>::print_pretty(ppii, x);
};
};
}
#endif
}
/** end flatstring_pretty.hpp **/

View file

@ -4,8 +4,23 @@ Glossary
--------
.. glossary::
iff
| Short for "if and only if"
pp
| Short for `pretty printer`. For example in `ppdetail`, `toppstr`.
| Short for "pretty printer". For example in `ppdetail`, `toppstr`.
ppii
| Short for "pretty-print indent info"
pps
| Short for "pretty-print state"
rtag
| Shorthand for "raw tag"
xtag
| Shorthand for `tag with preceding space`
| Shorthand for "tag with preceding space"
xrtag
| Shorthand for "raw tag with preceding space"

View file

@ -16,6 +16,16 @@ namespace xo {
**/
template <typename CharT, typename Traits = std::char_traits<CharT>>
class log_streambuf : public std::streambuf {
public:
struct rewind_state {
explicit rewind_state(std::size_t solpos, std::size_t color_esc, std::uint32_t p)
: solpos{solpos}, color_escape_chars{color_esc}, pos{p} {}
std::size_t solpos = 0;
std::size_t color_escape_chars = 0;
std::uint32_t pos = 0;
};
public:
log_streambuf(std::uint32_t buf_z, bool debug_flag = false) : debug_flag_{debug_flag} {
this->buf_v_.resize(buf_z);
@ -27,8 +37,15 @@ namespace xo {
char const * hi() const { return this->lo() + this->capacity(); }
std::uint32_t pos() const { return this->pptr() - this->pbase(); }
/** number of characters since start of line (last \n or \r) **/
std::uint32_t lpos() const { return pos() - solpos_; }
/** number of visible characters since start of line (last \n or \r) **/
std::uint32_t lpos() const {
assert(pos() >= solpos_ + color_escape_chars_);
return pos() - solpos_ - color_escape_chars_;
}
rewind_state checkpoint() const {
return rewind_state(solpos_, color_escape_chars_, pos());
}
bool debug_flag() const { return debug_flag_; }
@ -40,12 +57,24 @@ namespace xo {
this->setp(p_lo, p_hi);
this->solpos_ = 0;
this->color_escape_chars_ = 0;
this->color_escape_start_ = nullptr;
} /*reset_stream*/
void rewind_to(std::uint32_t p) {
void rewind_to(rewind_state s) {
if (debug_flag_) {
std::cout << "rewind_to: pos " << pos() << "->" << s.pos
<< " solpos " << solpos_ << "->" << s.solpos
<< " color_esc " << color_escape_chars_ << "->" << s.color_escape_chars
<< std::endl;
}
/* .setp(): using for side effect: sets .pptr to .pbase */
this->setp(this->pbase(), this->epptr());
this->pbump(p);
this->pbump(s.pos);
this->solpos_ = s.solpos;
this->color_escape_chars_ = s.color_escape_chars;
}
protected:
@ -65,7 +94,7 @@ namespace xo {
this->setp(p_base, p_hi);
this->pbump(old_n);
} /*expand*/
}
virtual std::streamsize
xsputn(char const * s, std::streamsize n) override {
@ -94,7 +123,7 @@ namespace xo {
ncopied = n;
}
if (debug_flag_) {
if (false /*debug_flag_*/) {
std::cout << "xsputn: copying ncopied=" << ncopied << " (/n=" << n << ") bytes into range [lo,hi)"
<< ", lo=" << (void*)this->pptr()
<< ", hi=" << (void*)(this->pptr() + n)
@ -103,11 +132,39 @@ namespace xo {
std::memcpy(this->pptr(), s, ncopied);
/* scan range [pptr, pptr+n] backwards, to account for newline (if any) */
for (char const * p_lo = this->pptr(), * p_hi = p_lo + n - 1, * p = p_hi; p >= p_lo; --p) {
/* scan range [pptr, pptr+n] for:
* 1. completed color escape sequences \033..m
* - account for chars in these sequences, since non-printing
* 2. newlines (and carriage returns)
* - remember position of last {newline or carriage return)
*/
for (char const * p_lo = this->pptr(), * p_hi = p_lo + n, * p = p_lo; p < p_hi; ++p) {
if (*p == '\n' || *p == '\r') {
this->solpos_ = (p+1 - this->pbase());
break;
/* reset, since these chars relevant as correction to solpos */
this->color_escape_chars_ = 0;
/* -> incomplete color escape, broken by newline */
this->color_escape_start_ = nullptr;
} else if (*p == '\033') {
if (debug_flag_) {
std::cout << "xsputn: \\033 at p-p_lo=" << (p - p_lo) << std::endl;
}
this->color_escape_start_ = p;
} else if (this->color_escape_start_ != nullptr) {
if (*p == 'm') {
/* escape seq non-printing including both endpoints */
std::int64_t esc_chars = (p+1 - color_escape_start_);
this->color_escape_chars_ += esc_chars;
if (debug_flag_) {
std::cout << "xsputn: m at p-p_lo" << (p - p_lo) << " +" << esc_chars
<< " -> color_escape_chars=" << color_escape_chars_ << std::endl;
}
this->color_escape_start_ = nullptr;
} else if (!isdigit(*p) && (*p != '[') && (*p != ';')) {
/* not color escape after all */
this->color_escape_start_ = nullptr;
}
}
}
@ -117,8 +174,7 @@ namespace xo {
} /*xsputn*/
virtual int_type
overflow(int_type new_ch) override
{
overflow(int_type new_ch) override {
char * old_pptr = this->pptr();
std::streamsize old_n = old_pptr - this->pbase();
@ -133,8 +189,9 @@ namespace xo {
this->buf_v_[old_n] = new_ch;
this->pbump(1);
if ((new_ch == static_cast<int_type>('\n')) || (new_ch == static_cast<int_type>('\r')))
if ((new_ch == static_cast<int_type>('\n')) || (new_ch == static_cast<int_type>('\r'))) {
this->solpos_ = this->pos();
}
if (new_ch == Traits::eof()) {
/* reminder: returning eof sets badbit on ostream */
@ -154,6 +211,9 @@ namespace xo {
std::ios_base::seekdir dir,
std::ios_base::openmode which) override {
//std::cout << "seekoff: off=" << off << ", dir=" << dir << ", which=" << which << std::endl;
if (debug_flag_) {
std::cout << "seekoff(off,dir,which)" << std::endl;
}
// Only output stream is supported
if (which != std::ios_base::out)
@ -179,6 +239,13 @@ namespace xo {
* Use to drive @ref lpos
**/
std::size_t solpos_ = 0;
/** number of non-printing chars after @ref solpos_, from
* completed color escape sequences.
* (ansi color escapes = text between '\033' and 'm')
**/
std::size_t color_escape_chars_ = 0;
/** non-null: start of incomplete color escape sequence **/
char const * color_escape_start_ = nullptr;
/** buffered output stored here **/
std::vector<char> buf_v_;
/** true to debug log_streambuf itself **/

View file

@ -2,8 +2,8 @@
#pragma once
#include "ppdetail_atomic.hpp"
#include <ostream>
//#include <utility> // for std::move
#include <cstdint>
namespace xo {
@ -177,25 +177,42 @@ namespace xo {
template <typename Contents>
color_impl<Contents> with_color(color_spec_type const & spec, Contents && contents) {
return color_impl<Contents>(coloring_control_flags::all, spec, std::forward<Contents>(contents));
} /*with_color*/
}
inline color_impl<int>
color_on(color_spec_type const & spec) {
return color_impl<int>(coloring_control_flags::color_on, spec, 0);
} /*color_on*/
}
inline color_impl<int>
color_off(color_spec_type const & spec) {
/* any spec other than color_spec_type::none() works here */
return color_impl<int>(coloring_control_flags::color_off, spec, 0);
} /*color_off*/
}
template <typename Contents>
inline std::ostream &
operator<<(std::ostream & os, color_impl<Contents> const & x) {
x.print(os);
return os;
} /*operator<<*/
}
#ifndef ppdetail_atomic
namespace print {
/* concat expected to be used on short string-like things.
* i.e. don't want structure visible to pretty-printer.
* could be using it like concat("boeing", 777)
*/
template <typename Contents>
struct ppdetail<color_impl<Contents>> {
using target_type = color_impl<Contents>;
static bool print_pretty(const ppindentinfo & ppii, const target_type & x) {
return ppdetail_atomic<target_type>::print_pretty(ppii, x);
}
};
}
#endif
} /*namespace xo*/

View file

@ -48,11 +48,8 @@ namespace xo {
struct ppdetail<concat_impl<T1,T2>> {
using target_type = concat_impl<T1,T2>;
static bool print_upto(ppstate * pps, const target_type & x) {
return ppdetail_atomic<target_type>::print_upto(pps, x);
}
static void print_pretty(ppstate * pps, const target_type & x) {
ppdetail_atomic<target_type>::print_pretty(pps, x);
static bool print_pretty(const ppindentinfo & ppii, const target_type & x) {
return ppdetail_atomic<target_type>::print_pretty(ppii, x);
}
};
}

View file

@ -23,11 +23,14 @@ namespace xo {
* Pretty-printer will introduce newlines if needed
* to stay to the left of this margin
**/
std::uint32_t right_margin_ = 135;
std::uint32_t right_margin_ = 80;
/** amount of additional indent per nesting level **/
std::uint32_t indent_width_ = 2;
/** assert if attempting this much indent **/
std::uint32_t assert_indent_threshold = 10000;
///@}
};
} /*namespace print*/

View file

@ -11,13 +11,34 @@
namespace xo {
namespace print {
struct ppstate; // see pretty.hpp
struct ppindentinfo;
// Defining this means ppdetail_atomic is not used.
// In that case where not explicitly specialized ppdetail will revert to ordinary printing for a type,
// instead of giving compile-time error about missing template specialization of ppdetail
// instead of giving compile-time error about missing template specialization of ppdetail.
#define ppdetail_atomic ppdetail
struct ppindentinfo {
ppindentinfo(ppstate * pps, std::uint32_t ci0, std::uint32_t indent_width, bool upto)
: pps_{pps}, ci0_{ci0}, ci1_{ci0 + indent_width}, upto_{upto} {}
ppstate * pps() const { return pps_; }
std::uint32_t ci1() const { return ci1_; }
bool upto() const { return upto_; }
private:
ppstate * pps_ = nullptr;
/** current indent **/
std::uint32_t ci0_ = 0;
/** ci0 +1 indent level **/
std::uint32_t ci1_ = 0;
/**
* true -> print on remainder of current line, unless past right margin
* false -> pretty across across multiple lines
**/
bool upto_;
};
/** @class ppdetail
* @brief template for opt-in to pretty-printer
*
@ -32,65 +53,51 @@ namespace xo {
template <typename T>
struct ppdetail;
template <typename T>
struct ppdetail_atomic;
template <typename T>
struct ppdetail_atomic {
/** 1. print @p x to private stream @ref scratch_ss_
/** upto=true:
* 1. print @p x to private stream @ref scratch_ss_
* 2. return true iff N = number of characters printed satisfies N <= @p budget.
* content actually printed to *sbuf may be used as-is in this case
* 3. return false otherwise. Will trigger non-degenerate pretty-printing.
* 4. in any case consume some of @ref scratch_sbuf_
*
* upto=false:
* print @p x to private stream @ref scratch_ss_
**/
static bool print_upto(ppstate * pps, const T & x);
/** print @p x to private stream @ref scratch_ss_ **/
static void print_pretty(ppstate * pps, const T & x);
static bool print_pretty(const ppindentinfo & ppii, const T & x);
};
#ifndef ppdetail_atomic
template <int N>
struct ppdetail<const char[N]> {
using target_type = const char[N];
static bool print_upto(ppstate * pps, const target_type & x) {
return ppdetail_atomic<target_type>::print_upto(pps, x);
}
static void print_pretty(ppstate * pps, const target_type & x) {
ppdetail_atomic<target_type>::print_pretty(pps, x);
static bool print_pretty(const ppindentinfo & ppii, const target_type & x) {
return ppdetail_atomic<target_type>::print_pretty(ppii, x);
}
};
template <>
struct ppdetail<const char *> {
static bool print_upto(ppstate * pps, const char * x) {
return ppdetail_atomic<const char *>::print_upto(pps, x);
}
static void print_pretty(ppstate * pps, const char * x) {
ppdetail_atomic<const char *>::print_pretty(pps, x);
static bool print_pretty(const ppindentinfo & ppii, const char * x) {
return ppdetail_atomic<const char *>::print_pretty(ppii, x);
}
};
#define PPDETAIL_ATOMIC_BODY(target_type) \
struct ppdetail<target_type> { \
static bool print_upto(ppstate * pps, const target_type & x) { \
return ppdetail_atomic<target_type>::print_upto(pps, x); \
} \
\
static void print_pretty(ppstate * pps, const target_type & x) { \
ppdetail_atomic<target_type>::print_pretty(pps, x); \
static bool print_pretty(const ppindentinfo & ppii, \
const target_type & x) { \
return ppdetail_atomic<target_type>::print_pretty(ppii, x); \
} \
}
#define PPDETAIL_ATOMIC_BODY_CONST(target_type) \
struct ppdetail<const target_type> { \
static bool print_upto(ppstate * pps, const target_type & x) { \
return ppdetail_atomic<target_type>::print_upto(pps, x); \
} \
\
static void print_pretty(ppstate * pps, const target_type & x) { \
ppdetail_atomic<target_type>::print_pretty(pps, x); \
static bool print_pretty(const ppindentinfo & ppii, \
const target_type & x) { \
return ppdetail_atomic<target_type>::print_pretty(ppii, x); \
} \
}
@ -104,16 +111,18 @@ namespace xo {
PPDETAIL_ATOMIC(bool);
PPDETAIL_ATOMIC(char);
// PPDETAIL_ATOMIC_CONST(char);
PPDETAIL_ATOMIC(std::int64_t);
PPDETAIL_ATOMIC(std::uint64_t);
PPDETAIL_ATOMIC(std::int32_t);
PPDETAIL_ATOMIC(std::uint32_t);
PPDETAIL_ATOMIC(float);
PPDETAIL_ATOMIC(double);
PPDETAIL_ATOMIC(std::string);
PPDETAIL_ATOMIC(std::string_view);
using voidptr = void*;
PPDETAIL_ATOMIC(voidptr);
#endif
}
}
} /*namespace print*/
} /*namespace xo*/

View file

@ -94,21 +94,26 @@ namespace xo {
/** implement pretty-printing for template @c ppconcat r**/
template <typename... Args>
struct ppdetail<ppconcat<Args...>> {
/** try to print @p target on one line.
/** upto=true:
* try to print @p target on one line.
* return false if budget (space until right margin) exhausted
* or if an embedded newline appears
*
* @return true on success, otherwise false.
*
* upto=false:
* pretty-print @p target using multiple lines
**/
static bool print_upto(ppstate * pps, ppconcat<Args...> target) {
std::uint32_t saved = pps->pos();
static bool print_pretty(const ppindentinfo & ppii, ppconcat<Args...> target) {
if (ppii.upto()) {
std::uint32_t saved = ppii.pps()->pos();
if (!pps->has_margin())
if (!ppii.pps()->has_margin())
return false;
if (std::apply(
[pps](auto &&... args) {
return detail::ppconcat_printupto_aux(pps, std::forward<decltype(args)>(args)...);
[ppii](auto &&... args) {
return detail::ppconcat_printupto_aux(ppii.pps(), std::forward<decltype(args)>(args)...);
},
std::forward<std::tuple<Args...>>(target.contents_)
) == false)
@ -116,22 +121,18 @@ namespace xo {
return false;
}
return pps->scan_no_newline(saved);
}
/** pretty-print @p target using multiple lines
**/
static void print_pretty(ppstate * pps, ppconcat<Args...> target) {
std::uint32_t ci0 = pps->lpos();
std::uint32_t ci1 = ci0 + pps->indent_width();
return ppii.pps()->scan_no_newline(saved);
} else {
std::apply(
[pps, ci1](auto &&... args) {
detail::ppconcat_print_pretty_aux(pps, ci1,
[ppii](auto &&... args) {
detail::ppconcat_print_pretty_aux(ppii.pps(), ppii.ci1(),
std::forward<decltype(args)>(args)...);
},
std::forward<std::tuple<Args...>>(target.contents_)
);
return false;
}
}
};
} /*namespace print*/

View file

@ -8,6 +8,7 @@
#include "xo/indentlog/print/ppconfig.hpp"
#include "xo/indentlog/log_streambuf.hpp"
#include "ppdetail_atomic.hpp"
#include "tag.hpp"
#include "pad.hpp"
#include <sstream>
#include <vector>
@ -16,12 +17,10 @@
namespace xo {
namespace print {
/** @class ppstate
* @brief hold pretty-printer state
*
* Use:
*
* ppconfig ppc;
* ppstate pps(&cout, 0, &ppc);
*
@ -31,14 +30,19 @@ namespace xo {
struct ppstate {
using streambuf_type = log_streambuf<char, std::char_traits<char>>;
explicit ppstate(std::uint32_t ci, const ppconfig * config, std::ostream * scratch_ss, streambuf_type * scratch_sbuf)
explicit ppstate(std::uint32_t ci, const ppconfig * config,
std::ostream * scratch_ss, streambuf_type * scratch_sbuf)
: scratch_sbuf_{scratch_sbuf}, scratch_ss_{scratch_ss},
current_indent_{ci}, config_{config}
{}
uint32_t indent_width() const { return config_->indent_width_; }
ppindentinfo indent_info(bool upto) { return ppindentinfo(this, lpos(), indent_width(), upto); }
std::uint32_t pos() const { return scratch_sbuf_->pos(); }
/** current position relative to start of line (last \n or \r),
* excluding color escape sequences
**/
std::uint32_t lpos() const { return scratch_sbuf_->lpos(); }
/** space available from current position until @c ppconfig.right_margin_
@ -60,8 +64,8 @@ namespace xo {
return avail_margin() >= budget;
}
/** true if no newlines in range [@p lo, pos),
* where pos is current position
/** true if no newlines in range [s, pos),
* where s is @p start and pos is current position
**/
bool scan_no_newline(std::uint32_t start) const {
char const * p = scratch_sbuf_->lo() + start;
@ -76,10 +80,13 @@ namespace xo {
}
void indent(std::uint32_t tab) {
assert(tab < config_->assert_indent_threshold);
(*scratch_ss_) << spaces(tab);
}
/** write (to scratch stream) newline followed by @p tab spaces **/
void newline_indent(std::uint32_t tab) {
(*scratch_ss_) << "\n";
this->indent(tab);
}
@ -94,12 +101,50 @@ namespace xo {
virtual void commit() {}
// pretty-printing helpers
/** pretty-print empty struct **/
template <typename StructName, typename... Members>
std::uint32_t pretty_struct(const ppindentinfo & ppii, StructName && structname, Members&&...);
/** auxiliary function supporting @ref pretty_stuct .
* pretty-print a single member name on behalf of a struct/class.
* @return true iff printed content fits on remainder of line before right margin
**/
template <typename Member, typename... Rest>
std::uint32_t print_upto_struct_members(const ppindentinfo & ppii,
Member && member,
Rest&&... rest);
/** base-case overload **/
std::uint32_t print_upto_struct_members(const ppindentinfo &) { return true; }
/** pretty-print newline-and-indent separated member values.
* For struct members, use refrtag(name,value)
**/
template <typename Member, typename... Rest>
void pretty_struct_members(const ppindentinfo & ppii,
Member && member,
Rest&&... rest);
/** base-case overload **/
void pretty_struct_members(const ppindentinfo &) {}
template <typename T>
bool print_upto(T && x);
template <typename Name, typename Value>
bool print_upto_tag(Name && name, Value && value);
template <typename T>
ppstate& pretty(T && x);
/** write (to internal scratch stream), in order:
* newline, indent to @p ci, tag @p name, space, @p value
**/
template <typename Name, typename Value>
ppstate& newline_pretty_tag(std::uint32_t ci, Name && name, Value && value);
/** like pretty(x), but follow with trailing \n **/
template <typename T>
ppstate& prettyn(T && x);
@ -165,6 +210,7 @@ namespace xo {
void check_commit() {
if (pps_) {
/* nuke state to prevent duplicate commit */
ppstate * pps = pps_;
pps_ = nullptr;
if (pps->decr_nesting_level() == 0)
@ -175,42 +221,59 @@ namespace xo {
ppstate * pps_ = nullptr;
};
template <typename T>
bool
ppdetail_atomic<T>::print_upto(ppstate * pps, const T & x)
template <typename StructName, typename... Members>
std::uint32_t
ppstate::pretty_struct(const ppindentinfo & ppii, StructName && structname, Members&&... members)
{
/* position before we write */
if (!pps->has_margin())
if (ppii.upto()) {
return (this->print_upto("<")
&& this->print_upto(structname)
&& this->print_upto_struct_members(ppii, members...)
&& this->print_upto(">"));
} else {
this->write("<");
this->write(structname);
this->pretty_struct_members(ppii, members...);
this->write(">");
return false;
std::uint32_t start = pps->pos();
/* if x is non-atomic may optimize by checking budget more often */
pps->write(x);
if (!pps->has_margin())
return false;
/* scan characters [lo, hi) in line buffer.
* Newline -> caller should use print_pretty()
*/
return (pps->scan_no_newline(start));
}
}
template <typename T>
void
ppdetail_atomic<T>::print_pretty(ppstate * pps, const T & x)
template <typename Member, typename... Rest>
std::uint32_t
ppstate::print_upto_struct_members(const ppindentinfo & ppii,
Member && member,
Rest&&... rest)
{
/* In default implementation we don't know where to introduce newlines.
* Still need to calculate lpos though
*/
pps->write(x);
if (this->print_upto(" ") && this->print_upto(member))
return this->print_upto_struct_members(ppii, rest...);
return false;
}
template <typename Member, typename... Rest>
void
ppstate::pretty_struct_members(const ppindentinfo & ppii,
Member && member,
Rest&&... rest)
{
newline_indent(ppii.ci1());
this->pretty(member);
this->pretty_struct_members(ppii, rest...);
}
template <typename T>
bool
ppstate::print_upto(T && value) {
return ppdetail<std::decay_t<T>>::print_upto(this, value);
std::uint32_t saved = pos();
if (!has_margin())
return false;
if (!ppdetail<std::decay_t<T>>::print_pretty(this->indent_info(true /*upto*/), value))
return false;
return scan_no_newline(saved);
}
template <typename T>
@ -220,12 +283,13 @@ namespace xo {
* Decision depends on ancestor context
*/
std::uint32_t saved = pos();
auto saved = scratch_sbuf_->checkpoint();
ppcommitter ppc(this);
/* print_upto() modifies @ref scratch_sbuf_ (and @ref scratch_ss_) */
bool fits = ppdetail<std::decay_t<T>>::print_upto(this, static_cast<const T &>(value));
/* print_pretty() modifies @ref scratch_sbuf_ (and @ref scratch_ss_) */
bool fits = ppdetail<std::decay_t<T>>::print_pretty(this->indent_info(true /*upto*/),
static_cast<const T &>(value));
if (fits) {
/* fits on 1 line -> pretty-printing maybe not required */
@ -235,7 +299,7 @@ namespace xo {
/* here: didn't fit -> split over multiple lines */
this->scratch_sbuf_->rewind_to(saved);
ppdetail<std::decay_t<T>>::print_pretty(this, value);
ppdetail<std::decay_t<T>>::print_pretty(this->indent_info(false), value);
ppc.check_commit();
return *this;
@ -248,12 +312,12 @@ namespace xo {
* Decision depends on ancestor context
*/
std::uint32_t saved = pos();
auto saved = scratch_sbuf_->checkpoint();
ppcommitter ppc(this);
/* print_upto() modifies @ref scratch_sbuf_ (and @ref scratch_ss_) */
bool fits = ppdetail<std::decay_t<T>>::print_upto(this, value);
/* print_pretty() modifies @ref scratch_sbuf_ (and @ref scratch_ss_) */
bool fits = ppdetail<std::decay_t<T>>::print_pretty(this->indent_info(true), value);
if (fits) {
this->newline_indent(0);
@ -264,12 +328,121 @@ namespace xo {
/* here: didn't fit -> split over multiple lines */
this->scratch_sbuf_->rewind_to(saved);
ppdetail<std::remove_reference_t<T>>::print_pretty(this, value);
ppdetail<std::remove_reference_t<T>>::print_pretty(this->indent_info(false), value);
this->newline_indent(0);
ppc.check_commit();
return *this;
}
template <typename T>
bool
ppdetail_atomic<T>::print_pretty(const ppindentinfo & ppii, const T & x)
{
if (ppii.upto()) {
std::uint32_t start = ppii.pps()->pos();
/* if x is non-atomic may optimize by checking budget more often */
ppii.pps()->write(x);
if (!ppii.pps()->has_margin())
return false;
/* scan characters [lo, hi) in line buffer.
* Newline -> caller should use print_pretty()
*/
return (ppii.pps()->scan_no_newline(start));
} else {
/* In default implementation we don't know where to introduce newlines.
* Still need to calculate lpos though
*/
ppii.pps()->write(x);
return false;
}
assert(false);
return true;
}
namespace detail {
template <typename Tag>
struct ppdetail_tag {
static bool print_pretty(const ppindentinfo & ppii,
const Tag & tag)
{
if (ppii.upto()) {
if (tag.prefix_space())
ppii.pps()->write(" ");
/* must color here, because we may keep the output if it fits! */
if (!ppii.pps()->print_upto(with_color(color_spec_type::yellow(), // tag_config::tag_color,
concat((char const *)":", tag.name()))))
return false;
ppii.pps()->write(" ");
if (!ppii.pps()->print_upto(tag.value()))
return false;
return true;
} else {
/* pretty-print like
* :somename
* pretty(value)
*/
if (tag.prefix_space())
ppii.pps()->write(" ");
ppii.pps()->write(with_color(color_spec_type::yellow(), //tag_config::tag_color,
concat((char const *)":", tag.name())));
ppii.pps()->newline_indent(ppii.ci1());
ppii.pps()->pretty(tag.value());
return false;
}
}
};
}
template <bool PrefixSpace, tagstyle TagStyle, typename Name, typename Value>
struct ppdetail<tag_impl<PrefixSpace, TagStyle, Name, Value>> {
static bool print_pretty(const ppindentinfo & ppii,
const tag_impl<PrefixSpace, TagStyle, Name, Value> & tag)
{
using tag_type = tag_impl<PrefixSpace, TagStyle, Name, Value>;
return detail::ppdetail_tag<tag_type>::print_pretty(ppii, tag);
}
};
template <bool PrefixSpace, tagstyle TagStyle, typename Name, typename Value>
struct ppdetail<ref_tag_impl<PrefixSpace, TagStyle, Name, Value>> {
static bool print_pretty(const ppindentinfo & ppii,
const ref_tag_impl<PrefixSpace, TagStyle, Name, Value> & tag)
{
using tag_type = ref_tag_impl<PrefixSpace, TagStyle, Name, Value>;
return detail::ppdetail_tag<tag_type>::print_pretty(ppii, tag);
}
};
template <typename Name, typename Value>
bool
ppstate::print_upto_tag(Name && name, Value && value)
{
return this->print_upto(xrtag(name, value));
}
template <typename Name, typename Value>
ppstate &
ppstate::newline_pretty_tag(std::uint32_t ci, Name && name, Value && value)
{
newline_indent(ci);
this->pretty(rtag(name, value));
return *this;
}
} /*namespace print*/
} /*namespace xo*/

View file

@ -1,14 +0,0 @@
/* @file pretty_concat.hpp
*
* author: Roland Conybeare, Jul 2025
*/
#pragma once
#include "concat.hpp"
#include "pretty.hpp"
namespace xo {
}
/* end pretty_concat.hpp */

View file

@ -1,56 +0,0 @@
/* file pretty_tag.hpp
*
* author: Roland Conybeare, Jul 2025
*/
#pragma once
#include "pretty.hpp"
#include "tag.hpp"
namespace xo {
namespace print {
template <bool PrefixSpace, tagstyle TagStyle, typename Name, typename Value>
struct ppdetail<tag_impl<PrefixSpace, TagStyle, Name, Value>> {
static bool print_upto(ppstate * pps, const tag_impl<PrefixSpace, TagStyle, Name, Value> & tag) {
std::uint32_t saved = pps->pos();
if (!pps->has_margin())
return false;
if (PrefixSpace)
pps->write(" ");
/* skil colorizing here, since doesn't consume visible space */
if (!pps->print_upto(concat((char const *)":", concat(tag.name(), (char const *)" "))))
return false;
if (!pps->print_upto(quot_impl(TagStyle == tagstyle::autoescape, tag.value())))
return false;
return pps->scan_no_newline(saved);
}
static void print_pretty(ppstate * pps, const tag_impl<PrefixSpace, TagStyle, Name, Value> & tag) {
/* pretty-print like
* :somename
* pretty(value)
*/
std::uint32_t ci0 = pps->lpos();
std::uint32_t ci1 = ci0 + pps->indent_width();
if (PrefixSpace)
pps->write(" ");
pps->write(with_color(tag_config::tag_color,
concat((char const *)":", tag.name())));
pps->newline_indent(ci1);
pps->pretty(tag.value());
pps->newline_indent(ci0);
}
};
} /*namespace print*/
} /*namespace xo*/
/* end pretty_tag.hpp */

View file

@ -11,56 +11,47 @@
namespace xo {
namespace print {
template <typename T>
struct ppdetail<std::vector<T>> {
static bool print_upto(ppstate * pps, const std::vector<T> & x) {
std::uint32_t saved = pps->pos();
if (!pps->has_margin())
return false;
pps->write("[");
template <typename Vector>
struct ppdetail_vector {
static bool print_pretty(const ppindentinfo & ppii, const Vector & x) {
if (ppii.upto()) {
ppii.pps()->write("[");
for (size_t i = 0, z = x.size(); i < z; ++i) {
if (i > 0)
pps->write(", ");
ppii.pps()->write(", ");
if (!pps->print_upto(x[i]))
if (!ppii.pps()->print_upto(x[i]))
return false;
if (!pps->has_margin())
if (!ppii.pps()->has_margin())
return false;
}
pps->write("]");
if (!pps->has_margin())
return false;
ppii.pps()->write("]");
return pps->scan_no_newline(saved);
}
return true;
} else {
ppii.pps()->write('[');
static void print_pretty(ppstate * pps, const std::vector<T> & x) {
std::uint32_t ci0 = pps->lpos();
pps->write('[');
std::uint32_t ci1 = ci0 + pps->indent_width();
for (size_t i = 0, z = x.size(); i < z; ++i) {
pps->newline_indent(ci1);
pps->pretty(x[i]);
if (i == 0)
ppii.pps()->indent(std::max(ppii.pps()->indent_width(), 1u) - 1);
else
ppii.pps()->newline_indent(ppii.ci1());
ppii.pps()->pretty(x[i]);
if (i+1 < z)
pps->write(',');
ppii.pps()->write(',');
}
pps->newline_indent(ci0);
pps->write(']');
ppii.pps()->write(" ]");
return false;
}
}
};
template <typename T>
struct ppdetail<const std::vector<T>> {
static bool print_upto(ppstate * pps, const std::vector<T> & x) {
return ppdetail<std::vector<T>>::print_upto(pps, x);
}
static void print_pretty(ppstate * pps, const std::vector<T> & x) {
ppdetail<std::vector<T>>::print_pretty(pps, x);
struct ppdetail<std::vector<T>> {
static bool print_pretty(const ppindentinfo & ppii, const std::vector<T> & x) {
return ppdetail_vector<std::vector<T>>::print_pretty(ppii, x);
}
};
}

View file

@ -103,13 +103,13 @@ namespace xo {
} /*print*/
private:
/* .unq_flag: if true, omit surrounding " chars
/** .unq_flag: if true, omit surrounding " chars
* whenever printed value satisfies both:
* - no escaped chars
* - no spaces
*/
**/
bool unq_flag_ = false;
/* .value: value to be printed */
/** .value: value to be printed **/
T value_;
}; /*quot_impl*/
@ -120,7 +120,7 @@ namespace xo {
return os;
} /*operator*/
/* writing out std::forward<T> behavior for completeness' sake:
/** writing out std::forward<T> behavior for completeness' sake:
*
* 1. call quoted(x) with rvalue std::string x, then:
* - T will be deduced to [std::string]
@ -134,7 +134,7 @@ namespace xo {
* 2b. call quoted(x) with std::string const & x, then:
* - T deduced to [std::string const &]
* - std::string const & passed to quot_impl ctor
*/
**/
template<typename T>
auto quot(T && x) {
return quot_impl(false /*unq_flag*/, std::forward<T>(x));

View file

@ -30,7 +30,7 @@ namespace xo {
raw,
};
/** K,V pair for printing.
/** key-value pair for printing.
*
* @tparam PrefixSpace if true print one space before :K
* @tparam TagStyle controls printing format
@ -63,6 +63,8 @@ namespace xo {
tag_impl(Name && n, Value && v)
: name_{std::forward<Name>(n)}, value_{std::forward<Value>(v)} {}
constexpr bool prefix_space() const { return PrefixSpace; }
Name const & name() const { return name_; }
Value const & value() const { return value_; }
@ -71,20 +73,52 @@ namespace xo {
Value value_;
};
/** key-value pair for printing.
* Like tag_impl<..> but uses reference for value.
* Use in context where value can't be a temporary rvalue.
**/
template <bool PrefixSpace, tagstyle TagStyle, typename Name, typename Value>
struct ref_tag_impl {
ref_tag_impl(Name const & n, Value const & v) : name_{n}, value_{v} {}
ref_tag_impl(Name && n, Value && v) : name_{std::forward<Name>(n)}, value_{std::forward<Value>(v)} {}
constexpr bool prefix_space() const { return PrefixSpace; }
Name const & name() const { return name_; }
Value const & value() const { return value_; }
private:
Name name_;
const Value& value_;
};
// ----- xtag -----
/** Write name,value pair @p n, @p v with format like
* :name value
* Precede with initial space
* Escape whitespace/special characters in @p v
**/
template<typename Name, typename Value>
auto //tag_impl<true, tagstyle::autoescape, Name, std::decay_t<Value>>
auto
xtag(Name && n, Value && v)
{
return tag_impl<true, tagstyle::autoescape, Name, std::decay_t<Value>>(n, v);
return tag_impl<true, tagstyle::autoescape, std::decay_t<Name>, std::decay_t<Value>>(n, v);
} /*xtag*/
template<typename Value>
auto //tag_impl<true, tagstyle::autoescape, char const *, std::decay_t<Value>>
xtag(char const * n, Value && v) {
return tag_impl<true, tagstyle::autoescape, char const *, std::decay_t<Value>>(n, v);
} /*xtag*/
// ----- xrtag ----
/** Write name,value pair @p n, @p v with format like
* :name value
* Precede with initial space.
* Do not escape whitespace/special characters in @p v.
**/
template<typename Name, typename Value>
auto
xrtag(Name && n, Value && v)
{
return tag_impl<true, tagstyle::raw, std::decay_t<Name>, std::decay_t<Value>>(n, v);
}
// ----- tag -----
@ -102,6 +136,28 @@ namespace xo {
return tag_impl<false, tagstyle::autoescape, char const *, Value>(n, v);
}
// ----- rtag -----
template<typename Name, typename Value>
auto
rtag(Name && n, Value && v)
{
return tag_impl<false, tagstyle::raw, std::decay_t<Name>, std::decay_t<Value>>(n, v);
}
// ----- refrtag -----
/** 'reference raw tag'.
* 1. @p v must survive until refrtag is used (i.e. until tag inserted into some stream)
* 2. don't escape whitespace when printing value (pretty-printing with parseable structure)
**/
template <typename Name, typename Value>
auto
refrtag(Name && n, Value && v)
{
return ref_tag_impl<false, tagstyle::raw, std::decay_t<Name>, std::decay_t<Value>>(n, v);
}
// ----- operator<< on tag_impl -----
template <bool PrefixSpace, tagstyle TagStyle, typename Name, typename Value>
@ -124,6 +180,29 @@ namespace xo {
return s;
} /*operator<<*/
// ----- operator<< on ref_tag_impl -----
template <bool PrefixSpace, tagstyle TagStyle, typename Name, typename Value>
inline std::ostream &
operator<<(std::ostream &s,
ref_tag_impl<PrefixSpace, TagStyle, Name, Value> const & tag)
{
using xo::print::unq;
if (PrefixSpace)
s << " ";
s << with_color(tag_config::tag_color, concat((char const *)":", tag.name()))
<< " ";
if (TagStyle == tagstyle::autoescape)
s << unq(tag.value());
else
s << tag.value();
return s;
} /*operator<<*/
} /*namespace xo*/
/* end tag.hpp */

View file

@ -7,8 +7,6 @@
#include "print/filename.hpp"
#include "print/ppstr.hpp"
#include "print/tostr.hpp"
#include "print/pretty_concat.hpp"
#include "print/pretty_tag.hpp"
#include <stdexcept>
#include <cstdint>

View file

@ -78,7 +78,16 @@ namespace xo {
return os;
}
}
#ifndef ppdetail_atomic
namespace print {
PPDETAIL_ATOMIC(xo::jit::runtime_binding_path);
PPDETAIL_ATOMIC(xo::jit::runtime_binding_detail);
}
#endif
namespace jit {
/**
* 1. pattern for a stack frame associated with a user-defined function (some Lambda lm)
*

View file

@ -3,6 +3,7 @@
#include "MachPipeline.hpp"
#include "activation_record.hpp"
#include "type2llvm.hpp"
#include "xo/expression/pretty_variable.hpp"
#include <string>
namespace xo {

View file

@ -22,6 +22,8 @@ namespace xo {
virtual void notify_source_primed(bp<ReactorSource> src) override;
virtual std::uint64_t run_one() override;
virtual void display(std::ostream & os) const override;
private:
PollingReactor() = default;
@ -42,7 +44,17 @@ namespace xo {
*/
std::vector<ReactorSourcePtr> source_v_;
}; /*PollingReactor*/
} /*namespace reactor*/
#ifndef ppdetail_atomic
namespace print {
using PollingReactorPointer = xo::reactor::PollingReactor*;
// placeholder, until we implement pretty-printing
PPDETAIL_ATOMIC(xo::reactor::PollingReactor);
PPDETAIL_ATOMIC(PollingReactorPointer);
}
#endif
} /*namespace xo*/
/* end PollingReactor.hpp */

View file

@ -61,6 +61,10 @@ namespace xo {
*/
void run() { this->run_n(-1); }
/** print self human-readably on stream @p os
**/
virtual void display(std::ostream & os) const = 0;
protected:
Reactor();
@ -68,6 +72,12 @@ namespace xo {
/* control logging verbosity */
log_level loglevel_;
}; /*Reactor*/
inline std::ostream &
operator<<(std::ostream & os, const Reactor & x) {
x.display(os);
return os;
}
} /*namespace reactor*/
} /*namespace xo*/

View file

@ -98,6 +98,15 @@ namespace xo {
return retval;
} /*run_one*/
void
PollingReactor::display(std::ostream & os) const {
os << "<PollingReactor"
<< xtag("next_ix", next_ix_)
<< xtag("source_v.size", source_v_.size())
<< ">";
}
} /*namespace reactor*/
} /*namespace xo*/

View file

@ -16,6 +16,8 @@ namespace xo {
public:
using LocalEnv = xo::ast::LocalEnv;
using Variable = xo::ast::Variable;
using ppstate = xo::print::ppstate;
using ppindentinfo = xo::print::ppindentinfo;
public:
envframestack() {}
@ -58,6 +60,7 @@ namespace xo {
}
void print (std::ostream & os) const;
bool pretty_print(const ppindentinfo & ppii) const;
private:
std::vector<rp<LocalEnv>> stack_;

View file

@ -76,7 +76,7 @@ namespace xo {
}
class parserstatemachine; /* see parserstatemachine.hpp */
class exprstatestack;
class exprstatestack; /* see exprstatestack.hpp */
class formal_arg;

View file

@ -15,6 +15,10 @@ namespace xo {
* @brief A stack of exprstate objects
**/
class exprstatestack {
public:
using ppstate = xo::print::ppstate;
using ppindentinfo = xo::print::ppindentinfo;
public:
exprstatestack() {}
@ -45,6 +49,7 @@ namespace xo {
}
void print (std::ostream & os) const;
bool pretty_print(const ppindentinfo & ppii) const;
private:
std::vector<std::unique_ptr<exprstate>> stack_;
@ -65,21 +70,6 @@ namespace xo {
return os;
}
} /*namespace scm*/
#ifndef ppdetail_atomic
namespace print {
template <>
struct ppdetail<xo::scm::exprstatestack *> {
static bool print_upto(ppstate * pps, const xo::scm::exprstatestack * x) {
return ppdetail_atomic<const xo::scm::exprstatestack *>::print_upto(pps, x);
}
static void print_pretty(ppstate * pps, const xo::scm::exprstatestack * x) {
ppdetail_atomic<const xo::scm::exprstatestack *>::print_pretty(pps, x);
}
};
}
#endif
} /*namespace xo*/

View file

@ -87,13 +87,4 @@ namespace xo {
return os;
}
} /*namespace scm*/
#ifndef ppdetail_atomic
namespace print {
PPDETAIL_ATOMIC(xo::scm::parserstatemachine);
}
#endif
} /*namespace xo*/
/* end parserstatemachine.hpp */

View file

@ -0,0 +1,20 @@
/* file pretty_envframestack.hpp
*
* author: Roland Conybeare, Jul 2025
*/
#pragma once
#include "envframestack.hpp"
#include "xo/indentlog/print/pretty.hpp"
namespace xo {
namespace print {
template <>
struct ppdetail<xo::scm::envframestack*> {
static inline bool print_pretty(const ppindentinfo & ppii, const xo::scm::envframestack * p) {
return p->pretty_print(ppii);
}
};
} /*namespace print*/
} /*namespace xo*/

View file

@ -0,0 +1,20 @@
/* file pretty_exprstatestack.hpp
*
* author: Roland Conybeare, Jul 2025
*/
#pragma once
#include "exprstatestack.hpp"
#include "xo/indentlog/print/pretty.hpp"
namespace xo {
namespace print {
template <>
struct ppdetail<xo::scm::exprstatestack*> {
static inline bool print_pretty(const ppindentinfo & ppii, const xo::scm::exprstatestack * p) {
return p->pretty_print(ppii);
}
};
} /*namespace print*/
} /*namespace xo*/

View file

@ -0,0 +1,18 @@
/* file pretty_parserstatemachine.hpp
*
* author: Roland Conybeare, Jul 2025
*/
#pragma once
#include "parserstatemachine.hpp"
#include "xo/indentlog/print/pretty.hpp"
namespace xo {
namespace print {
template<>
struct ppdetail<xo::scm::parserstatemachine> {
static bool print_pretty(const ppindentinfo & ppii, const xo::scm::parserstatemachine & x);
};
}
} /*namespace xo*/

View file

@ -1,4 +1,4 @@
# parser/CMakeLists.txt
# reader/CMakeLists.txt
set(SELF_LIB xo_reader)
set(SELF_SRCS
@ -19,7 +19,9 @@ set(SELF_SRCS
expect_type_xs.cpp
lambda_xs.cpp
let1_xs.cpp
envframestack.cpp)
envframestack.cpp
pretty_parserstatemachine.cpp
)
xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS})
xo_dependency(${SELF_LIB} xo_expression)

View file

@ -4,6 +4,8 @@
*/
#include "envframestack.hpp"
#include "pretty_envframestack.hpp"
#include "pretty_localenv.hpp"
namespace xo {
using xo::ast::LocalEnv;
@ -92,6 +94,45 @@ namespace xo {
os << ">" << std::endl;
}
bool
envframestack::pretty_print(const ppindentinfo & ppii) const
{
ppstate * pps = ppii.pps();
if (ppii.upto()) {
if (stack_.size() > 1)
return false;
if (!pps->print_upto("<envframestack"))
return false;
if (!pps->print_upto_tag("size", stack_.size()))
return false;
if ((stack_.size() > 0)
&& !pps->print_upto_tag("[0]", stack_[0]))
{
return false;
}
pps->write(">");
return true;
} else {
pps->write("<envframestack");
pps->newline_pretty_tag(ppii.ci1(), "size", stack_.size());
for (std::size_t i = 0, z = stack_.size(); i < z; ++i) {
std::string i_str = tostr("[", z-i-1, "]");
pps->newline_pretty_tag(ppii.ci1(), i_str, stack_[i]);
}
pps->write(">");
return false;
}
}
} /*namespace scm*/
} /*namespace xo*/

View file

@ -3,6 +3,7 @@
#include "exprstate.hpp"
#include "exprstatestack.hpp"
#include "parserstatemachine.hpp"
#include "pretty_parserstatemachine.hpp"
#include "pretty_expression.hpp"
//#include "formal_arg.hpp"
#include "xo/expression/Variable.hpp"

View file

@ -4,6 +4,7 @@
*/
#include "exprstatestack.hpp"
#include <cstdint>
namespace xo {
namespace scm {
@ -65,6 +66,48 @@ namespace xo {
os << ">" << std::endl;
}
bool
exprstatestack::pretty_print(const ppindentinfo & ppii) const
{
ppstate * pps = ppii.pps();
if (ppii.upto()) {
if (stack_.size() > 1)
return false;
if (!pps->print_upto("<exprstatestack"))
return false;
if (!pps->print_upto_tag("size", stack_.size()))
return false;
/** always multiple lines if more than one element in stack **/
if ((stack_.size() > 0)
&& !pps->print_upto_tag("[0]", *stack_[0].get()))
{
return false;
}
pps->write(">");
return true;
} else {
pps->write("<exprstatestack");
pps->newline_pretty_tag(ppii.ci1(), "size", stack_.size());
for (std::size_t i = 0, z = stack_.size(); i < z; ++i) {
std::string i_str = tostr("[", z-i-1, "]");
pps->newline_pretty_tag(ppii.ci1(), i_str, *stack_[i].get());
}
pps->write(">");
return false;
}
}
} /*namespace scm*/
} /*namespace xo*/

View file

@ -5,6 +5,9 @@
#include "parserstatemachine.hpp"
#include "exprstatestack.hpp"
#include "pretty_parserstatemachine.hpp"
#include "pretty_envframestack.hpp"
#include "pretty_localenv.hpp"
#include "xo/expression/pretty_expression.hpp"
namespace xo {

View file

@ -0,0 +1,44 @@
/* file pretty_parserstatemachine.cpp
*
* author: Roland Conybeare, Jul 2025
*/
#include "pretty_parserstatemachine.hpp"
#include "pretty_exprstatestack.hpp"
#include "pretty_envframestack.hpp"
#include "exprstatestack.hpp"
namespace xo {
namespace print {
bool
ppdetail<xo::scm::parserstatemachine>::print_pretty(const ppindentinfo & ppii, const xo::scm::parserstatemachine & x)
{
ppstate * pps = ppii.pps();
if (ppii.upto()) {
if (!pps->print_upto("<psm"))
return false;
if (!pps->print_upto_tag("stack", x.p_stack_))
return false;
if (!pps->print_upto_tag("env_stack", x.p_env_stack_))
return false;
if (!pps->print_upto_tag("emit_expr", (void*)x.p_emit_expr_))
return false;
return pps->print_upto(">");
} else {
pps->write("<psm");
pps->newline_pretty_tag(ppii.ci1(), "stack", x.p_stack_);
pps->newline_pretty_tag(ppii.ci1(), "env_stack", x.p_env_stack_);
pps->newline_pretty_tag(ppii.ci1(), "emit_expr", (void*)x.p_emit_expr_);
pps->write(">");
return false;
}
}
} /*namespace print*/
} /*namespace xo*/

View file

@ -4,6 +4,7 @@
#include "exprstatestack.hpp"
#include "expect_expr_xs.hpp"
#include "parserstatemachine.hpp"
#include "pretty_exprstatestack.hpp"
#include "xo/expression/AssignExpr.hpp"
#include "xo/expression/Apply.hpp"
#include "xo/expression/pretty_expression.hpp"

View file

@ -10,66 +10,67 @@
namespace xo {
namespace print {
#ifndef ppdetail_atomic
template <>
struct ppdetail<xo::ref::Refcount *> {
static bool print_upto(ppstate * pps, const xo::ref::Refcount * x) {
return ppdetail_atomic<const xo::ref::Refcount *>::print_upto(pps, x);
}
static void print_pretty(ppstate * pps, const xo::ref::Refcount * x) {
ppdetail_atomic<const xo::ref::Refcount *>::print_pretty(pps, x);
static bool print_pretty(const ppindentinfo & ppii, const xo::ref::Refcount * x) {
return ppdetail_atomic<const xo::ref::Refcount *>::print_pretty(ppii, x);
}
};
#endif
template <typename T>
struct ppdetail<rp<T>> {
static bool print_upto(ppstate * pps, const rp<T> & x) {
static bool print_pretty(const ppindentinfo & ppii, const rp<T> & x) {
if (ppii.upto()) {
if (auto p = x.get()) {
return ppdetail<T>::print_upto(pps, *p);
return ppdetail<T>::print_pretty(ppii, *p);
} else {
/* note: degenerate case here, since never write newline for nullptr */
pps->write("<nullptr ");
pps->write(reflect::type_name<T>());
pps->write(">");
ppii.pps()->write("<nullptr ");
ppii.pps()->write(reflect::type_name<T>());
ppii.pps()->write(">");
return pps->has_margin();
return ppii.pps()->has_margin();
}
}
static void print_pretty(ppstate * pps, const rp<T> & x) {
if (auto p = x.get()) {
ppdetail<T>::print_pretty(pps, *p);
} else {
pps->write("<nullptr ");
pps->write(reflect::type_name<T>());
pps->write(">");
if (auto p = x.get()) {
ppdetail<T>::print_pretty(ppii, *p);
} else {
ppii.pps()->write("<nullptr ");
ppii.pps()->write(reflect::type_name<T>());
ppii.pps()->write(">");
}
return false;
}
}
};
template <typename T>
struct ppdetail<bp<T>> {
static bool print_upto(ppstate * pps, const bp<T> & x) {
static bool print_pretty(const ppindentinfo & ppii, const bp<T> & x) {
if (ppii.upto()) {
if (auto p = x.get()) {
return ppdetail<T>::print_upto(pps, *p);
return ppdetail<T>::print_pretty(ppii, *p);
} else {
/* note: degenerate case here, since never write newline for nullptr */
pps->write("<nullptr ");
pps->write(reflect::type_name<T>());
pps->write(">");
ppii.pps()->write("<nullptr ");
ppii.pps()->write(reflect::type_name<T>());
ppii.pps()->write(">");
return pps->has_margin();
return ppii.pps()->has_margin();
}
}
static void print_pretty(ppstate * pps, const bp<T> & x) {
if (auto p = x.get()) {
ppdetail<T>::print_pretty(pps, *p);
} else {
pps->write("<nullptr ");
pps->write(reflect::type_name<T>());
pps->write(">");
if (auto p = x.get()) {
ppdetail<T>::print_pretty(ppii, *p);
} else {
ppii.pps()->write("<nullptr ");
ppii.pps()->write(reflect::type_name<T>());
ppii.pps()->write(">");
}
return false;
}
}
};

View file

@ -218,6 +218,8 @@ namespace xo {
/* synonym for .advance_one_event() */
virtual std::uint64_t run_one() override;
virtual void display(std::ostream & os) const override;
private:
explicit Simulator(utc_nanos t0);

View file

@ -543,6 +543,16 @@ namespace xo {
return n;
} /*run_throttled_until*/
void
Simulator::display(std::ostream & os) const
{
os << "<Simulator"
<< xtag("sim_heap.size", sim_heap_.size())
<< xtag("n_event", n_event_)
<< xtag("src_v.size", src_v_.size())
<< ">";
} /*display*/
} /*namespace sim*/
} /*namespace xo*/

View file

@ -3,6 +3,7 @@
#include "xo/unit/basis_unit.hpp"
#include "xo/unit/bu_store.hpp"
#include "xo/indentlog/scope.hpp"
#include "xo/flatstring/flatstring_pretty.hpp"
//#include "xo/indentlog/print/tag.hpp"
#include <catch2/catch.hpp>