diff options
Diffstat (limited to 'src/op.h')
-rw-r--r-- | src/op.h | 343 |
1 files changed, 343 insertions, 0 deletions
diff --git a/src/op.h b/src/op.h new file mode 100644 index 00000000..347eac1d --- /dev/null +++ b/src/op.h @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2003-2009, John Wiegley. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @addtogroup expr + */ + +/** + * @file op.h + * @author John Wiegley + * + * @ingroup expr + */ +#ifndef _OP_H +#define _OP_H + +#include "expr.h" + +namespace ledger { + +class expr_t::op_t : public noncopyable +{ + friend class expr_t; + friend class expr_t::parser_t; + +public: + typedef expr_t::ptr_op_t ptr_op_t; + +private: + mutable short refc; + ptr_op_t left_; + + variant<ptr_op_t, // used by all binary operators + value_t, // used by constant VALUE + string, // used by constant IDENT + expr_t::func_t // used by terminal FUNCTION + > data; + +public: + enum kind_t { + // Constants + VALUE, + IDENT, + + CONSTANTS, + + FUNCTION, + + TERMINALS, + + // Binary operators + O_NOT, + O_NEG, + + UNARY_OPERATORS, + + O_EQ, + O_LT, + O_LTE, + O_GT, + O_GTE, + + O_AND, + O_OR, + + O_ADD, + O_SUB, + O_MUL, + O_DIV, + + O_QUERY, + O_COLON, + + O_CONS, + O_SEQ, + + O_DEFINE, + O_LOOKUP, + O_CALL, + O_MATCH, + + BINARY_OPERATORS, + + OPERATORS, + + UNKNOWN, + + LAST + }; + + kind_t kind; + + explicit op_t() : refc(0), kind(UNKNOWN) { + TRACE_CTOR(op_t, ""); + } + explicit op_t(const kind_t _kind) : refc(0), kind(_kind) { + TRACE_CTOR(op_t, "const kind_t"); + } + ~op_t() { + TRACE_DTOR(op_t); + assert(refc == 0); + } + + bool is_value() const { + if (kind == VALUE) { + assert(data.type() == typeid(value_t)); + return true; + } + return false; + } + value_t& as_value_lval() { + assert(is_value()); + value_t& val(boost::get<value_t>(data)); + VERIFY(val.valid()); + return val; + } + const value_t& as_value() const { + return const_cast<op_t *>(this)->as_value_lval(); + } + void set_value(const value_t& val) { + VERIFY(val.valid()); + data = val; + } + + bool is_ident() const { + if (kind == IDENT) { + assert(data.type() == typeid(string)); + return true; + } + return false; + } + string& as_ident_lval() { + assert(is_ident()); + return boost::get<string>(data); + } + const string& as_ident() const { + return const_cast<op_t *>(this)->as_ident_lval(); + } + void set_ident(const string& val) { + data = val; + } + + bool is_function() const { + return kind == FUNCTION; + } + expr_t::func_t& as_function_lval() { + assert(kind == FUNCTION); + return boost::get<expr_t::func_t>(data); + } + const expr_t::func_t& as_function() const { + return const_cast<op_t *>(this)->as_function_lval(); + } + void set_function(const expr_t::func_t& val) { + data = val; + } + + ptr_op_t& left() { + assert(kind > TERMINALS || kind == IDENT); + return left_; + } + const ptr_op_t& left() const { + assert(kind > TERMINALS || kind == IDENT); + return left_; + } + void set_left(const ptr_op_t& expr) { + assert(kind > TERMINALS || kind == IDENT); + left_ = expr; + } + + ptr_op_t& as_op_lval() { + assert(kind > TERMINALS || kind == IDENT); + return boost::get<ptr_op_t>(data); + } + const ptr_op_t& as_op() const { + return const_cast<op_t *>(this)->as_op_lval(); + } + + ptr_op_t& right() { + assert(kind > TERMINALS); + return as_op_lval(); + } + const ptr_op_t& right() const { + assert(kind > TERMINALS); + return as_op(); + } + void set_right(const ptr_op_t& expr) { + assert(kind > TERMINALS); + data = expr; + } + bool has_right() const { + if (kind < TERMINALS) + return false; + return as_op(); + } + +private: + void acquire() const { + DEBUG("op.memory", + "Acquiring " << this << ", refc now " << refc + 1); + assert(refc >= 0); + refc++; + } + void release() const { + DEBUG("op.memory", + "Releasing " << this << ", refc now " << refc - 1); + assert(refc > 0); + if (--refc == 0) + checked_delete(this); + } + + friend inline void intrusive_ptr_add_ref(const op_t * op) { + op->acquire(); + } + friend inline void intrusive_ptr_release(const op_t * op) { + op->release(); + } + + ptr_op_t copy(ptr_op_t _left = NULL, ptr_op_t _right = NULL) const { + ptr_op_t node(new_node(kind, _left, _right)); + if (kind < TERMINALS) + node->data = data; + return node; + } + +public: + static ptr_op_t new_node(kind_t _kind, ptr_op_t _left = NULL, + ptr_op_t _right = NULL); + + ptr_op_t compile(scope_t& scope, const int depth = 0); + value_t calc(scope_t& scope, ptr_op_t * locus = NULL, + const int depth = 0); + + struct context_t + { + ptr_op_t expr_op; + ptr_op_t op_to_find; + ostream_pos_type * start_pos; + ostream_pos_type * end_pos; + bool relaxed; + + context_t(const ptr_op_t& _expr_op = NULL, + const ptr_op_t& _op_to_find = NULL, + ostream_pos_type * const _start_pos = NULL, + ostream_pos_type * const _end_pos = NULL, + const bool _relaxed = true) + : expr_op(_expr_op), op_to_find(_op_to_find), + start_pos(_start_pos), end_pos(_end_pos), + relaxed(_relaxed) {} + }; + + bool print(std::ostream& out, const context_t& context = context_t()) const; + void dump(std::ostream& out, const int depth) const; + + static ptr_op_t wrap_value(const value_t& val); + static ptr_op_t wrap_functor(const expr_t::func_t& fobj); + +#if defined(HAVE_BOOST_SERIALIZATION) +private: + /** Serialization. */ + + friend class boost::serialization::access; + + template<class Archive> + void serialize(Archive& ar, const unsigned int /* version */) { + ar & refc; + ar & kind; + if (Archive::is_loading::value || ! left_ || left_->kind != FUNCTION) { + ar & left_; + } else { + ptr_op_t temp_op; + ar & temp_op; + } + if (Archive::is_loading::value || kind == VALUE || kind == IDENT || + (kind > UNARY_OPERATORS && + (! has_right() || ! right()->is_function()))) { + ar & data; + } else { + variant<ptr_op_t, value_t, string, expr_t::func_t> temp_data; + ar & temp_data; + } + } +#endif // HAVE_BOOST_SERIALIZATION +}; + +inline expr_t::ptr_op_t +expr_t::op_t::new_node(kind_t _kind, ptr_op_t _left, ptr_op_t _right) +{ + ptr_op_t node(new op_t(_kind)); + if (_left) node->set_left(_left); + if (_right) node->set_right(_right); + return node; +} + +inline expr_t::ptr_op_t expr_t::op_t::wrap_value(const value_t& val) { + ptr_op_t temp(new op_t(op_t::VALUE)); + temp->set_value(val); + return temp; +} + +inline expr_t::ptr_op_t +expr_t::op_t::wrap_functor(const expr_t::func_t& fobj) { + ptr_op_t temp(new op_t(op_t::FUNCTION)); + temp->set_function(fobj); + return temp; +} + +#define MAKE_FUNCTOR(x) expr_t::op_t::wrap_functor(bind(&x, this, _1)) +#define WRAP_FUNCTOR(x) expr_t::op_t::wrap_functor(x) + +string op_context(const expr_t::ptr_op_t op, + const expr_t::ptr_op_t locus = NULL); + +} // namespace ledger + +#endif // _OP_H |