diff --git a/xo-expression2/CMakeLists.txt b/xo-expression2/CMakeLists.txt index 869f891d..5fc6d451 100644 --- a/xo-expression2/CMakeLists.txt +++ b/xo-expression2/CMakeLists.txt @@ -150,6 +150,32 @@ xo_add_genfacetimpl( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-expression2-facetimpl-expression-ifelseexpr + FACET_PKG xo_expression2 + FACET Expression + REPR IfElseExpr + INPUT idl/IExpression_DIfElseExpr.json5 + OUTPUT_HPP_DIR include/xo/expression2 + OUTPUT_IMPL_SUBDIR detail + OUTPUT_CPP_DIR src/expression2 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-expression2-facetimpl-printable-ifelseexpr + FACET_PKG xo_printable2 + FACET Printable + REPR IfElseExpr + INPUT idl/IPrintable_DIfElseExpr.json5 + OUTPUT_HPP_DIR include/xo/expression2 + OUTPUT_IMPL_SUBDIR detail + OUTPUT_CPP_DIR src/expression2 +) + +# ---------------------------------------------------------------- + # note: manual target; generated code committed to git xo_add_genfacetimpl( TARGET xo-expression2-facetimpl-gcobject-uniquestring diff --git a/xo-expression2/idl/IExpression_DIfElseExpr.json5 b/xo-expression2/idl/IExpression_DIfElseExpr.json5 new file mode 100644 index 00000000..ed2fb1e8 --- /dev/null +++ b/xo-expression2/idl/IExpression_DIfElseExpr.json5 @@ -0,0 +1,12 @@ +{ + mode: "implementation", + includes: [ "\"Expression.hpp\"" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Expression.json5", + brief: "provide AExpression interface for DIfElseExpr state", + using_doxygen: true, + repr: "DIfElseExpr", + doc: ["doc for IExpression+DIfElseExpr" ], +} diff --git a/xo-expression2/idl/IPrintable_DIfElseExpr.json5 b/xo-expression2/idl/IPrintable_DIfElseExpr.json5 new file mode 100644 index 00000000..a8011385 --- /dev/null +++ b/xo-expression2/idl/IPrintable_DIfElseExpr.json5 @@ -0,0 +1,13 @@ +{ + mode: "implementation", + includes: [ "", + "" ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Printable.json5", + brief: "provide APrintable interface for DIfElseExpr", + using_doxygen: true, + repr: "DIfElseExpr", + doc: [ "implement APrintable for DIfElseExpr" ], +} diff --git a/xo-expression2/include/xo/expression2/DIfElseExpr.hpp b/xo-expression2/include/xo/expression2/DIfElseExpr.hpp new file mode 100644 index 00000000..4a1107ca --- /dev/null +++ b/xo-expression2/include/xo/expression2/DIfElseExpr.hpp @@ -0,0 +1,230 @@ +/** @file DIfElseExpr.hpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include "Expression.hpp" +#include "TypeRef.hpp" +#include "exprtype.hpp" +#include +//#include +#include +//#include + +namespace xo { + namespace scm { + + /** @class DIfExpr + * @brief abstract syntax tree for a function definition + **/ + class DIfElseExpr { + public: + using AAllocator = xo::mm::AAllocator; + using TypeDescr = xo::reflect::TypeDescr; + using ppindentinfo = xo::print::ppindentinfo; + + public: + /** @defgroup scm-ifelseexpr-constructors **/ + ///@{ + + /** + * @p ifexpr_type type for value produced by if-expression. + * same as both when_true->valuetype() and + * when_false->valuetype(). + * @p test test-expression; always execute + * @p when_true then-branch; executes only when test succeeds + * @p when_false else-branch; executes only when test fails + **/ + DIfElseExpr(TypeRef ifexpr_type, + obj test_expr, + obj when_true, + obj when_false); + + /** create if-else expression using memory from @p mm. + * @p when_false can be null + **/ + static obj make(obj mm, + obj test, + obj when_true, + obj when_false); + + /** create expression for conditional execution of + * @p when_true or @p when_false, depending on result + * of evaluating expression @p test + **/ + static DIfElseExpr * _make(obj mm, + obj test, + obj when_true, + obj when_false); + + ///@} + /** @defgroup scm-ifelseexpr-access-methods **/ + ///@{ + + obj test() const noexcept { return test_; } + obj when_true() const noexcept { return when_true_; } + obj when_false() const noexcept { return when_false_; } + + ///@} + /** @defgroup scm-ifelseexpr-expression-facet **/ + ///@{ + + exprtype extype() const noexcept { return exprtype::ifexpr; } + TypeRef typeref() const noexcept { return typeref_; } + TypeDescr valuetype() const noexcept { return typeref_.td(); } + void assign_valuetype(TypeDescr td) noexcept; + + ///@} + /** @defgroup scm-ifelseexpr-printable-facet **/ + ///@{ + + bool pretty(const ppindentinfo & ppii) const; + + ///@} + +#ifdef NOT_YET + virtual std::set get_free_variables() const override { + std::set retval = test_->get_free_variables(); + + std::set free_vars; + free_vars = when_true_->get_free_variables(); + for (const auto & s : free_vars) + retval.insert(s); + + free_vars = when_false_->get_free_variables(); + for (const auto & s : free_vars) + retval.insert(s); + + return retval; + } + + virtual std::size_t visit_preorder(VisitFn visitor_fn) override { + std::size_t n = 1; + + visitor_fn(this); + + n += this->test_->visit_preorder(visitor_fn); + n += this->when_true_->visit_preorder(visitor_fn); + n += this->when_false_->visit_preorder(visitor_fn); + + return n; + } + + virtual std::size_t visit_layer(VisitFn visitor_fn) override { + std::size_t n = 1; + + visitor_fn(this); + + n += this->test_->visit_layer(visitor_fn); + n += this->when_true_->visit_layer(visitor_fn); + n += this->when_false_->visit_layer(visitor_fn); + + return n; + } + + virtual rp xform_layer(TransformFn xform_fn) override { + this->test_ = this->test_->xform_layer(xform_fn); + this->when_true_ = this->when_true_->xform_layer(xform_fn); + this->when_false_= this->when_false_->xform_layer(xform_fn); + + return xform_fn(this); + } + + virtual void attach_envs(bp p) override { + test_->attach_envs(p); + when_true_->attach_envs(p); + when_false_->attach_envs(p); + } +#endif + +#ifdef NOT_USING + virtual std::int32_t find_free_vars(std::set> * p_set) override { + return (test_->find_free_vars(p_set) + + when_true_->find_free_vars(p_set) + + when_false_->find_free_vars(p_set)); + } +#endif + +#ifdef NOPE + virtual void display(std::ostream & os) const override; + virtual std::uint32_t pretty_print(const ppindentinfo & ppi) const override; +#endif + + protected: +#ifdef NOT_YET + /** + * @p ifexpr_type type for value produced by if-expression. + * same as both when_true->valuetype() and + * when_false->valuetype(). + * @p test test-expression; always execute + * @p when_true then-branch; executes only when test succeeds + * @p when_false else-branch; executes only when test fails + **/ + IfExpr(TypeDescr ifexpr_type, + rp test, + rp when_true, + rp when_false) + : Expression(exprtype::ifexpr, ifexpr_type), + test_{std::move(test)}, + when_true_{std::move(when_true)}, + when_false_{std::move(when_false)} {} + + static TypeDescr check_consistent_valuetype(const rp & when_true, + const rp & when_false); + + /** determine if-expr valuetype **/ + void establish_valuetype(); +#endif + + private: + /** expression value always has type consistent + * with this description + **/ + TypeRef typeref_; + /** if: + * (if x y z) + * + * executes x; if true execute y; otherwise execute z + **/ + obj test_; + obj when_true_; + obj when_false_; + }; /*IfExpr*/ + +#ifdef NOPE + inline rp + make_ifexpr(const rp & test, + const rp & when_true, + const rp & when_false) + { + return IfExpr::make(test, when_true, when_false); + } + + class IfExprAccess : public IfExpr { + public: + static rp make(rp test, + rp when_true, + rp when_false); + static rp make_empty(); + + void assign_test(rp x) { test_ = std::move(x); } + void assign_when_true(rp x); + void assign_when_false(rp x); + + private: + IfExprAccess(TypeDescr ifexpr_type, + rp test, + rp when_true, + rp when_false) + : IfExpr(ifexpr_type, + std::move(test), + std::move(when_true), + std::move(when_false)) {} + }; +#endif + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DIfElseExpr.hpp */ diff --git a/xo-expression2/include/xo/expression2/detail/IExpression_DIfElseExpr.hpp b/xo-expression2/include/xo/expression2/detail/IExpression_DIfElseExpr.hpp new file mode 100644 index 00000000..03500a39 --- /dev/null +++ b/xo-expression2/include/xo/expression2/detail/IExpression_DIfElseExpr.hpp @@ -0,0 +1,66 @@ +/** @file IExpression_DIfElseExpr.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IExpression_DIfElseExpr.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IExpression_DIfElseExpr.json5] + **/ + +#pragma once + +#include "Expression.hpp" +#include "Expression.hpp" +#include "DIfElseExpr.hpp" + +namespace xo { namespace scm { class IExpression_DIfElseExpr; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::IExpression_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IExpression_DIfElseExpr + **/ + class IExpression_DIfElseExpr { + public: + /** @defgroup scm-expression-difelseexpr-type-traits **/ + ///@{ + using TypeDescr = xo::scm::AExpression::TypeDescr; + using Copaque = xo::scm::AExpression::Copaque; + using Opaque = xo::scm::AExpression::Opaque; + ///@} + /** @defgroup scm-expression-difelseexpr-methods **/ + ///@{ + // const methods + /** expression type (constant | apply | ..) **/ + static exprtype extype(const DIfElseExpr & self) noexcept; + /** placeholder for type giving possible values for this expression **/ + static TypeRef typeref(const DIfElseExpr & self) noexcept; + /** type giving possible values for this expression. Maybe null before typecheck **/ + static TypeDescr valuetype(const DIfElseExpr & self) noexcept; + + // non-const methods + /** assing to valuetype member. Useful when scaffolding expressions **/ + static void assign_valuetype(DIfElseExpr & self, TypeDescr td) noexcept; + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/xo-expression2/include/xo/expression2/detail/IPrintable_DIfElseExpr.hpp b/xo-expression2/include/xo/expression2/detail/IPrintable_DIfElseExpr.hpp new file mode 100644 index 00000000..e9cf67ff --- /dev/null +++ b/xo-expression2/include/xo/expression2/detail/IPrintable_DIfElseExpr.hpp @@ -0,0 +1,62 @@ +/** @file IPrintable_DIfElseExpr.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DIfElseExpr.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DIfElseExpr.json5] + **/ + +#pragma once + +#include "Printable.hpp" +#include +#include +#include "DIfElseExpr.hpp" + +namespace xo { namespace scm { class IPrintable_DIfElseExpr; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::print::IPrintable_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class IPrintable_DIfElseExpr + **/ + class IPrintable_DIfElseExpr { + public: + /** @defgroup scm-printable-difelseexpr-type-traits **/ + ///@{ + using ppindentinfo = xo::print::APrintable::ppindentinfo; + using Copaque = xo::print::APrintable::Copaque; + using Opaque = xo::print::APrintable::Opaque; + ///@} + /** @defgroup scm-printable-difelseexpr-methods **/ + ///@{ + // const methods + /** Pretty-printing support for this object. +See [xo-indentlog/xo/indentlog/pretty.hpp] **/ + static bool pretty(const DIfElseExpr & self, const ppindentinfo & ppii); + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/xo-expression2/include/xo/expression2/exprtype.hpp b/xo-expression2/include/xo/expression2/exprtype.hpp index df4e3be6..952051be 100644 --- a/xo-expression2/include/xo/expression2/exprtype.hpp +++ b/xo-expression2/include/xo/expression2/exprtype.hpp @@ -38,9 +38,9 @@ namespace xo { #endif /** variable reference **/ variable, -#ifdef NOT_YET /** if-then-else **/ ifexpr, +#ifdef NOT_YET /** sequence **/ sequence, /** type conversion **/ diff --git a/xo-expression2/src/expression2/CMakeLists.txt b/xo-expression2/src/expression2/CMakeLists.txt index 7a7013de..840e7070 100644 --- a/xo-expression2/src/expression2/CMakeLists.txt +++ b/xo-expression2/src/expression2/CMakeLists.txt @@ -8,6 +8,7 @@ set(SELF_SRCS DVariable.cpp DDefineExpr.cpp DApplyExpr.cpp + DIfElseExpr.cpp TypeRef.cpp @@ -25,6 +26,9 @@ set(SELF_SRCS IExpression_DApplyExpr.cpp IPrintable_DApplyExpr.cpp + IExpression_DIfElseExpr.cpp + IPrintable_DIfElseExpr.cpp + DLocalSymtab.cpp DGlobalSymtab.cpp diff --git a/xo-expression2/src/expression2/DDefineExpr.cpp b/xo-expression2/src/expression2/DDefineExpr.cpp index ba2304ad..961fbecc 100644 --- a/xo-expression2/src/expression2/DDefineExpr.cpp +++ b/xo-expression2/src/expression2/DDefineExpr.cpp @@ -1,5 +1,5 @@ /** @file DDefineExpr.cpp -* + * * @author Roland Conybeare, Jan 2026 **/ diff --git a/xo-expression2/src/expression2/DIfElseExpr.cpp b/xo-expression2/src/expression2/DIfElseExpr.cpp new file mode 100644 index 00000000..0e18114e --- /dev/null +++ b/xo-expression2/src/expression2/DIfElseExpr.cpp @@ -0,0 +1,184 @@ +/** @file DIfElseExpr.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "DIfElseExpr.hpp" +#include "detail/IExpression_DIfElseExpr.hpp" +#include +#include +#include + +namespace xo { + using xo::print::APrintable; + using xo::reflect::typeseq; + using xo::facet::FacetRegistry; + + namespace scm { + DIfElseExpr::DIfElseExpr(TypeRef ifexpr_tref, + obj test_expr, + obj when_true, + obj when_false) + : typeref_{ifexpr_tref}, + test_{test_expr}, + when_true_{when_true}, + when_false_{when_false} + {} + + obj + DIfElseExpr::make(obj mm, + obj test, + obj when_true, + obj when_false) + { + return obj + (_make(mm, + test, when_true, when_false)); + } + + DIfElseExpr * + DIfElseExpr::_make(obj mm, + obj test, + obj when_true, + obj when_false) + { + void * mem = mm.alloc(typeseq::id(), + sizeof(DIfElseExpr)); + + // just crete typevar here, then rely on type checking + // later + + auto prefix = TypeRef::prefix_type::from_chars("if"); + TypeRef tref = TypeRef::dwim(prefix, nullptr); + + return new (mem) DIfElseExpr(tref, + test, + when_true, + when_false); + } + + void + DIfElseExpr::assign_valuetype(TypeDescr td) noexcept + { + typeref_.resolve(td); + } + + bool + DIfElseExpr::pretty(const ppindentinfo & ppii) const + { + auto test + = FacetRegistry::instance().try_variant(test_); + auto when_true + = FacetRegistry::instance().try_variant(when_true_); + auto when_false + = FacetRegistry::instance().try_variant(when_false_); + + + return ppii.pps()->pretty_struct + (ppii, + "DIfElseExpr", + refrtag("typeref", typeref_), + refrtag("test", test), + refrtag("when_true", when_true), + refrtag("when_false", when_false)); + } + + // ---------------------------------------------------------------- + +#ifdef NOPE + auto IfExpr::check_consistent_valuetype(const rp & when_true, + const rp & when_false) -> TypeDescr + { + if (when_true->valuetype() != when_false->valuetype()) + return nullptr; + + return when_true->valuetype(); + } + + void IfExpr::establish_valuetype() + { + if (this->when_true_.get() && this->when_false_.get()) + this->assign_valuetype(check_consistent_valuetype(this->when_true_, this->when_false_)); + } + + rp + IfExpr::make(const rp & test, + const rp & when_true, + const rp & when_false) + { + /** TODO: verify test returns _boolean_ type **/ + + if (when_true->valuetype() != when_false->valuetype()) { + throw std::runtime_error + (tostr("IfExpr::make:" + " types {T1,T2} found for branches of if-expr" + " where equal types expected", + xtag("T1", when_true->valuetype()->canonical_name()), + xtag("T2", when_false->valuetype()->canonical_name()))); + } + + /* arbitrary choice here */ + auto ifexpr_type = when_true->valuetype(); + + return new IfExpr(ifexpr_type, + test, + when_true, + when_false); + } /*make*/ + + void + IfExpr::display(std::ostream & os) const { + os << ""; + } /*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_)); + } + + rp + IfExprAccess::make(rp test, + rp when_true, + rp when_false) + { + auto ifexpr_type = check_consistent_valuetype(when_true, when_false); + + return new IfExprAccess(ifexpr_type, std::move(test), std::move(when_true), std::move(when_false)); + } + + rp + IfExprAccess::make_empty() + { + return new IfExprAccess(nullptr /*ifexpr_valuetype*/, + nullptr /*test*/, + nullptr /*when_true*/, + nullptr /*when_false*/); + } + + void + IfExprAccess::assign_when_true(rp x) + { + this->when_true_ = std::move(x); + } + + void + IfExprAccess::assign_when_false(rp x) + { + this->when_false_ = std::move(x); + } +#endif + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DIfElseExpr.cpp */ diff --git a/xo-expression2/src/expression2/IExpression_DIfElseExpr.cpp b/xo-expression2/src/expression2/IExpression_DIfElseExpr.cpp new file mode 100644 index 00000000..78680310 --- /dev/null +++ b/xo-expression2/src/expression2/IExpression_DIfElseExpr.cpp @@ -0,0 +1,45 @@ +/** @file IExpression_DIfElseExpr.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IExpression_DIfElseExpr.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IExpression_DIfElseExpr.json5] +**/ + +#include "detail/IExpression_DIfElseExpr.hpp" + +namespace xo { + namespace scm { + auto + IExpression_DIfElseExpr::extype(const DIfElseExpr & self) noexcept -> exprtype + { + return self.extype(); + } + + auto + IExpression_DIfElseExpr::typeref(const DIfElseExpr & self) noexcept -> TypeRef + { + return self.typeref(); + } + + auto + IExpression_DIfElseExpr::valuetype(const DIfElseExpr & self) noexcept -> TypeDescr + { + return self.valuetype(); + } + + auto + IExpression_DIfElseExpr::assign_valuetype(DIfElseExpr & self, TypeDescr td) noexcept -> void + { + self.assign_valuetype(td); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IExpression_DIfElseExpr.cpp */ \ No newline at end of file diff --git a/xo-expression2/src/expression2/IPrintable_DIfElseExpr.cpp b/xo-expression2/src/expression2/IPrintable_DIfElseExpr.cpp new file mode 100644 index 00000000..ec68b9fc --- /dev/null +++ b/xo-expression2/src/expression2/IPrintable_DIfElseExpr.cpp @@ -0,0 +1,28 @@ +/** @file IPrintable_DIfElseExpr.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [/Users/roland/proj/xo-umbrella2/xo-facet/codegen/genfacet] + * arguments: + * --input [idl/IPrintable_DIfElseExpr.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/IPrintable_DIfElseExpr.json5] +**/ + +#include "detail/IPrintable_DIfElseExpr.hpp" + +namespace xo { + namespace scm { + auto + IPrintable_DIfElseExpr::pretty(const DIfElseExpr & self, const ppindentinfo & ppii) -> bool + { + return self.pretty(ppii); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end IPrintable_DIfElseExpr.cpp */ \ No newline at end of file diff --git a/xo-expression2/src/expression2/expression2_register_facets.cpp b/xo-expression2/src/expression2/expression2_register_facets.cpp index fc6ef3c1..8ab2ff51 100644 --- a/xo-expression2/src/expression2/expression2_register_facets.cpp +++ b/xo-expression2/src/expression2/expression2_register_facets.cpp @@ -20,6 +20,9 @@ #include #include +#include +#include + #include #include #include @@ -44,7 +47,8 @@ namespace xo { // +- Constant // +- Variable // +- DefineExpr - // \- ApplyExpr + // +- ApplyExpr + // \- IfElseExpr FacetRegistry::register_impl(); FacetRegistry::register_impl(); @@ -58,11 +62,15 @@ namespace xo { FacetRegistry::register_impl(); FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + FacetRegistry::register_impl(); + log && log(xtag("DUniqueString.tseq", typeseq::id())); log && log(xtag("DDefineExpr.tseq", typeseq::id())); log && log(xtag("DVariable.tseq", typeseq::id())); log && log(xtag("DConstant.tseq", typeseq::id())); log && log(xtag("DApplyExpr.tseq", typeseq::id())); + log && log(xtag("DIfElseExpr.tseq", typeseq::id())); log && log(xtag("AExpression.tqseq", typeseq::id())); diff --git a/xo-expression2/utest/CMakeLists.txt b/xo-expression2/utest/CMakeLists.txt index f464708e..deb1d25a 100644 --- a/xo-expression2/utest/CMakeLists.txt +++ b/xo-expression2/utest/CMakeLists.txt @@ -9,6 +9,7 @@ set(UTEST_SRCS DVariable.test.cpp DApplyExpr.test.cpp DDefineExpr.test.cpp + DIfElseExpr.test.cpp ) xo_add_utest_executable(${UTEST_EXE} ${UTEST_SRCS}) diff --git a/xo-expression2/utest/DIfElseExpr.test.cpp b/xo-expression2/utest/DIfElseExpr.test.cpp new file mode 100644 index 00000000..a82521a0 --- /dev/null +++ b/xo-expression2/utest/DIfElseExpr.test.cpp @@ -0,0 +1,345 @@ +/** @file DIfElseExpr.test.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "init_expression2.hpp" +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include + +namespace ut { + using xo::S_expression2_tag; + using xo::scm::DIfElseExpr; + using xo::scm::DConstant; + using xo::scm::DFloat; + using xo::scm::DBoolean; + using xo::scm::AExpression; + using xo::mm::CollectorTypeRegistry; + using xo::mm::AAllocator; + using xo::mm::ACollector; + using xo::mm::AGCObject; + using xo::mm::DX1Collector; + using xo::mm::CollectorConfig; + using xo::mm::ArenaConfig; + using xo::print::APrintable; + using xo::print::ppstate_standalone; + using xo::print::ppconfig; + using xo::facet::FacetRegistry; + using xo::facet::with_facet; + using xo::facet::obj; + using xo::reflect::Reflect; + using xo::InitEvidence; + using xo::InitSubsys; + using xo::scope; + + static InitEvidence s_init = InitSubsys::require(); + + TEST_CASE("DIfElseExpr-init", "[expression2][DIfElseExpr]") + { + REQUIRE(s_init.evidence()); + } + + TEST_CASE("DIfElseExpr-make", "[expression2][DIfElseExpr]") + { + REQUIRE(s_init.evidence()); + + CollectorConfig cfg{ + .name_ = "difelseexpr_make_test", + .arena_config_ = ArenaConfig{ + .size_ = 8192, + .store_header_flag_ = true}, + .object_types_z_ = 16384, + .gc_trigger_v_{{4096, 4096}}, + .debug_flag_ = false, + }; + + DX1Collector gc(cfg); + auto alloc = with_facet::mkobj(&gc); + auto coll = with_facet::mkobj(&gc); + + bool ok = CollectorTypeRegistry::instance().install_types(coll); + REQUIRE(ok); + + // Create test expression: constant true + obj bval = DBoolean::box(alloc, true); + auto test_expr = DConstant::make(alloc, bval); + REQUIRE(test_expr.data() != nullptr); + + // Create when_true expression: constant 1.0 + obj fval1 = DFloat::box(alloc, 1.0); + auto when_true_expr = DConstant::make(alloc, fval1); + REQUIRE(when_true_expr.data() != nullptr); + + // Create when_false expression: constant 2.0 + obj fval2 = DFloat::box(alloc, 2.0); + auto when_false_expr = DConstant::make(alloc, fval2); + REQUIRE(when_false_expr.data() != nullptr); + + // Create if-else expression: if true then 1.0 else 2.0 + auto ifexpr = DIfElseExpr::make(alloc, test_expr, when_true_expr, when_false_expr); + REQUIRE(ifexpr.data() != nullptr); + } + + TEST_CASE("DIfElseExpr-test", "[expression2][DIfElseExpr]") + { + REQUIRE(s_init.evidence()); + + CollectorConfig cfg{ + .name_ = "difelseexpr_test_test", + .arena_config_ = ArenaConfig{ + .size_ = 8192, + .store_header_flag_ = true}, + .object_types_z_ = 16384, + .gc_trigger_v_{{4096, 4096}}, + .debug_flag_ = false, + }; + + DX1Collector gc(cfg); + auto alloc = with_facet::mkobj(&gc); + auto coll = with_facet::mkobj(&gc); + + bool ok = CollectorTypeRegistry::instance().install_types(coll); + REQUIRE(ok); + + obj bval = DBoolean::box(alloc, true); + auto test_expr = DConstant::make(alloc, bval); + + obj fval1 = DFloat::box(alloc, 1.0); + auto when_true_expr = DConstant::make(alloc, fval1); + + obj fval2 = DFloat::box(alloc, 2.0); + auto when_false_expr = DConstant::make(alloc, fval2); + + auto ifexpr = DIfElseExpr::make(alloc, test_expr, when_true_expr, when_false_expr); + REQUIRE(ifexpr.data() != nullptr); + + obj test = ifexpr.data()->test(); + REQUIRE(test.data() != nullptr); + REQUIRE(test.extype() == xo::scm::exprtype::constant); + } + + TEST_CASE("DIfElseExpr-when-true", "[expression2][DIfElseExpr]") + { + REQUIRE(s_init.evidence()); + + CollectorConfig cfg{ + .name_ = "difelseexpr_when_true_test", + .arena_config_ = ArenaConfig{ + .size_ = 8192, + .store_header_flag_ = true}, + .object_types_z_ = 16384, + .gc_trigger_v_{{4096, 4096}}, + .debug_flag_ = false, + }; + + DX1Collector gc(cfg); + auto alloc = with_facet::mkobj(&gc); + auto coll = with_facet::mkobj(&gc); + + bool ok = CollectorTypeRegistry::instance().install_types(coll); + REQUIRE(ok); + + obj bval = DBoolean::box(alloc, true); + auto test_expr = DConstant::make(alloc, bval); + + obj fval1 = DFloat::box(alloc, 1.0); + auto when_true_expr = DConstant::make(alloc, fval1); + + obj fval2 = DFloat::box(alloc, 2.0); + auto when_false_expr = DConstant::make(alloc, fval2); + + auto ifexpr = DIfElseExpr::make(alloc, test_expr, when_true_expr, when_false_expr); + REQUIRE(ifexpr.data() != nullptr); + + obj wt = ifexpr.data()->when_true(); + REQUIRE(wt.data() != nullptr); + REQUIRE(wt.extype() == xo::scm::exprtype::constant); + } + + TEST_CASE("DIfElseExpr-when-false", "[expression2][DIfElseExpr]") + { + REQUIRE(s_init.evidence()); + + CollectorConfig cfg{ + .name_ = "difelseexpr_when_false_test", + .arena_config_ = ArenaConfig{ + .size_ = 8192, + .store_header_flag_ = true}, + .object_types_z_ = 16384, + .gc_trigger_v_{{4096, 4096}}, + .debug_flag_ = false, + }; + + DX1Collector gc(cfg); + auto alloc = with_facet::mkobj(&gc); + auto coll = with_facet::mkobj(&gc); + + bool ok = CollectorTypeRegistry::instance().install_types(coll); + REQUIRE(ok); + + obj bval = DBoolean::box(alloc, false); + auto test_expr = DConstant::make(alloc, bval); + + obj fval1 = DFloat::box(alloc, 1.0); + auto when_true_expr = DConstant::make(alloc, fval1); + + obj fval2 = DFloat::box(alloc, 2.0); + auto when_false_expr = DConstant::make(alloc, fval2); + + auto ifexpr = DIfElseExpr::make(alloc, test_expr, when_true_expr, when_false_expr); + REQUIRE(ifexpr.data() != nullptr); + + obj wf = ifexpr.data()->when_false(); + REQUIRE(wf.data() != nullptr); + REQUIRE(wf.extype() == xo::scm::exprtype::constant); + } + + TEST_CASE("DIfElseExpr-extype", "[expression2][DIfElseExpr]") + { + REQUIRE(s_init.evidence()); + + CollectorConfig cfg{ + .name_ = "difelseexpr_extype_test", + .arena_config_ = ArenaConfig{ + .size_ = 8192, + .store_header_flag_ = true}, + .object_types_z_ = 16384, + .gc_trigger_v_{{4096, 4096}}, + .debug_flag_ = false, + }; + + DX1Collector gc(cfg); + auto alloc = with_facet::mkobj(&gc); + auto coll = with_facet::mkobj(&gc); + + bool ok = CollectorTypeRegistry::instance().install_types(coll); + REQUIRE(ok); + + obj bval = DBoolean::box(alloc, true); + auto test_expr = DConstant::make(alloc, bval); + + obj fval1 = DFloat::box(alloc, 1.0); + auto when_true_expr = DConstant::make(alloc, fval1); + + obj fval2 = DFloat::box(alloc, 2.0); + auto when_false_expr = DConstant::make(alloc, fval2); + + auto ifexpr = DIfElseExpr::make(alloc, test_expr, when_true_expr, when_false_expr); + REQUIRE(ifexpr.data() != nullptr); + REQUIRE(ifexpr.data()->extype() == xo::scm::exprtype::ifexpr); + } + + TEST_CASE("DIfElseExpr-valuetype", "[expression2][DIfElseExpr]") + { + REQUIRE(s_init.evidence()); + + CollectorConfig cfg{ + .name_ = "difelseexpr_valuetype_test", + .arena_config_ = ArenaConfig{ + .size_ = 8192, + .store_header_flag_ = true}, + .object_types_z_ = 16384, + .gc_trigger_v_{{4096, 4096}}, + .debug_flag_ = false, + }; + + DX1Collector gc(cfg); + auto alloc = with_facet::mkobj(&gc); + auto coll = with_facet::mkobj(&gc); + + bool ok = CollectorTypeRegistry::instance().install_types(coll); + REQUIRE(ok); + + obj bval = DBoolean::box(alloc, true); + auto test_expr = DConstant::make(alloc, bval); + + obj fval1 = DFloat::box(alloc, 1.0); + auto when_true_expr = DConstant::make(alloc, fval1); + + obj fval2 = DFloat::box(alloc, 2.0); + auto when_false_expr = DConstant::make(alloc, fval2); + + auto ifexpr = DIfElseExpr::make(alloc, test_expr, when_true_expr, when_false_expr); + REQUIRE(ifexpr.data() != nullptr); + + // valuetype may be null before type resolution + // just verify we can call it + ifexpr.data()->valuetype(); + } + + TEST_CASE("DIfElseExpr-pretty", "[expression2][DIfElseExpr][pp]") + { + scope log(XO_DEBUG(true)); + + REQUIRE(s_init.evidence()); + + CollectorConfig cfg{ + .name_ = "difelseexpr_pretty_test", + .arena_config_ = ArenaConfig{ + .size_ = 8192, + .store_header_flag_ = true}, + .object_types_z_ = 16384, + .gc_trigger_v_{{4096, 4096}}, + .debug_flag_ = false, + }; + + DX1Collector gc(cfg); + auto alloc = with_facet::mkobj(&gc); + auto coll = with_facet::mkobj(&gc); + + bool ok = CollectorTypeRegistry::instance().install_types(coll); + REQUIRE(ok); + + obj bval = DBoolean::box(alloc, true); + auto test_expr = DConstant::make(alloc, bval); + + obj fval1 = DFloat::box(alloc, 1.0); + auto when_true_expr = DConstant::make(alloc, fval1); + + obj fval2 = DFloat::box(alloc, 2.0); + auto when_false_expr = DConstant::make(alloc, fval2); + + auto ifexpr = DIfElseExpr::make(alloc, + test_expr, + when_true_expr, when_false_expr); + REQUIRE(ifexpr.data() != nullptr); + + std::stringstream ss; + ppconfig ppc; + ppstate_standalone pps(&ss, 0, &ppc); + + obj ifexpr_pr(ifexpr.data()); + pps.pretty(ifexpr_pr); + + std::string output = ss.str(); + + log && log(output); + + CHECK(output.find("DIfElseExpr") != std::string::npos); + } +} + +/* end DIfElseExpr.test.cpp */ diff --git a/xo-interpreter2/include/xo/interpreter2/VirtualSchematikaMachine.hpp b/xo-interpreter2/include/xo/interpreter2/VirtualSchematikaMachine.hpp index e8e58dbc..066b7ffd 100644 --- a/xo-interpreter2/include/xo/interpreter2/VirtualSchematikaMachine.hpp +++ b/xo-interpreter2/include/xo/interpreter2/VirtualSchematikaMachine.hpp @@ -63,6 +63,12 @@ namespace xo { **/ void _do_eval_apply_op(); + /** evaluate an if-else expression + * Require: + * - expression in @ref expr_ + **/ + void _do_eval_if_else_op(); + private: /* * Some registers are preserved by evaluation: diff --git a/xo-interpreter2/src/interpreter2/VirtualSchematikaMachine.cpp b/xo-interpreter2/src/interpreter2/VirtualSchematikaMachine.cpp index b2789c26..11a60c64 100644 --- a/xo-interpreter2/src/interpreter2/VirtualSchematikaMachine.cpp +++ b/xo-interpreter2/src/interpreter2/VirtualSchematikaMachine.cpp @@ -54,6 +54,9 @@ namespace xo { case exprtype::apply: _do_eval_apply_op(); break; + case exprtype::ifexpr: + _do_eval_if_else_op(); + break; } } @@ -87,6 +90,13 @@ namespace xo { // not implemented assert(false); } + + void + VirtualSchematikaMachine::_do_eval_if_else_op() + { + // not implemented + assert(false); + } } /*namespace scm*/ } /*namespace xo*/ diff --git a/xo-reader2/src/reader2/DProgressSsm.cpp b/xo-reader2/src/reader2/DProgressSsm.cpp index bd48e58c..76574c7b 100644 --- a/xo-reader2/src/reader2/DProgressSsm.cpp +++ b/xo-reader2/src/reader2/DProgressSsm.cpp @@ -1186,9 +1186,10 @@ namespace xo { case optype::op_multiply: { - auto pm_obj = with_facet::mkobj(&Primitives::s_mul_gco_gco_pm); - - auto fn_expr = DConstant::make(p_psm->expr_alloc(), pm_obj); + auto pm_obj = (with_facet::mkobj + (&Primitives::s_mul_gco_gco_pm)); + auto fn_expr = (DConstant::make + (p_psm->expr_alloc(), pm_obj)); /* note: * 1. don't assume we know lhs_ / rhs_ value types yet.