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

This commit is contained in:
Roland Conybeare 2025-07-19 11:47:03 -05:00
commit b8ae0f95fa
28 changed files with 327 additions and 116 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

@ -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 */

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*/