summaryrefslogtreecommitdiffstats
path: root/eval/src/vespa/eval/eval/operator_nodes.h
blob: 7759958be4b295a5c654cbca8c824d47ccae6a57 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#pragma once

#include "basic_nodes.h"
#include <vespa/vespalib/stllike/string.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <cmath>
#include <memory>
#include <map>

namespace vespalib {
namespace eval {

struct NodeVisitor;

namespace nodes {

/**
 * Common superclass for AST nodes describing infix operators. Each
 * operator has a left hand side expression and a right hand side
 * expression. The parser will use Operator instances to resolve
 * precedence.
 **/
class Operator : public Node {
public:
    enum Order { LEFT, RIGHT };

private:
    vespalib::string _op_str;
    int              _priority;
    Order            _order;
    Node_UP          _lhs;
    Node_UP          _rhs;
    bool             _is_const_double;

public:
    Operator(const vespalib::string &op_str_in, int priority_in, Order order_in);
    ~Operator();
    vespalib::string op_str() const { return _op_str; }
    int priority() const { return _priority; }
    Order order() const { return _order; }
    const Node &lhs() const { return *_lhs; }
    const Node &rhs() const { return *_rhs; }
    bool is_const_double() const override { return _is_const_double; }
    size_t num_children() const override { return (_lhs && _rhs) ? 2 : 0; }
    const Node &get_child(size_t idx) const override {
        assert(idx < 2);
        return (idx == 0) ? lhs() : rhs();
    }
    void detach_children(NodeHandler &handler) override {
        handler.handle(std::move(_lhs));
        handler.handle(std::move(_rhs));
    }

    bool do_before(const Operator &other) {
        if (priority() > other.priority()) {
            return true;
        }
        if (other.priority() > priority()) {
            return false;
        }
        assert(order() == other.order());
        return (order() == LEFT);
    }

    virtual void bind(Node_UP lhs_in, Node_UP rhs_in) {
        _lhs = std::move(lhs_in);
        _rhs = std::move(rhs_in);
        _is_const_double = (_lhs->is_const_double() && _rhs->is_const_double());
    }

    vespalib::string dump(DumpContext &ctx) const override {
        vespalib::string str;
        str += "(";
        str += _lhs->dump(ctx);
        str += op_str();
        str += _rhs->dump(ctx);
        str += ")";
        return str;
    }
};
typedef std::unique_ptr<Operator> Operator_UP;

//-----------------------------------------------------------------------------

/**
 * Repository for known operators. This is used by the parser to
 * create appropriate operator nodes.
 **/
class OperatorRepo {
private:
    static OperatorRepo _instance;
    typedef nodes::Operator_UP (*factory_type)();
    std::map<vespalib::string,factory_type> _map;
    size_t _max_size;
    template <typename T>
    void add(const T &op) {
        vespalib::string op_str = op.op_str();
        _max_size = std::max(_max_size, op_str.size());
        _map[op_str] = T::create;
    }
    OperatorRepo();
public:
    static const OperatorRepo &instance() { return _instance; }
    size_t max_size() const { return _max_size; }
    nodes::Operator_UP create(vespalib::string &tmp) const {
        for (; !tmp.empty(); tmp.resize(tmp.size() - 1)) {
            auto result = _map.find(tmp);
            if (result != _map.end()) {
                return result->second();
            }
        }
        return nodes::Operator_UP(nullptr);
    }
    std::vector<vespalib::string> get_names() const {
        std::vector<vespalib::string> ret;
        for (const auto &entry: _map) {
            ret.push_back(entry.first);
        }
        return ret;
    }
};

//-----------------------------------------------------------------------------

template <typename T>
struct OperatorHelper : Operator {
    using Helper = OperatorHelper<T>;
    OperatorHelper(const vespalib::string &op_str_in, int priority_in, Operator::Order order_in)
        : Operator(op_str_in, priority_in, order_in) {}
    void accept(NodeVisitor &visitor) const override;
    static Operator_UP create() { return Operator_UP(new T()); }
};

//-----------------------------------------------------------------------------

class Add : public OperatorHelper<Add> {
private:
    bool _is_forest;
public:
    Add() : Helper("+", 101, LEFT), _is_forest(false) {}
    bool is_forest() const override { return _is_forest; }
    bool check_forest() const {
        bool lhs_ok = (lhs().is_tree() || lhs().is_forest());
        bool rhs_ok = (rhs().is_tree() || rhs().is_forest());
        return (lhs_ok && rhs_ok);
    }
    void bind(Node_UP lhs_in, Node_UP rhs_in) override {
        OperatorHelper<Add>::bind(std::move(lhs_in), std::move(rhs_in));
        _is_forest = check_forest();
    }
};

//-----------------------------------------------------------------------------

struct Sub          : OperatorHelper<Sub>          { Sub()          : Helper("-", 101, LEFT)  {}};
struct Mul          : OperatorHelper<Mul>          { Mul()          : Helper("*", 102, LEFT)  {}};
struct Div          : OperatorHelper<Div>          { Div()          : Helper("/", 102, LEFT)  {}};
struct Mod          : OperatorHelper<Mod>          { Mod()          : Helper("%", 102, LEFT)  {}};
struct Pow          : OperatorHelper<Pow>          { Pow()          : Helper("^", 103, RIGHT) {}};
struct Equal        : OperatorHelper<Equal>        { Equal()        : Helper("==", 10, LEFT)  {}};
struct NotEqual     : OperatorHelper<NotEqual>     { NotEqual()     : Helper("!=", 10, LEFT)  {}};
struct Approx       : OperatorHelper<Approx>       { Approx()       : Helper("~=", 10, LEFT)  {}};
struct Less         : OperatorHelper<Less>         { Less()         : Helper("<",  10, LEFT)  {}};
struct LessEqual    : OperatorHelper<LessEqual>    { LessEqual()    : Helper("<=", 10, LEFT)  {}};
struct Greater      : OperatorHelper<Greater>      { Greater()      : Helper(">",  10, LEFT)  {}};
struct GreaterEqual : OperatorHelper<GreaterEqual> { GreaterEqual() : Helper(">=", 10, LEFT)  {}};
struct And          : OperatorHelper<And>          { And()          : Helper("&&",  2, LEFT)  {}};
struct Or           : OperatorHelper<Or>           { Or()           : Helper("||",  1, LEFT)  {}};

//-----------------------------------------------------------------------------

} // namespace vespalib::eval::nodes
} // namespace vespalib::eval
} // namespace vespalib