diff --git a/xo-expression/include/xo/expression/Apply.hpp b/xo-expression/include/xo/expression/Apply.hpp index 556c2560..0dd1137a 100644 --- a/xo-expression/include/xo/expression/Apply.hpp +++ b/xo-expression/include/xo/expression/Apply.hpp @@ -101,7 +101,7 @@ namespace xo { virtual void attach_envs(bp 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, diff --git a/xo-expression/include/xo/expression/AssignExpr.hpp b/xo-expression/include/xo/expression/AssignExpr.hpp index 248cc7c3..8cc2b7c7 100644 --- a/xo-expression/include/xo/expression/AssignExpr.hpp +++ b/xo-expression/include/xo/expression/AssignExpr.hpp @@ -40,6 +40,7 @@ namespace xo { virtual void attach_envs(bp 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 & lhs, diff --git a/xo-expression/include/xo/expression/Constant.hpp b/xo-expression/include/xo/expression/Constant.hpp index b2c9f71d..9da00a3a 100644 --- a/xo-expression/include/xo/expression/Constant.hpp +++ b/xo-expression/include/xo/expression/Constant.hpp @@ -6,6 +6,7 @@ #pragma once #include "ConstantInterface.hpp" +#include "pretty_expression.hpp" #include 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), diff --git a/xo-expression/include/xo/expression/ConvertExpr.hpp b/xo-expression/include/xo/expression/ConvertExpr.hpp index 88a821d4..d8969eb8 100644 --- a/xo-expression/include/xo/expression/ConvertExpr.hpp +++ b/xo-expression/include/xo/expression/ConvertExpr.hpp @@ -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, diff --git a/xo-expression/include/xo/expression/DefineExpr.hpp b/xo-expression/include/xo/expression/DefineExpr.hpp index c950c48b..1dc7fad7 100644 --- a/xo-expression/include/xo/expression/DefineExpr.hpp +++ b/xo-expression/include/xo/expression/DefineExpr.hpp @@ -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: /** diff --git a/xo-expression/include/xo/expression/Environment.hpp b/xo-expression/include/xo/expression/Environment.hpp index cd5ee5af..92103553 100644 --- a/xo-expression/include/xo/expression/Environment.hpp +++ b/xo-expression/include/xo/expression/Environment.hpp @@ -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 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 & diff --git a/xo-expression/include/xo/expression/GeneralizedExpression.hpp b/xo-expression/include/xo/expression/GeneralizedExpression.hpp index a0822a09..585b22fb 100644 --- a/xo-expression/include/xo/expression/GeneralizedExpression.hpp +++ b/xo-expression/include/xo/expression/GeneralizedExpression.hpp @@ -20,8 +20,9 @@ namespace xo { **/ class GeneralizedExpression : public ref::Refcount { public: - using TypeDescr = xo::reflect::TypeDescr; - using ppstate = xo::print::ppstate; + 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 */ diff --git a/xo-expression/include/xo/expression/GlobalEnv.hpp b/xo-expression/include/xo/expression/GlobalEnv.hpp index e05e88ff..798c8c76 100644 --- a/xo-expression/include/xo/expression/GlobalEnv.hpp +++ b/xo-expression/include/xo/expression/GlobalEnv.hpp @@ -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(); diff --git a/xo-expression/include/xo/expression/IfExpr.hpp b/xo-expression/include/xo/expression/IfExpr.hpp index 912fce90..946fda9d 100644 --- a/xo-expression/include/xo/expression/IfExpr.hpp +++ b/xo-expression/include/xo/expression/IfExpr.hpp @@ -6,7 +6,7 @@ #pragma once #include "Expression.hpp" -#include +//#include #include //#include @@ -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: /** diff --git a/xo-expression/include/xo/expression/Lambda.hpp b/xo-expression/include/xo/expression/Lambda.hpp index cfc94b58..380eeb9f 100644 --- a/xo-expression/include/xo/expression/Lambda.hpp +++ b/xo-expression/include/xo/expression/Lambda.hpp @@ -98,7 +98,7 @@ namespace xo { virtual void attach_envs(bp 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 diff --git a/xo-expression/include/xo/expression/LocalEnv.hpp b/xo-expression/include/xo/expression/LocalEnv.hpp index 9f883e20..8ae757ea 100644 --- a/xo-expression/include/xo/expression/LocalEnv.hpp +++ b/xo-expression/include/xo/expression/LocalEnv.hpp @@ -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> & argv, const rp & parent_env); @@ -103,12 +104,6 @@ namespace xo { }; } /*namespace ast*/ - -#ifndef ppdetail_atomic - namespace print { - PPDETAIL_ATOMIC(xo::ast::LocalEnv); - } -#endif } /*namespace xo*/ diff --git a/xo-expression/include/xo/expression/Primitive.hpp b/xo-expression/include/xo/expression/Primitive.hpp index 2305bfe4..27c265d9 100644 --- a/xo-expression/include/xo/expression/Primitive.hpp +++ b/xo-expression/include/xo/expression/Primitive.hpp @@ -6,9 +6,10 @@ #pragma once #include "PrimitiveInterface.hpp" +#include "pretty_expression.hpp" #include "llvmintrinsic.hpp" #include "xo/reflect/Reflect.hpp" -//#include +#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("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("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, diff --git a/xo-expression/include/xo/expression/Sequence.hpp b/xo-expression/include/xo/expression/Sequence.hpp index 243c4057..6faa0d12 100644 --- a/xo-expression/include/xo/expression/Sequence.hpp +++ b/xo-expression/include/xo/expression/Sequence.hpp @@ -6,7 +6,6 @@ #pragma once #include "Expression.hpp" -//#include 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 **/ diff --git a/xo-expression/include/xo/expression/Variable.hpp b/xo-expression/include/xo/expression/Variable.hpp index 9228660a..21f7d90b 100644 --- a/xo-expression/include/xo/expression/Variable.hpp +++ b/xo-expression/include/xo/expression/Variable.hpp @@ -65,6 +65,7 @@ namespace xo { virtual void attach_envs(bp /*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, diff --git a/xo-expression/include/xo/expression/pretty_expression.hpp b/xo-expression/include/xo/expression/pretty_expression.hpp index 1fe2bc77..44045a66 100644 --- a/xo-expression/include/xo/expression/pretty_expression.hpp +++ b/xo-expression/include/xo/expression/pretty_expression.hpp @@ -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 { - 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 { - 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); } }; } diff --git a/xo-expression/include/xo/expression/pretty_localenv.hpp b/xo-expression/include/xo/expression/pretty_localenv.hpp new file mode 100644 index 00000000..14caebf5 --- /dev/null +++ b/xo-expression/include/xo/expression/pretty_localenv.hpp @@ -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 { + static bool print_pretty(const ppindentinfo & ppii, const xo::ast::LocalEnv & x) { + return x.pretty_print(ppii); + } + }; + } +} diff --git a/xo-expression/include/xo/expression/pretty_variable.hpp b/xo-expression/include/xo/expression/pretty_variable.hpp new file mode 100644 index 00000000..07eb9910 --- /dev/null +++ b/xo-expression/include/xo/expression/pretty_variable.hpp @@ -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 { + static bool print_pretty(const ppindentinfo & ppii, const xo::ast::Expression & x) { + return x.pretty_print(ppii); + } + }; + } +} diff --git a/xo-expression/src/expression/Apply.cpp b/xo-expression/src/expression/Apply.cpp index 440601c7..7cb039b4 100644 --- a/xo-expression/src/expression/Apply.cpp +++ b/xo-expression/src/expression/Apply.cpp @@ -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 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("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("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*/ diff --git a/xo-expression/src/expression/AssignExpr.cpp b/xo-expression/src/expression/AssignExpr.cpp index c8b52711..2d07f4e7 100644 --- a/xo-expression/src/expression/AssignExpr.cpp +++ b/xo-expression/src/expression/AssignExpr.cpp @@ -4,7 +4,10 @@ */ #include "AssignExpr.hpp" +#include "pretty_expression.hpp" +#include "pretty_variable.hpp" #include "xo/indentlog/print/tag.hpp" +#include 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*/ diff --git a/xo-expression/src/expression/ConvertExpr.cpp b/xo-expression/src/expression/ConvertExpr.cpp index 2e741f1b..f09e1eb9 100644 --- a/xo-expression/src/expression/ConvertExpr.cpp +++ b/xo-expression/src/expression/ConvertExpr.cpp @@ -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 diff --git a/xo-expression/src/expression/DefineExpr.cpp b/xo-expression/src/expression/DefineExpr.cpp index cc7787be..3b2dbaf6 100644 --- a/xo-expression/src/expression/DefineExpr.cpp +++ b/xo-expression/src/expression/DefineExpr.cpp @@ -6,7 +6,6 @@ #include "DefineExpr.hpp" #include "Variable.hpp" #include "pretty_expression.hpp" -#include "xo/indentlog/print/pretty_tag.hpp" #include 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("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("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 ----- diff --git a/xo-expression/src/expression/GeneralizedExpression.cpp b/xo-expression/src/expression/GeneralizedExpression.cpp index 2cc79655..3734e291 100644 --- a/xo-expression/src/expression/GeneralizedExpression.cpp +++ b/xo-expression/src/expression/GeneralizedExpression.cpp @@ -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*/ diff --git a/xo-expression/src/expression/GlobalEnv.cpp b/xo-expression/src/expression/GlobalEnv.cpp index a9fd8f16..e9ec1acc 100644 --- a/xo-expression/src/expression/GlobalEnv.cpp +++ b/xo-expression/src/expression/GlobalEnv.cpp @@ -20,7 +20,33 @@ namespace xo { void GlobalEnv::print(std::ostream & os) const { - os << ""; + os << ""; + } + + 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("print_upto_tag("size", global_map_.size())) + return false; + pps->write(">"); + + return true; + } else { + pps->write("newline_pretty_tag(ppii.ci1(), "size", global_map_.size()); + pps->write(">"); + + return false; + } } } /*namespace ast*/ } /*namespace xo*/ diff --git a/xo-expression/src/expression/IfExpr.cpp b/xo-expression/src/expression/IfExpr.cpp index bd5d231f..f6377ce3 100644 --- a/xo-expression/src/expression/IfExpr.cpp +++ b/xo-expression/src/expression/IfExpr.cpp @@ -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*/ diff --git a/xo-expression/src/expression/Lambda.cpp b/xo-expression/src/expression/Lambda.cpp index 2f24a9d0..80e30e67 100644 --- a/xo-expression/src/expression/Lambda.cpp +++ b/xo-expression/src/expression/Lambda.cpp @@ -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 #include @@ -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("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("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 */ diff --git a/xo-expression/src/expression/LocalEnv.cpp b/xo-expression/src/expression/LocalEnv.cpp index 1b27e577..8e6ab0e7 100644 --- a/xo-expression/src/expression/LocalEnv.cpp +++ b/xo-expression/src/expression/LocalEnv.cpp @@ -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 @@ -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("print_upto_tag("this", (void*)this)) + return false; + if (!pps->print_upto_tag("argv", argv_)) + return false; + pps->write(">"); + + return true; + } else { + pps->write("newline_pretty_tag(ppii.ci1(), "this", (void*)this); + pps->newline_pretty_tag(ppii.ci1(), "argv", argv_); + pps->write(">"); + + return false; + } + } + } /*namespace ast*/ } /*namespace xo*/ diff --git a/xo-expression/src/expression/Sequence.cpp b/xo-expression/src/expression/Sequence.cpp index a9812867..3153c06e 100644 --- a/xo-expression/src/expression/Sequence.cpp +++ b/xo-expression/src/expression/Sequence.cpp @@ -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("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("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; } diff --git a/xo-expression/src/expression/Variable.cpp b/xo-expression/src/expression/Variable.cpp index af862cfa..663be6c6 100644 --- a/xo-expression/src/expression/Variable.cpp +++ b/xo-expression/src/expression/Variable.cpp @@ -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("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("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*/ diff --git a/xo-flatstring/include/xo/flatstring/flatstring.hpp b/xo-flatstring/include/xo/flatstring/flatstring.hpp index a332950d..947d70da 100644 --- a/xo-flatstring/include/xo/flatstring/flatstring.hpp +++ b/xo-flatstring/include/xo/flatstring/flatstring.hpp @@ -636,6 +636,7 @@ namespace xo { return ((s1 <=> s2) == std::strong_ordering::equal); } ///@} + } /*namespace xo*/ /** end flatstring.hpp **/ diff --git a/xo-flatstring/include/xo/flatstring/flatstring_pretty.hpp b/xo-flatstring/include/xo/flatstring/flatstring_pretty.hpp new file mode 100644 index 00000000..2474a3a4 --- /dev/null +++ b/xo-flatstring/include/xo/flatstring/flatstring_pretty.hpp @@ -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 + struct ppdetail> { + static bool print_pretty(const ppindentinfo & ppii, + const flatstring & x) { + return ppdetail_atomic>::print_pretty(ppii, x); + }; + }; + } +#endif +} + +/** end flatstring_pretty.hpp **/ diff --git a/xo-indentlog/docs/glossary.rst b/xo-indentlog/docs/glossary.rst index 82bd0d2d..0631a3fd 100644 --- a/xo-indentlog/docs/glossary.rst +++ b/xo-indentlog/docs/glossary.rst @@ -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" diff --git a/xo-indentlog/include/xo/indentlog/log_streambuf.hpp b/xo-indentlog/include/xo/indentlog/log_streambuf.hpp index 855fc05b..b6e9305d 100644 --- a/xo-indentlog/include/xo/indentlog/log_streambuf.hpp +++ b/xo-indentlog/include/xo/indentlog/log_streambuf.hpp @@ -16,6 +16,16 @@ namespace xo { **/ template > 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,32 +174,32 @@ namespace xo { } /*xsputn*/ virtual int_type - overflow(int_type new_ch) override - { - char * old_pptr = this->pptr(); - std::streamsize old_n = old_pptr - this->pbase(); + overflow(int_type new_ch) override { + char * old_pptr = this->pptr(); + std::streamsize old_n = old_pptr - this->pbase(); - assert(old_n <= static_cast(this->buf_v_.size())); + assert(old_n <= static_cast(this->buf_v_.size())); - if (debug_flag_) { - std::cout << "overflow: new_ch=" << quoted_char(new_ch) << std::endl; - } + if (debug_flag_) { + std::cout << "overflow: new_ch=" << quoted_char(new_ch) << std::endl; + } - this->expand_to(2 * buf_v_.size()); + this->expand_to(2 * buf_v_.size()); - this->buf_v_[old_n] = new_ch; - this->pbump(1); + this->buf_v_[old_n] = new_ch; + this->pbump(1); - if ((new_ch == static_cast('\n')) || (new_ch == static_cast('\r'))) - this->solpos_ = this->pos(); + if ((new_ch == static_cast('\n')) || (new_ch == static_cast('\r'))) { + this->solpos_ = this->pos(); + } - if (new_ch == Traits::eof()) { - /* reminder: returning eof sets badbit on ostream */ - return Traits::not_eof(new_ch); - } else { - return new_ch; - } - } /*overflow*/ + if (new_ch == Traits::eof()) { + /* reminder: returning eof sets badbit on ostream */ + return Traits::not_eof(new_ch); + } else { + return new_ch; + } + } /*overflow*/ /* off. offset, relative to starting point dir. * dir. @@ -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 buf_v_; /** true to debug log_streambuf itself **/ diff --git a/xo-indentlog/include/xo/indentlog/print/color.hpp b/xo-indentlog/include/xo/indentlog/print/color.hpp index bcd3e634..ef91f49f 100644 --- a/xo-indentlog/include/xo/indentlog/print/color.hpp +++ b/xo-indentlog/include/xo/indentlog/print/color.hpp @@ -2,8 +2,8 @@ #pragma once +#include "ppdetail_atomic.hpp" #include -//#include // for std::move #include namespace xo { @@ -17,11 +17,11 @@ namespace xo { inline std::ostream & operator<< (std::ostream & os, color_encoding x) { switch(x) { - case color_encoding::none: os << "none"; break; - case color_encoding::ansi: os << "ansi"; break; + case color_encoding::none: os << "none"; break; + case color_encoding::ansi: os << "ansi"; break; case color_encoding::xterm: os << "xterm"; break; - case color_encoding::rgb: os << "rgb"; break; - default: os << "???"; break; + case color_encoding::rgb: os << "rgb"; break; + default: os << "???"; break; } return os; } /*operator<<*/ @@ -125,11 +125,11 @@ namespace xo { } /*operator<<*/ enum class coloring_control_flags : std::uint8_t { - none = 0x0, - color_on = 0x01, - contents = 0x02, + none = 0x0, + color_on = 0x01, + contents = 0x02, color_off = 0x04, - all = 0x07 + all = 0x07 }; inline std::uint8_t operator& (coloring_control_flags x, coloring_control_flags y) { @@ -177,25 +177,42 @@ namespace xo { template color_impl with_color(color_spec_type const & spec, Contents && contents) { return color_impl(coloring_control_flags::all, spec, std::forward(contents)); - } /*with_color*/ + } inline color_impl color_on(color_spec_type const & spec) { return color_impl(coloring_control_flags::color_on, spec, 0); - } /*color_on*/ + } inline color_impl color_off(color_spec_type const & spec) { /* any spec other than color_spec_type::none() works here */ return color_impl(coloring_control_flags::color_off, spec, 0); - } /*color_off*/ + } template inline std::ostream & operator<<(std::ostream & os, color_impl 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 + struct ppdetail> { + using target_type = color_impl; + + static bool print_pretty(const ppindentinfo & ppii, const target_type & x) { + return ppdetail_atomic::print_pretty(ppii, x); + } + }; + } +#endif } /*namespace xo*/ diff --git a/xo-indentlog/include/xo/indentlog/print/concat.hpp b/xo-indentlog/include/xo/indentlog/print/concat.hpp index 3c166c41..e9d4905d 100644 --- a/xo-indentlog/include/xo/indentlog/print/concat.hpp +++ b/xo-indentlog/include/xo/indentlog/print/concat.hpp @@ -48,11 +48,8 @@ namespace xo { struct ppdetail> { using target_type = concat_impl; - static bool print_upto(ppstate * pps, const target_type & x) { - return ppdetail_atomic::print_upto(pps, x); - } - static void print_pretty(ppstate * pps, const target_type & x) { - ppdetail_atomic::print_pretty(pps, x); + static bool print_pretty(const ppindentinfo & ppii, const target_type & x) { + return ppdetail_atomic::print_pretty(ppii, x); } }; } diff --git a/xo-indentlog/include/xo/indentlog/print/ppconfig.hpp b/xo-indentlog/include/xo/indentlog/print/ppconfig.hpp index 1cc60597..67d1831a 100644 --- a/xo-indentlog/include/xo/indentlog/print/ppconfig.hpp +++ b/xo-indentlog/include/xo/indentlog/print/ppconfig.hpp @@ -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*/ diff --git a/xo-indentlog/include/xo/indentlog/print/ppdetail_atomic.hpp b/xo-indentlog/include/xo/indentlog/print/ppdetail_atomic.hpp index 05614eed..89824028 100644 --- a/xo-indentlog/include/xo/indentlog/print/ppdetail_atomic.hpp +++ b/xo-indentlog/include/xo/indentlog/print/ppdetail_atomic.hpp @@ -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,88 +53,76 @@ namespace xo { template struct ppdetail; - template - struct ppdetail_atomic; - template 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 struct ppdetail { using target_type = const char[N]; - - static bool print_upto(ppstate * pps, const target_type & x) { - return ppdetail_atomic::print_upto(pps, x); - } - static void print_pretty(ppstate * pps, const target_type & x) { - ppdetail_atomic::print_pretty(pps, x); + static bool print_pretty(const ppindentinfo & ppii, const target_type & x) { + return ppdetail_atomic::print_pretty(ppii, x); } }; template <> struct ppdetail { - static bool print_upto(ppstate * pps, const char * x) { - return ppdetail_atomic::print_upto(pps, x); - } - static void print_pretty(ppstate * pps, const char * x) { - ppdetail_atomic::print_pretty(pps, x); + static bool print_pretty(const ppindentinfo & ppii, const char * x) { + return ppdetail_atomic::print_pretty(ppii, x); } }; -#define PPDETAIL_ATOMIC_BODY(target_type) \ - struct ppdetail { \ - static bool print_upto(ppstate * pps, const target_type & x) { \ - return ppdetail_atomic::print_upto(pps, x); \ - } \ - \ - static void print_pretty(ppstate * pps, const target_type & x) { \ - ppdetail_atomic::print_pretty(pps, x); \ - } \ +#define PPDETAIL_ATOMIC_BODY(target_type) \ + struct ppdetail { \ + static bool print_pretty(const ppindentinfo & ppii, \ + const target_type & x) { \ + return ppdetail_atomic::print_pretty(ppii, x); \ + } \ } -#define PPDETAIL_ATOMIC_BODY_CONST(target_type) \ - struct ppdetail { \ - static bool print_upto(ppstate * pps, const target_type & x) { \ - return ppdetail_atomic::print_upto(pps, x); \ - } \ - \ - static void print_pretty(ppstate * pps, const target_type & x) { \ - ppdetail_atomic::print_pretty(pps, x); \ - } \ +#define PPDETAIL_ATOMIC_BODY_CONST(target_type) \ + struct ppdetail { \ + static bool print_pretty(const ppindentinfo & ppii, \ + const target_type & x) { \ + return ppdetail_atomic::print_pretty(ppii, x); \ + } \ } -#define PPDETAIL_ATOMIC(target_type) \ - template<> \ +#define PPDETAIL_ATOMIC(target_type) \ + template<> \ PPDETAIL_ATOMIC_BODY(target_type) -#define PPDETAIL_ATOMIC_CONST(target_type) \ - template<> \ +#define PPDETAIL_ATOMIC_CONST(target_type) \ + template<> \ PPDETAIL_ATOMIC_BODY_CONST(target_type) 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*/ diff --git a/xo-indentlog/include/xo/indentlog/print/ppstr.hpp b/xo-indentlog/include/xo/indentlog/print/ppstr.hpp index 358c14b6..f5f2ad5b 100644 --- a/xo-indentlog/include/xo/indentlog/print/ppstr.hpp +++ b/xo-indentlog/include/xo/indentlog/print/ppstr.hpp @@ -94,44 +94,45 @@ namespace xo { /** implement pretty-printing for template @c ppconcat r**/ template struct ppdetail> { - /** 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 target) { - std::uint32_t saved = pps->pos(); + static bool print_pretty(const ppindentinfo & ppii, ppconcat target) { + if (ppii.upto()) { + std::uint32_t saved = ppii.pps()->pos(); - if (!pps->has_margin()) - return false; + if (!ppii.pps()->has_margin()) + return false; - if (std::apply( - [pps](auto &&... args) { - return detail::ppconcat_printupto_aux(pps, std::forward(args)...); + if (std::apply( + [ppii](auto &&... args) { + return detail::ppconcat_printupto_aux(ppii.pps(), std::forward(args)...); + }, + std::forward>(target.contents_) + ) == false) + { + return false; + } + + return ppii.pps()->scan_no_newline(saved); + } else { + std::apply( + [ppii](auto &&... args) { + detail::ppconcat_print_pretty_aux(ppii.pps(), ppii.ci1(), + std::forward(args)...); }, std::forward>(target.contents_) - ) == false) - { + ); + return false; } - - return pps->scan_no_newline(saved); - } - - /** pretty-print @p target using multiple lines - **/ - static void print_pretty(ppstate * pps, ppconcat target) { - std::uint32_t ci0 = pps->lpos(); - std::uint32_t ci1 = ci0 + pps->indent_width(); - - std::apply( - [pps, ci1](auto &&... args) { - detail::ppconcat_print_pretty_aux(pps, ci1, - std::forward(args)...); - }, - std::forward>(target.contents_) - ); } }; } /*namespace print*/ diff --git a/xo-indentlog/include/xo/indentlog/print/pretty.hpp b/xo-indentlog/include/xo/indentlog/print/pretty.hpp index 369713b0..c6ed3a40 100644 --- a/xo-indentlog/include/xo/indentlog/print/pretty.hpp +++ b/xo-indentlog/include/xo/indentlog/print/pretty.hpp @@ -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 #include @@ -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>; - 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 + 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 + 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 + void pretty_struct_members(const ppindentinfo & ppii, + Member && member, + Rest&&... rest); + + /** base-case overload **/ + void pretty_struct_members(const ppindentinfo &) {} + template bool print_upto(T && x); + template + bool print_upto_tag(Name && name, Value && value); + template ppstate& pretty(T && x); + /** write (to internal scratch stream), in order: + * newline, indent to @p ci, tag @p name, space, @p value + **/ + template + ppstate& newline_pretty_tag(std::uint32_t ci, Name && name, Value && value); + /** like pretty(x), but follow with trailing \n **/ template 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 - bool - ppdetail_atomic::print_upto(ppstate * pps, const T & x) + template + 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 - void - ppdetail_atomic::print_pretty(ppstate * pps, const T & x) + template + 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 + 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 bool ppstate::print_upto(T && value) { - return ppdetail>::print_upto(this, value); + std::uint32_t saved = pos(); + + if (!has_margin()) + return false; + + if (!ppdetail>::print_pretty(this->indent_info(true /*upto*/), value)) + return false; + + return scan_no_newline(saved); } template @@ -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>::print_upto(this, static_cast(value)); + /* print_pretty() modifies @ref scratch_sbuf_ (and @ref scratch_ss_) */ + bool fits = ppdetail>::print_pretty(this->indent_info(true /*upto*/), + static_cast(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>::print_pretty(this, value); + ppdetail>::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>::print_upto(this, value); + /* print_pretty() modifies @ref scratch_sbuf_ (and @ref scratch_ss_) */ + bool fits = ppdetail>::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>::print_pretty(this, value); + ppdetail>::print_pretty(this->indent_info(false), value); this->newline_indent(0); ppc.check_commit(); return *this; } + template + bool + ppdetail_atomic::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 + 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 + struct ppdetail> { + static bool print_pretty(const ppindentinfo & ppii, + const tag_impl & tag) + { + using tag_type = tag_impl; + + return detail::ppdetail_tag::print_pretty(ppii, tag); + } + }; + + template + struct ppdetail> { + static bool print_pretty(const ppindentinfo & ppii, + const ref_tag_impl & tag) + { + using tag_type = ref_tag_impl; + + return detail::ppdetail_tag::print_pretty(ppii, tag); + } + }; + + template + bool + ppstate::print_upto_tag(Name && name, Value && value) + { + return this->print_upto(xrtag(name, value)); + } + + template + 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*/ diff --git a/xo-indentlog/include/xo/indentlog/print/pretty_concat.hpp b/xo-indentlog/include/xo/indentlog/print/pretty_concat.hpp deleted file mode 100644 index 8b484936..00000000 --- a/xo-indentlog/include/xo/indentlog/print/pretty_concat.hpp +++ /dev/null @@ -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 */ diff --git a/xo-indentlog/include/xo/indentlog/print/pretty_tag.hpp b/xo-indentlog/include/xo/indentlog/print/pretty_tag.hpp deleted file mode 100644 index 7402136b..00000000 --- a/xo-indentlog/include/xo/indentlog/print/pretty_tag.hpp +++ /dev/null @@ -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 - struct ppdetail> { - static bool print_upto(ppstate * pps, const tag_impl & 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 & 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 */ diff --git a/xo-indentlog/include/xo/indentlog/print/pretty_vector.hpp b/xo-indentlog/include/xo/indentlog/print/pretty_vector.hpp index efccb800..6a05fe14 100644 --- a/xo-indentlog/include/xo/indentlog/print/pretty_vector.hpp +++ b/xo-indentlog/include/xo/indentlog/print/pretty_vector.hpp @@ -11,56 +11,47 @@ namespace xo { namespace print { - template - struct ppdetail> { - static bool print_upto(ppstate * pps, const std::vector & x) { - std::uint32_t saved = pps->pos(); - if (!pps->has_margin()) + template + 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) + ppii.pps()->write(", "); + + if (!ppii.pps()->print_upto(x[i])) + return false; + if (!ppii.pps()->has_margin()) + return false; + } + ppii.pps()->write("]"); + + return true; + } else { + ppii.pps()->write('['); + + for (size_t i = 0, z = x.size(); i < z; ++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) + ppii.pps()->write(','); + } + + ppii.pps()->write(" ]"); return false; - - pps->write("["); - for (size_t i = 0, z = x.size(); i < z; ++i) { - if (i > 0) - pps->write(", "); - - if (!pps->print_upto(x[i])) - return false; - if (!pps->has_margin()) - return false; } - pps->write("]"); - if (!pps->has_margin()) - return false; - - return pps->scan_no_newline(saved); - } - - static void print_pretty(ppstate * pps, const std::vector & 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+1 < z) - pps->write(','); - } - - pps->newline_indent(ci0); - pps->write(']'); } }; template - struct ppdetail> { - static bool print_upto(ppstate * pps, const std::vector & x) { - return ppdetail>::print_upto(pps, x); - } - static void print_pretty(ppstate * pps, const std::vector & x) { - ppdetail>::print_pretty(pps, x); + struct ppdetail> { + static bool print_pretty(const ppindentinfo & ppii, const std::vector & x) { + return ppdetail_vector>::print_pretty(ppii, x); } }; } diff --git a/xo-indentlog/include/xo/indentlog/print/quoted.hpp b/xo-indentlog/include/xo/indentlog/print/quoted.hpp index 6de2bb95..c34d099f 100644 --- a/xo-indentlog/include/xo/indentlog/print/quoted.hpp +++ b/xo-indentlog/include/xo/indentlog/print/quoted.hpp @@ -103,13 +103,13 @@ namespace xo { } /*print*/ private: - /* .unq_flag: if true, omit surrounding " chars - * whenever printed value satisfies both: - * - no escaped chars - * - no spaces - */ + /** .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 behavior for completeness' sake: + /** writing out std::forward 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 auto quot(T && x) { return quot_impl(false /*unq_flag*/, std::forward(x)); diff --git a/xo-indentlog/include/xo/indentlog/print/tag.hpp b/xo-indentlog/include/xo/indentlog/print/tag.hpp index ad55f3c2..008dcbdd 100644 --- a/xo-indentlog/include/xo/indentlog/print/tag.hpp +++ b/xo-indentlog/include/xo/indentlog/print/tag.hpp @@ -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(n)}, value_{std::forward(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 + 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(n)}, value_{std::forward(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 - auto //tag_impl> + auto xtag(Name && n, Value && v) { - return tag_impl>(n, v); + return tag_impl, std::decay_t>(n, v); } /*xtag*/ - template - auto //tag_impl> - xtag(char const * n, Value && v) { - return tag_impl>(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 + auto + xrtag(Name && n, Value && v) + { + return tag_impl, std::decay_t>(n, v); + } // ----- tag ----- @@ -102,6 +136,28 @@ namespace xo { return tag_impl(n, v); } + // ----- rtag ----- + + template + auto + rtag(Name && n, Value && v) + { + return tag_impl, std::decay_t>(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 + auto + refrtag(Name && n, Value && v) + { + return ref_tag_impl, std::decay_t>(n, v); + } + // ----- operator<< on tag_impl ----- template @@ -124,6 +180,29 @@ namespace xo { return s; } /*operator<<*/ + + // ----- operator<< on ref_tag_impl ----- + + template + inline std::ostream & + operator<<(std::ostream &s, + ref_tag_impl 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 */ diff --git a/xo-indentlog/include/xo/indentlog/scope.hpp b/xo-indentlog/include/xo/indentlog/scope.hpp index 10cabf8e..3217e0e8 100644 --- a/xo-indentlog/include/xo/indentlog/scope.hpp +++ b/xo-indentlog/include/xo/indentlog/scope.hpp @@ -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 #include diff --git a/xo-jit/include/xo/jit/activation_record.hpp b/xo-jit/include/xo/jit/activation_record.hpp index 4b39eed3..ff59e9bf 100644 --- a/xo-jit/include/xo/jit/activation_record.hpp +++ b/xo-jit/include/xo/jit/activation_record.hpp @@ -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) * diff --git a/xo-jit/src/jit/MachPipeline.cpp b/xo-jit/src/jit/MachPipeline.cpp index 5c48c655..826cc7c2 100644 --- a/xo-jit/src/jit/MachPipeline.cpp +++ b/xo-jit/src/jit/MachPipeline.cpp @@ -3,6 +3,7 @@ #include "MachPipeline.hpp" #include "activation_record.hpp" #include "type2llvm.hpp" +#include "xo/expression/pretty_variable.hpp" #include namespace xo { diff --git a/xo-reactor/include/xo/reactor/PollingReactor.hpp b/xo-reactor/include/xo/reactor/PollingReactor.hpp index 2a0aca80..f5e02a12 100644 --- a/xo-reactor/include/xo/reactor/PollingReactor.hpp +++ b/xo-reactor/include/xo/reactor/PollingReactor.hpp @@ -22,6 +22,8 @@ namespace xo { virtual void notify_source_primed(bp 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 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 */ diff --git a/xo-reactor/include/xo/reactor/Reactor.hpp b/xo-reactor/include/xo/reactor/Reactor.hpp index 4b0d6bc9..a2048c0b 100644 --- a/xo-reactor/include/xo/reactor/Reactor.hpp +++ b/xo-reactor/include/xo/reactor/Reactor.hpp @@ -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*/ diff --git a/xo-reactor/src/reactor/PollingReactor.cpp b/xo-reactor/src/reactor/PollingReactor.cpp index 08316748..b01e3f9f 100644 --- a/xo-reactor/src/reactor/PollingReactor.cpp +++ b/xo-reactor/src/reactor/PollingReactor.cpp @@ -98,6 +98,15 @@ namespace xo { return retval; } /*run_one*/ + + void + PollingReactor::display(std::ostream & os) const { + os << ""; + } + } /*namespace reactor*/ } /*namespace xo*/ diff --git a/xo-reader/include/xo/reader/envframestack.hpp b/xo-reader/include/xo/reader/envframestack.hpp index 8084d584..2ec256fe 100644 --- a/xo-reader/include/xo/reader/envframestack.hpp +++ b/xo-reader/include/xo/reader/envframestack.hpp @@ -14,8 +14,10 @@ namespace xo { **/ class envframestack { public: - using LocalEnv = xo::ast::LocalEnv; - using Variable = xo::ast::Variable; + 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> stack_; diff --git a/xo-reader/include/xo/reader/exprstate.hpp b/xo-reader/include/xo/reader/exprstate.hpp index 83b459c8..0d9b7678 100644 --- a/xo-reader/include/xo/reader/exprstate.hpp +++ b/xo-reader/include/xo/reader/exprstate.hpp @@ -76,7 +76,7 @@ namespace xo { } class parserstatemachine; /* see parserstatemachine.hpp */ - class exprstatestack; + class exprstatestack; /* see exprstatestack.hpp */ class formal_arg; diff --git a/xo-reader/include/xo/reader/exprstatestack.hpp b/xo-reader/include/xo/reader/exprstatestack.hpp index ce7bdc1d..e8f51d45 100644 --- a/xo-reader/include/xo/reader/exprstatestack.hpp +++ b/xo-reader/include/xo/reader/exprstatestack.hpp @@ -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> stack_; @@ -65,21 +70,6 @@ namespace xo { return os; } } /*namespace scm*/ - -#ifndef ppdetail_atomic - namespace print { - template <> - struct ppdetail { - static bool print_upto(ppstate * pps, const xo::scm::exprstatestack * x) { - return ppdetail_atomic::print_upto(pps, x); - } - static void print_pretty(ppstate * pps, const xo::scm::exprstatestack * x) { - ppdetail_atomic::print_pretty(pps, x); - } - }; - } -#endif - } /*namespace xo*/ diff --git a/xo-reader/include/xo/reader/parserstatemachine.hpp b/xo-reader/include/xo/reader/parserstatemachine.hpp index decc1e6c..490ac35c 100644 --- a/xo-reader/include/xo/reader/parserstatemachine.hpp +++ b/xo-reader/include/xo/reader/parserstatemachine.hpp @@ -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 */ diff --git a/xo-reader/include/xo/reader/pretty_envframestack.hpp b/xo-reader/include/xo/reader/pretty_envframestack.hpp new file mode 100644 index 00000000..043b0eb2 --- /dev/null +++ b/xo-reader/include/xo/reader/pretty_envframestack.hpp @@ -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 { + static inline bool print_pretty(const ppindentinfo & ppii, const xo::scm::envframestack * p) { + return p->pretty_print(ppii); + } + }; + } /*namespace print*/ +} /*namespace xo*/ diff --git a/xo-reader/include/xo/reader/pretty_exprstatestack.hpp b/xo-reader/include/xo/reader/pretty_exprstatestack.hpp new file mode 100644 index 00000000..4c2b04f1 --- /dev/null +++ b/xo-reader/include/xo/reader/pretty_exprstatestack.hpp @@ -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 { + static inline bool print_pretty(const ppindentinfo & ppii, const xo::scm::exprstatestack * p) { + return p->pretty_print(ppii); + } + }; + } /*namespace print*/ +} /*namespace xo*/ diff --git a/xo-reader/include/xo/reader/pretty_parserstatemachine.hpp b/xo-reader/include/xo/reader/pretty_parserstatemachine.hpp new file mode 100644 index 00000000..512a6844 --- /dev/null +++ b/xo-reader/include/xo/reader/pretty_parserstatemachine.hpp @@ -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 { + static bool print_pretty(const ppindentinfo & ppii, const xo::scm::parserstatemachine & x); + }; + } +} /*namespace xo*/ diff --git a/xo-reader/src/reader/CMakeLists.txt b/xo-reader/src/reader/CMakeLists.txt index 785855ec..9024a19a 100644 --- a/xo-reader/src/reader/CMakeLists.txt +++ b/xo-reader/src/reader/CMakeLists.txt @@ -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) diff --git a/xo-reader/src/reader/envframestack.cpp b/xo-reader/src/reader/envframestack.cpp index 6b27a26d..97bca077 100644 --- a/xo-reader/src/reader/envframestack.cpp +++ b/xo-reader/src/reader/envframestack.cpp @@ -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("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("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*/ diff --git a/xo-reader/src/reader/exprstate.cpp b/xo-reader/src/reader/exprstate.cpp index bf30134d..13714a38 100644 --- a/xo-reader/src/reader/exprstate.cpp +++ b/xo-reader/src/reader/exprstate.cpp @@ -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" diff --git a/xo-reader/src/reader/exprstatestack.cpp b/xo-reader/src/reader/exprstatestack.cpp index 2e070c48..bb38305a 100644 --- a/xo-reader/src/reader/exprstatestack.cpp +++ b/xo-reader/src/reader/exprstatestack.cpp @@ -4,6 +4,7 @@ */ #include "exprstatestack.hpp" +#include 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("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("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*/ diff --git a/xo-reader/src/reader/parserstatemachine.cpp b/xo-reader/src/reader/parserstatemachine.cpp index 34c7cbbe..feb99d53 100644 --- a/xo-reader/src/reader/parserstatemachine.cpp +++ b/xo-reader/src/reader/parserstatemachine.cpp @@ -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 { diff --git a/xo-reader/src/reader/pretty_parserstatemachine.cpp b/xo-reader/src/reader/pretty_parserstatemachine.cpp new file mode 100644 index 00000000..b4649042 --- /dev/null +++ b/xo-reader/src/reader/pretty_parserstatemachine.cpp @@ -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::print_pretty(const ppindentinfo & ppii, const xo::scm::parserstatemachine & x) + { + ppstate * pps = ppii.pps(); + + if (ppii.upto()) { + if (!pps->print_upto("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("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*/ diff --git a/xo-reader/src/reader/progress_xs.cpp b/xo-reader/src/reader/progress_xs.cpp index fea536a7..4fe13126 100644 --- a/xo-reader/src/reader/progress_xs.cpp +++ b/xo-reader/src/reader/progress_xs.cpp @@ -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" diff --git a/xo-refcnt/include/xo/refcnt/pretty_refcnt.hpp b/xo-refcnt/include/xo/refcnt/pretty_refcnt.hpp index ecf53aba..8c1903f1 100644 --- a/xo-refcnt/include/xo/refcnt/pretty_refcnt.hpp +++ b/xo-refcnt/include/xo/refcnt/pretty_refcnt.hpp @@ -10,66 +10,67 @@ namespace xo { namespace print { +#ifndef ppdetail_atomic template <> struct ppdetail { - static bool print_upto(ppstate * pps, const xo::ref::Refcount * x) { - return ppdetail_atomic::print_upto(pps, x); - } - static void print_pretty(ppstate * pps, const xo::ref::Refcount * x) { - ppdetail_atomic::print_pretty(pps, x); + static bool print_pretty(const ppindentinfo & ppii, const xo::ref::Refcount * x) { + return ppdetail_atomic::print_pretty(ppii, x); } }; +#endif template struct ppdetail> { - static bool print_upto(ppstate * pps, const rp & x) { - if (auto p = x.get()) { - return ppdetail::print_upto(pps, *p); + static bool print_pretty(const ppindentinfo & ppii, const rp & x) { + if (ppii.upto()) { + if (auto p = x.get()) { + return ppdetail::print_pretty(ppii, *p); + } else { + /* note: degenerate case here, since never write newline for nullptr */ + + ppii.pps()->write("write(reflect::type_name()); + ppii.pps()->write(">"); + + return ppii.pps()->has_margin(); + } } else { - /* note: degenerate case here, since never write newline for nullptr */ - - pps->write("write(reflect::type_name()); - pps->write(">"); - - return pps->has_margin(); - } - } - - static void print_pretty(ppstate * pps, const rp & x) { - if (auto p = x.get()) { - ppdetail::print_pretty(pps, *p); - } else { - pps->write("write(reflect::type_name()); - pps->write(">"); + if (auto p = x.get()) { + ppdetail::print_pretty(ppii, *p); + } else { + ppii.pps()->write("write(reflect::type_name()); + ppii.pps()->write(">"); + } + return false; } } }; template struct ppdetail> { - static bool print_upto(ppstate * pps, const bp & x) { - if (auto p = x.get()) { - return ppdetail::print_upto(pps, *p); + static bool print_pretty(const ppindentinfo & ppii, const bp & x) { + if (ppii.upto()) { + if (auto p = x.get()) { + return ppdetail::print_pretty(ppii, *p); + } else { + /* note: degenerate case here, since never write newline for nullptr */ + + ppii.pps()->write("write(reflect::type_name()); + ppii.pps()->write(">"); + + return ppii.pps()->has_margin(); + } } else { - /* note: degenerate case here, since never write newline for nullptr */ - - pps->write("write(reflect::type_name()); - pps->write(">"); - - return pps->has_margin(); - } - } - - static void print_pretty(ppstate * pps, const bp & x) { - if (auto p = x.get()) { - ppdetail::print_pretty(pps, *p); - } else { - pps->write("write(reflect::type_name()); - pps->write(">"); + if (auto p = x.get()) { + ppdetail::print_pretty(ppii, *p); + } else { + ppii.pps()->write("write(reflect::type_name()); + ppii.pps()->write(">"); + } + return false; } } }; diff --git a/xo-simulator/include/xo/simulator/Simulator.hpp b/xo-simulator/include/xo/simulator/Simulator.hpp index 37c696cf..3a57b783 100644 --- a/xo-simulator/include/xo/simulator/Simulator.hpp +++ b/xo-simulator/include/xo/simulator/Simulator.hpp @@ -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); diff --git a/xo-simulator/src/simulator/Simulator.cpp b/xo-simulator/src/simulator/Simulator.cpp index 2f6ddff5..7c63ed14 100644 --- a/xo-simulator/src/simulator/Simulator.cpp +++ b/xo-simulator/src/simulator/Simulator.cpp @@ -543,6 +543,16 @@ namespace xo { return n; } /*run_throttled_until*/ + void + Simulator::display(std::ostream & os) const + { + os << ""; + } /*display*/ + } /*namespace sim*/ } /*namespace xo*/ diff --git a/xo-unit/utest/basis_unit.test.cpp b/xo-unit/utest/basis_unit.test.cpp index 0874db56..06b6fc23 100644 --- a/xo-unit/utest/basis_unit.test.cpp +++ b/xo-unit/utest/basis_unit.test.cpp @@ -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