/** @file IfExpr.hpp * * Author: Roland Conybeare **/ #pragma once #include "Expression.hpp" //#include #include //#include namespace xo { namespace scm { /** @class IfExpr * @brief abstract syntax tree for a function definition * **/ class IfExpr : public Expression { public: using TypeDescr = xo::reflect::TypeDescr; public: /** create expression for conditional execution of * @p when_true or @p when_false, depending on result * of evaluating expression @p test **/ static rp make(const rp & test, const rp & when_true, const rp & when_false); /** downcast from Expression **/ static bp from(bp x) { return bp::from(x); } const rp & test() const { return test_; } const rp & when_true() const { return when_true_; } const rp & when_false() const { return when_false_; } // ----- Expression ----- 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); } #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 virtual void display(std::ostream & os) const override; virtual std::uint32_t pretty_print(const ppindentinfo & ppi) const override; protected: /** * @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(); protected: /** if: * (if x y z) * * executes x; if true execute y; otherwise execute z **/ rp test_; rp when_true_; rp when_false_; }; /*IfExpr*/ 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)) {} }; } /*namespace scm*/ } /*namespace xo*/ /** end IfExpr.hpp **/