Skip to content

File expression.hpp

File List > backends > cxx > include > zmbt > model > expression.hpp

Go to the documentation of this file

#ifndef ZMBT_MODEL_EXPRESSION_V2_HPP_
#define ZMBT_MODEL_EXPRESSION_V2_HPP_

#include <ostream>

#include "zmbt/core.hpp"
#include "zmbt/reflect.hpp"
#include "signal_operator_handler.hpp"
#include "keyword.hpp"
#include "keyword_grammar.hpp"
#include "keyword_codegen_type.hpp"
#include "exceptions.hpp"


namespace zmbt {

class Expression
{
public:
    using V = boost::json::value;
    using Keyword = dsl::Keyword;

    struct EvalLog
    {
        mutable std::shared_ptr<boost::json::array> stack;

        EvalLog() = default;

        std::string str() const;

        void push(boost::json::value const& expr, boost::json::value const& x, boost::json::value const& result, std::uint64_t const depth) const;


        static void format(std::ostream& os, boost::json::array const& log, int const indent = 0);

        friend std::ostream& operator<<(std::ostream& os, EvalLog const& log);

        static EvalLog make();
    };

    struct EvalContext
    {
        SignalOperatorHandler op;
        EvalLog log;
        std::uint64_t const depth;

        EvalContext operator++(int) const;
    };

private:
    Keyword keyword_;
    boost::json::value underlying_;
    boost::json::value const* params_ptr_;
    boost::json::value const dummy_params_{};

    struct internal_tag{};
    Expression(internal_tag, Keyword const& keyword, boost::json::value&& underlying);

    struct json_ctor_params;
    Expression(json_ctor_params&&);

    void handle_binary_args(V const& x, V const*& lhs, V const*& rhs) const;

    boost::json::value eval_Const(boost::json::value const&, SignalOperatorHandler const&) const;
    boost::json::value eval_UnaryOp(boost::json::value const&, SignalOperatorHandler const&) const;
    boost::json::value eval_CodegenFn(boost::json::value const&, SignalOperatorHandler const&) const;
    boost::json::value eval_BinaryOp(boost::json::value const&, SignalOperatorHandler const&) const;
    boost::json::value eval_Special(boost::json::value const&, EvalContext const&) const;
public:

    static Expression literalAsEq(boost::json::value const& underlying);
    static Expression constAsEq(boost::json::value const& underlying);

    Expression(std::initializer_list<boost::json::value_ref> items);
    Expression(boost::json::value const& expr);
    Expression(Keyword const& keyword, boost::json::value const& params);
    explicit Expression(Keyword const& keyword);

    Expression();

    template <class T>
    Expression(T const& sample) : Expression(json_from(sample)) {}

    Expression(Expression const& o);
    Expression(Expression && o);
    Expression& operator=(Expression const& o);
    Expression& operator=(Expression && o);

    friend Expression operator|(Expression const& lhs, Expression const& rhs);

    friend Expression operator&(Expression const& lhs, Expression const& rhs);


    friend Expression operator<<(Expression const& expr, Expression const& x);


    friend Expression operator>>(Expression const& expr, Expression const& x);




    ~Expression() = default;

    boost::json::value const& underlying() const
    {
        return underlying_;
    }

    boost::json::value const& serialize() const
    {
        return underlying();
    }

    bool operator==(Expression const& o) const
    {
        return (keyword_ == o.keyword_) && (underlying_ == o.underlying_);
    }

    bool operator!=(Expression const& o) const
    {
        return !operator==(o);
    }

    Keyword keyword() const
    {
        return keyword_;
    }

    boost::json::value const& params() const
    {
        return has_params() ? *params_ptr_ : dummy_params_;
    }

    boost::json::value const& subexpr() const
    {
        return params();
    }

    bool has_params() const
    {
        return nullptr != params_ptr_;
    }

    bool is(Keyword const kwrd) const
    {
        return kwrd == keyword_;
    }

    bool is_literal() const
    {
        return is(Keyword::Literal);
    }

    bool is_noop() const
    {
        return is(Keyword::Noop);
    }

    bool is_const() const;

    operator boost::json::value() const
    {
        return underlying();
    }

    boost::json::value eval(boost::json::value const& x = nullptr, EvalContext const& ctx = {}) const;

    bool match(boost::json::value const& observed, SignalOperatorHandler const& op = {}) const;

};

template<class T>
struct reflect::custom_serialization<T, mp_if<is_base_of<Expression, T>, void>> {

    static boost::json::value
    json_from(T const& t)
    {
        return t.underlying();
    }

    static T
    dejsonize(boost::json::value const& v)
    {
        return static_cast<T>(Expression(v));
    }

};

}  // namespace zmbt

#endif