/** @file Apply.hpp * * Author: Roland Conybeare **/ #pragma once #include "Expression.hpp" //#include namespace xo { namespace scm { /** @class Apply * @brief syntax for a function call. * * In general we don't know function to be invoked * until runtime, depending on the nature of Expression. **/ class Apply : public Expression { public: using TypeDescr = xo::reflect::TypeDescr; public: /** create new apply-expression instance **/ static rp make(const rp & fn, const std::vector> & argv); /** create apply-expression to compare two 64-bit integers **/ static rp make_cmp_eq_i64(const rp & lhs, const rp & rhs); /** create apply-expression to compare two 64-bit integers **/ static rp make_cmp_ne_i64(const rp & lhs, const rp & rhs); /** create apply-expression for less-than comparison of two 64-bit integers **/ static rp make_cmp_lt_i64(const rp & lhs, const rp & rhs); /** create apply-expression for less-than-or-equal comparison of two 64-bit integers **/ static rp make_cmp_le_i64(const rp & lhs, const rp & rhs); /** create apply-expression for greater-than comparison of two 64-bit integers **/ static rp make_cmp_gt_i64(const rp & lhs, const rp & rhs); /** create apply-expression for greater-than-or-equal comparison of two 64-bit integers **/ static rp make_cmp_ge_i64(const rp & lhs, const rp & rhs); /** create apply-expression to add two 64-bit integers **/ static rp make_add2_i64(const rp & lhs, const rp & rhs); /** create apply-expression to subtract two 64-bit integers **/ static rp make_sub2_i64(const rp & lhs, const rp & rhs); /** create apply-expression to multiply two 64-bit integers **/ static rp make_mul2_i64(const rp & lhs, const rp & rhs); /** create apply-expression to divide two 64-bit integers **/ static rp make_div2_i64(const rp & lhs, const rp & rhs); /** create apply-expression to add two 64-bit floating-point numbers **/ static rp make_add2_f64(const rp & lhs, const rp & rhs); /** create apply-expression to subtract two 64-bit floating-point numbers **/ static rp make_sub2_f64(const rp & lhs, const rp & rhs); /** create apply-expression to multiply two 64-bit floating-point numbers **/ static rp make_mul2_f64(const rp & lhs, const rp & rhs); /** create apply-expression to divide two 64-bit floating-point numbers **/ static rp make_div2_f64(const rp & lhs, const rp & rhs); /** downcast from Expression **/ static bp from(bp x) { return bp::from(x); } const rp & fn() const { return fn_; } const std::vector> & argv() const { return argv_; } std::size_t n_arg() const { return argv_.size(); } const rp & lookup_arg(size_t i) const { return argv_.at(i); } virtual std::set get_free_variables() const override { std::set retval = fn_->get_free_variables(); for (const auto & arg : argv_) { std::set arg_free_set = arg->get_free_variables(); for (const auto & name : arg_free_set) retval.insert(name); } return retval; } virtual std::size_t visit_preorder(VisitFn visitor_fn) override { std::size_t n = 1; visitor_fn(this); n += fn_->visit_preorder(visitor_fn); for (const auto & arg : argv_) n += arg->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 += fn_->visit_layer(visitor_fn); for (const auto & arg : argv_) n += arg->visit_layer(visitor_fn); return n; } virtual rp xform_layer(TransformFn xform_fn) override { this->fn_ = fn_->xform_layer(xform_fn); for (auto & arg : argv_) arg = arg->xform_layer(xform_fn); return xform_fn(this); } 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; protected: Apply(TypeDescr apply_valuetype, const rp & fn, const std::vector> & argv) : Expression(exprtype::apply, apply_valuetype), fn_{fn}, argv_(argv) {} protected: /** function to invoke **/ rp fn_; /** argument expressions, in l-to-r order **/ std::vector> argv_; }; /*Apply*/ #ifdef NOT_USING namespace detail { /** Use: ** std::vector> **/ template struct apply_push_args; template <> struct apply_push_args<> { static void push_all(std::vector> * /*p_argv*/) {} }; template struct apply_push_args { static void push_all(std::vector> * p_argv, const ref::rp & x, Rest... rest) { p_argv->push_back(x); apply_push_args::push_all(p_argv, rest...); }; }; } #endif /* reminder: initializer-lists are compile-time only */ inline rp make_apply(const rp & fn, const std::initializer_list> args) { std::vector> argv(args); return Apply::make(fn, argv); } /*make_apply*/ /** @class ApplyAccess * @brief Apply with writeable members * * Convenient when scaffolding a parser, * e.g. see xo-parser **/ class ApplyAccess : public Apply { public: static rp make_empty(); /** assign function being called to @p fn **/ void assign_fn(const rp& fn); /** assign expression for argument i, counting from 1. * can use @p i = 0 as alternative to @ ref assign_fn **/ void assign_arg(size_t i, const rp& arg); // inherited from GeneralizedExpression.. // void assign_valuetype(TypeDescr apply_valuetype); private: ApplyAccess(TypeDescr apply_valuetype, const rp& fn, const std::vector>& argv) : Apply(apply_valuetype, fn, argv) {} }; } /*namespace scm*/ } /*namespace xo*/ /** end Apply.hpp **/