Skip to content

File expression.hpp

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

Go to the documentation of this file

#ifndef ZMBT_EXPR_EXPRESSION_V2_HPP_
#define ZMBT_EXPR_EXPRESSION_V2_HPP_

#include <ostream>

#include "zmbt/core.hpp"
#include "zmbt/logging.hpp"
#include "zmbt/reflect.hpp"
#include "operator.hpp"
#include "keyword.hpp"
#include "keyword_grammar.hpp"
#include "encoding.hpp"
#include "eval_context.hpp"


namespace zmbt {
namespace lang {

class Expression;

class ExpressionView
{
public:

    using V = boost::json::value;
    using Keyword = lang::Keyword;

    // CTORS

    ExpressionView();

    ExpressionView(ExpressionView const&) = default;
    ExpressionView(ExpressionView&&) = default;
    ExpressionView& operator=(ExpressionView const&) = default;
    ExpressionView& operator=(ExpressionView&&) = default;

    explicit ExpressionView(EncodingView v)
        : encoding_view_{v}
    {
    }

    explicit ExpressionView(Encoding enc)
        : encoding_view_{EncodingView(enc)}
    {
    }

    virtual ~ExpressionView() = default;

    EncodingView encoding_view() const
    {
        return encoding_view_;
    }

    boost::json::value to_json() const;


    // OPERATORS


    bool operator==(ExpressionView const& o) const
    {
        return (this == &o) || (encoding_view() == o.encoding_view());
    }

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

    // ENCODING OBSERVERS



    bool has_subexpr() const
    {
        return encoding_view().size() > 1;
    }

    std::list<ExpressionView> subexpressions_list() const;

    std::list<ExpressionView> tuple_parameters() const;


    // DATA OBSERVERS

    boost::json::value const& data() const;

    boost::json::string const& as_string() const
    {
        return data().as_string();
    }

    boost::json::array const& as_array() const
    {
        return data().as_array();
    }

    boost::json::object const& as_object() const
    {
        return data().as_object();
    }

    bool as_bool() const
    {
        return data().as_bool();
    }

    boost::json::string const* if_string() const
    {
        return data().if_string();
    }

    boost::json::array const* if_array() const
    {
        return data().if_array();
    }

    boost::json::object const* if_object() const
    {
        return data().if_object();
    }

    bool const* if_bool() const
    {
        return data().if_bool();
    }

    bool is_null() const
    {
        return data().is_null();
    }


    std::string serialize() const
    {
        return boost::json::serialize(to_json());
    }

    boost::json::string_view keyword_to_str() const;

    // KEYWORD OBSERVERS


    Keyword keyword() const
    {
        return encoding_view().head();
    }

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

    bool is_compose() const
    {
        return is(Keyword::Pipe);
    }

    bool is_fork() const
    {
        return is(Keyword::Fork);
    }

    bool is_tuple() const
    {
        return is(Keyword::Tuple);
    }

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

    bool is_preproc() const
    {
        return is(Keyword::PreProc);
    }

    bool is_link() const
    {
        return is(Keyword::Link);
    }

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

    bool is_error() const
    {
        return is(Keyword::Err);
    }

    bool is_complete_flip() const
    {
        return is(Keyword::Flip) && encoding_view().size() > 1;
    }


    // ATTR-BASED OBSERVERS

    bool is_const() const;

    bool is_boolean() const;

    bool is_valid_link() const
    {
        auto const child = encoding_view().child(0);
        return is(Keyword::Fn) && (child.head() == Keyword::Tuple) && (child.arity() == 2);
    }

    bool is_infix_pipe() const
    {
        return is_compose() && (encoding_view().arity() > 1);
    }

    bool is_infix_tuple() const
    {
        return is_tuple() && (encoding_view().arity() > 1);
    }

    bool is_infix_fork() const
    {
        return is_fork() && encoding_view().arity() == 2;
    }

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

    // Boost.Spirit Karma generator

    std::string prettify() const;
    std::ostream& prettify_to(std::ostream& os) const;

    template <std::size_t N>
    void prettify_to(char (&buff)[N]) const
    {
        return prettify_to(buff, N);
    }

    void prettify_to(char* buff, std::size_t n) const;

    friend std::ostream& operator<<(std::ostream& os, ExpressionView const& expr);
    friend zmbt::Logger& operator<<(zmbt::Logger& logger, ExpressionView const& expr);



    // PREPROCESSING

    std::list<std::pair<std::string, std::string>> preprocessing_parameters() const;


    // EVALUATORS

    Expression eval_e(ExpressionView const& x, EvalContext ctx) const;


    bool eval_as_predicate(ExpressionView const& x, Expression& err_sts, EvalContext ctx) const;

    bool eval_as_predicate(boost::json::value const& x, Expression& err_sts, EvalContext ctx) const;

    Expression eval_maybe_predicate(ExpressionView const& x, EvalContext ctx) const;

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

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

    friend V operator*(ExpressionView expr, ExpressionView const& x);

    friend V operator*(ExpressionView expr);

  protected:
    EncodingView encoding_view_;
};


class Expression : public ExpressionView
{
    static Expression unfold_left_assoc(Keyword const keyword, Expression&& lhs, Expression&& rhs);
    template <class T>
    static Encoding encodeNested(Keyword const& keyword, std::move_iterator<T> begin, std::move_iterator<T> const end);

  public:
    // STATIC FUNCS

    // using ExpressionView::operator==;
    // using ExpressionView::operator!=;

    bool operator==(Expression v) const
    {
        return ExpressionView::operator==(v);
    }

    bool operator!=(Expression v) const
    {
        return ExpressionView::operator!=(v);
    }


    // Terminal expression
    static Encoding encodeLiteral(boost::json::value const& params);
    // Terminal expression
    static Encoding encodePreProc(boost::json::value const& params);

    // Non-terminal expression
    static Encoding encodeNested(Keyword const& keyword, std::initializer_list<Expression> subexpressions);
    static Encoding encodeNested(Keyword const& keyword, std::vector<Expression>&& subexpressions);

    static bool to_predicate_if_const(Expression& e);

    // CTORS

    Expression();

    explicit Expression(Encoding && encoding);
    explicit Expression(Encoding const& encoding);

    // Deserialize JSON
    Expression(boost::json::value const& expr);
    Expression(boost::json::value && expr);

    // construct Literal from JSON init list
    Expression(std::initializer_list<boost::json::value_ref> items);

    template <class T>
    Expression(T sample) : Expression(json_from(std::move(sample))) {}

    // construct from keyword
    explicit Expression(Keyword const& keyword);
    explicit Expression(ExpressionView const& view);

    Expression(Expression const& other);
    Expression(Expression&& other);
    Expression& operator=(Expression const& other);
    Expression& operator=(Expression&& other);
    ~Expression() = default;

    Encoding encoding() const { return encoding_; }

    // SUGAR SYNTAX OPERATORS

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

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

    friend Expression operator+(Expression lhs, Expression rhs);

    friend Expression operator<<(Expression link, Expression expr);

    friend Expression operator~(Expression expr);

  private:
    Encoding encoding_;
};


ZMBT_INJECT_SERIALIZATION
}  // namespace lang

template<>
struct reflect::custom_serialization<lang::ExpressionView> {

    static boost::json::value
    json_from(lang::ExpressionView const& t)
    {
        return t.to_json();
    }
};

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

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

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

}  // namespace zmbt


#endif