diff options
Diffstat (limited to 'valexpr.h')
-rw-r--r-- | valexpr.h | 979 |
1 files changed, 718 insertions, 261 deletions
@@ -1,46 +1,373 @@ +/* + * Copyright (c) 2003-2008, 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. + */ + #ifndef _VALEXPR_H #define _VALEXPR_H #include "value.h" -#include "error.h" +#include "utils.h" #include "mask.h" -#include <memory> - namespace ledger { class entry_t; class transaction_t; class account_t; +namespace expr { + +DECLARE_EXCEPTION(error, compile_error); +DECLARE_EXCEPTION(error, calc_error); + +#if 0 +struct context_t +{ + const entry_t * entry() { + return NULL; + } + const transaction_t * xact() { + return NULL; + } + const account_t * account() { + return NULL; + } +}; + +struct entry_context_t : public context_t +{ + const entry_t * entry_; + + const entry_t * entry() { + return entry_; + } +}; + +struct xact_context_t : public context_t +{ + const transaction_t * xact_; + + const entry_t * entry() { + return xact_->entry; + } + const transaction_t * xact() { + return xact_; + } + const account_t * account() { + return xact_->account; + } +}; + +struct account_context_t : public context_t +{ + const account_t * account_; + + const account_t * account() { + return account_; + } +}; +#endif + struct details_t { - const entry_t * entry; + const entry_t * entry; const transaction_t * xact; const account_t * account; - details_t() : entry(NULL), xact(NULL), account(NULL) {} + details_t() : entry(NULL), xact(NULL), account(NULL) { + TRACE_CTOR(details_t, ""); + } + details_t(const details_t& other) + : entry(other.entry), + xact(other.xact), + account(other.account) { + TRACE_CTOR(details_t, "copy"); + } details_t(const entry_t& _entry) : entry(&_entry), xact(NULL), account(NULL) { - DEBUG_PRINT("ledger.memory.ctors", "ctor details_t"); + TRACE_CTOR(details_t, "const entry_t&"); } details_t(const transaction_t& _xact); details_t(const account_t& _account) : entry(NULL), xact(NULL), account(&_account) { - DEBUG_PRINT("ledger.memory.ctors", "ctor details_t"); + TRACE_CTOR(details_t, "const account_t&"); } -#ifdef DEBUG_ENABLED - ~details_t() { - DEBUG_PRINT("ledger.memory.dtors", "dtor details_t"); + ~details_t() throw() { + TRACE_DTOR(details_t); } -#endif }; -struct value_expr_t +struct op_t; +typedef intrusive_ptr<op_t> ptr_op_t; + +class call_scope_t; + +typedef function<value_t (call_scope_t&)> function_t; + +#define MAKE_FUNCTOR(x) expr::op_t::wrap_functor(bind(&x, this, _1)) +#define WRAP_FUNCTOR(x) expr::op_t::wrap_functor(x) + +class scope_t : public noncopyable +{ + scope_t(); + +public: + enum type_t { + CHILD_SCOPE, + SYMBOL_SCOPE, + CALL_SCOPE, + CONTEXT_SCOPE + } type_; + + explicit scope_t(type_t _type) : type_(_type) { + TRACE_CTOR(scope_t, "type_t"); + } + virtual ~scope_t() { + TRACE_DTOR(scope_t); + } + + const type_t type() const { + return type_; + } + + virtual void define(const string& name, ptr_op_t def) = 0; + void define(const string& name, const value_t& val); + virtual ptr_op_t lookup(const string& name) = 0; + value_t resolve(const string& name); + + virtual optional<scope_t&> find_scope(const type_t _type, + bool skip_this = false) = 0; + virtual optional<scope_t&> find_first_scope(const type_t _type1, + const type_t _type2, + bool skip_this = false) = 0; + + template <typename T> + T& find_scope(bool skip_this = false) { + assert(false); + } + template <typename T> + optional<T&> maybe_find_scope(bool skip_this = false) { + assert(false); + } +}; + +class child_scope_t : public scope_t +{ + scope_t * parent; + + child_scope_t(); + +public: + explicit child_scope_t(type_t _type = CHILD_SCOPE) + : scope_t(_type), parent(NULL) { + TRACE_CTOR(child_scope_t, "type_t"); + } + explicit child_scope_t(scope_t& _parent, type_t _type = CHILD_SCOPE) + : scope_t(_type), parent(&_parent) { + TRACE_CTOR(child_scope_t, "scope_t&, type_t"); + } + virtual ~child_scope_t() { + TRACE_DTOR(child_scope_t); + } +public: + virtual void define(const string& name, ptr_op_t def) { + if (parent) + parent->define(name, def); + } + virtual ptr_op_t lookup(const string& name) { + if (parent) + return parent->lookup(name); + return ptr_op_t(); + } + + virtual optional<scope_t&> find_scope(type_t _type, + bool skip_this = false) { + for (scope_t * ptr = (skip_this ? parent : this); ptr; ) { + if (ptr->type() == _type) + return *ptr; + + ptr = polymorphic_downcast<child_scope_t *>(ptr)->parent; + } + return none; + } + + virtual optional<scope_t&> find_first_scope(const type_t _type1, + const type_t _type2, + bool skip_this = false) { + for (scope_t * ptr = (skip_this ? parent : this); ptr; ) { + if (ptr->type() == _type1 || ptr->type() == _type2) + return *ptr; + + ptr = polymorphic_downcast<child_scope_t *>(ptr)->parent; + } + return none; + } +}; + +class symbol_scope_t : public child_scope_t +{ + typedef std::map<const string, ptr_op_t> symbol_map; + symbol_map symbols; + +public: + explicit symbol_scope_t() + : child_scope_t(SYMBOL_SCOPE) { + TRACE_CTOR(symbol_scope_t, ""); + } + explicit symbol_scope_t(scope_t& _parent) + : child_scope_t(_parent, SYMBOL_SCOPE) { + TRACE_CTOR(symbol_scope_t, "scope_t&"); + } + virtual ~symbol_scope_t() { + TRACE_DTOR(symbol_scope_t); + } + + virtual void define(const string& name, ptr_op_t def); + void define(const string& name, const value_t& val) { + scope_t::define(name, val); + } + virtual ptr_op_t lookup(const string& name); +}; + +class call_scope_t : public child_scope_t { + value_t args; + + call_scope_t(); + +public: + explicit call_scope_t(scope_t& _parent) + : child_scope_t(_parent, CALL_SCOPE) { + TRACE_CTOR(call_scope_t, "scope_t&"); + } + virtual ~call_scope_t() { + TRACE_DTOR(call_scope_t); + } + + void set_args(const value_t& _args) { + args = _args; + } + + value_t& value() { + return args; + } + + value_t& operator[](const unsigned int index) { + // jww (2008-07-21): exception here if it's out of bounds + return args[index]; + } + const value_t& operator[](const unsigned int index) const { + // jww (2008-07-21): exception here if it's out of bounds + return args[index]; + } + + void push_back(const value_t& val) { + args.push_back(val); + } + void pop_back() { + args.pop_back(); + } + + const std::size_t size() const { + return args.size(); + } +}; + +template <typename T> +class var_t : public noncopyable +{ + T * value; + + var_t(); + +public: + // jww (2008-07-21): Give a good exception here if we can't find "name" + var_t(scope_t& scope, const string& name) + : value(scope.resolve(name).template as_pointer<T>()) { + TRACE_CTOR(var_t, "scope_t&, const string&"); + } + var_t(call_scope_t& scope, const unsigned int idx) + : value(scope[idx].template as_pointer<T>()) { + TRACE_CTOR(var_t, "call_scope_t&, const unsigned int"); + } + ~var_t() throw() { + TRACE_DTOR(var_t); + } + + T& operator *() { return *value; } + T * operator->() { return value; } +}; + +#if 0 +class context_scope_t : public child_scope_t +{ +public: + value_t current_element; + std::size_t element_index; + std::size_t sequence_size; + + explicit context_scope_t(scope_t& _parent, + const value_t& _element = NULL_VALUE, + const std::size_t _element_index = 0, + const std::size_t _sequence_size = 0) + : child_scope_t(_parent, CONTEXT_SCOPE), current_element(_element), + element_index(_element_index), sequence_size(_sequence_size) + { + TRACE_CTOR(expr::context_scope_t, "scope_t&, const value_t&, ..."); + } + virtual ~context_scope_t() { + TRACE_DTOR(expr::context_scope_t); + } + + const std::size_t index() const { + return element_index; + } + const std::size_t size() const { + return sequence_size; + } + + value_t& value() { + return current_element; + } +}; +#endif + +class op_t : public noncopyable +{ + op_t(); + +public: enum kind_t { // Constants - CONSTANT, + VALUE, + MASK, ARG_INDEX, CONSTANTS, @@ -70,6 +397,8 @@ struct value_expr_t TOTAL_EXPR, // Functions + FUNCTION, + F_NOW, F_ARITH_MEAN, F_QUANTITY, @@ -84,12 +413,15 @@ struct value_expr_t F_YEAR, F_MONTH, F_DAY, + + BEGIN_MASKS, F_CODE_MASK, F_PAYEE_MASK, F_NOTE_MASK, F_ACCOUNT_MASK, F_SHORT_ACCOUNT_MASK, F_COMMODITY_MASK, + END_MASKS, TERMINALS, @@ -113,7 +445,7 @@ struct value_expr_t O_OR, O_QUES, O_COL, - O_COM, + O_COMMA, O_DEF, O_REF, O_ARG, @@ -121,210 +453,297 @@ struct value_expr_t LAST }; - kind_t kind; - mutable short refc; - value_expr_t * left; + kind_t kind; + mutable short refc; + ptr_op_t left_; - union { - value_t * value; - mask_t * mask; - unsigned int arg_index; // used by ARG_INDEX and O_ARG - value_expr_t * right; - }; + variant<unsigned int, // used by ARG_INDEX and O_ARG + value_t, // used by constant VALUE + mask_t, // used by constant MASK + function_t, // used by terminal FUNCTION +#if 0 + node_t::nameid_t, // used by NODE_ID and ATTR_ID +#endif + ptr_op_t> // used by all binary operators + data; - value_expr_t(const kind_t _kind) - : kind(_kind), refc(0), left(NULL), right(NULL) { - DEBUG_PRINT("ledger.memory.ctors", "ctor value_expr_t " << this); + explicit op_t(const kind_t _kind) : kind(_kind), refc(0){ + TRACE_CTOR(op_t, "const kind_t"); + } + ~op_t() { + TRACE_DTOR(op_t); + assert(refc == 0); } - ~value_expr_t(); - void release() const { - DEBUG_PRINT("ledger.valexpr.memory", - "Releasing " << this << ", refc now " << refc - 1); - assert(refc > 0); - if (--refc == 0) - delete this; + bool is_long() const { + return data.type() == typeid(unsigned int); + } + unsigned int& as_long_lval() { + assert(kind == ARG_INDEX || kind == O_ARG); + return boost::get<unsigned int>(data); + } + const unsigned int& as_long() const { + return const_cast<op_t *>(this)->as_long_lval(); + } + void set_long(unsigned int val) { + data = val; + } + + 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)); + assert(val.valid()); + return val; } - value_expr_t * acquire() { - DEBUG_PRINT("ledger.valexpr.memory", - "Acquiring " << this << ", refc now " << refc + 1); + const value_t& as_value() const { + return const_cast<op_t *>(this)->as_value_lval(); + } + void set_value(const value_t& val) { + assert(val.valid()); + data = val; + } + + bool is_string() const { + if (kind == VALUE) { + assert(data.type() == typeid(value_t)); + return boost::get<value_t>(data).is_string(); + } + return false; + } + string& as_string_lval() { + assert(is_string()); + return boost::get<value_t>(data).as_string_lval(); + } + const string& as_string() const { + return const_cast<op_t *>(this)->as_string_lval(); + } + void set_string(const string& val) { + data = value_t(val); + } + + bool is_mask() const { + if (kind > BEGIN_MASKS && kind < END_MASKS) { + assert(data.type() == typeid(mask_t)); + return true; + } + return false; + } + mask_t& as_mask_lval() { + assert(is_mask()); + return boost::get<mask_t>(data); + } + const mask_t& as_mask() const { + return const_cast<op_t *>(this)->as_mask_lval(); + } + void set_mask(const mask_t& val) { + data = val; + } + void set_mask(const string& expr) { + data = mask_t(expr); + } + + bool is_function() const { + return kind == FUNCTION; + } + function_t& as_function_lval() { + assert(kind == FUNCTION); + return boost::get<function_t>(data); + } + const function_t& as_function() const { + return const_cast<op_t *>(this)->as_function_lval(); + } + void set_function(const function_t& val) { + data = val; + } + +#if 0 + bool is_name() const { + return data.type() == typeid(node_t::nameid_t); + } + node_t::nameid_t& as_name_lval() { + assert(kind == NODE_ID || kind == ATTR_ID); + return boost::get<node_t::nameid_t>(data); + } + const node_t::nameid_t& as_name() const { + return const_cast<op_t *>(this)->as_name_lval(); + } + void set_name(const node_t::nameid_t& val) { + data = val; + } +#endif + + ptr_op_t& as_op_lval() { + assert(kind > TERMINALS); + return boost::get<ptr_op_t>(data); + } + const ptr_op_t& as_op() const { + return const_cast<op_t *>(this)->as_op_lval(); + } + + void acquire() const { + DEBUG("ledger.xpath.memory", + "Acquiring " << this << ", refc now " << refc + 1); assert(refc >= 0); refc++; - return this; } - const value_expr_t * acquire() const { - DEBUG_PRINT("ledger.valexpr.memory", - "Acquiring " << this << ", refc now " << refc + 1); - refc++; - return this; + void release() const { + DEBUG("ledger.xpath.memory", + "Releasing " << this << ", refc now " << refc - 1); + assert(refc > 0); + if (--refc == 0) + checked_delete(this); } - void set_left(value_expr_t * expr) { + ptr_op_t& left() { + return left_; + } + const ptr_op_t& left() const { + assert(kind > TERMINALS); + return left_; + } + void set_left(const ptr_op_t& expr) { assert(kind > TERMINALS); - if (left) - left->release(); - left = expr ? expr->acquire() : NULL; + left_ = expr; } - void set_right(value_expr_t * expr) { + 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); - if (right) - right->release(); - right = expr ? expr->acquire() : NULL; + data = expr; + } + + static ptr_op_t new_node(kind_t _kind, ptr_op_t _left = NULL, + ptr_op_t _right = NULL); + ptr_op_t copy(ptr_op_t _left = NULL, ptr_op_t _right = NULL) const { + return new_node(kind, _left, _right); } + static ptr_op_t wrap_value(const value_t& val); + static ptr_op_t wrap_functor(const function_t& fobj); + + ptr_op_t compile(scope_t& scope); + value_t current_value(scope_t& scope); +#if 0 + node_t& current_xml_node(scope_t& scope); +#endif + value_t calc(scope_t& scope); + void compute(value_t& result, const details_t& details = details_t(), - value_expr_t * context = NULL) const; + ptr_op_t context = NULL) const; value_t compute(const details_t& details = details_t(), - value_expr_t * context = NULL) const { + ptr_op_t context = NULL) const { value_t temp; compute(temp, details, context); return temp; } - private: - value_expr_t(const value_expr_t&) { - DEBUG_PRINT("ledger.memory.ctors", "ctor value_expr_t (copy) " << this); + struct print_context_t + { + scope_t& scope; + const bool relaxed; + const ptr_op_t& op_to_find; + unsigned long * start_pos; + unsigned long * end_pos; + + print_context_t(scope_t& _scope, + const bool _relaxed = false, + const ptr_op_t& _op_to_find = ptr_op_t(), + unsigned long * _start_pos = NULL, + unsigned long * _end_pos = NULL) + : scope(_scope), relaxed(_relaxed), op_to_find(_op_to_find), + start_pos(_start_pos), end_pos(_end_pos) {} + }; + + bool print(std::ostream& out, print_context_t& context) const; + void dump(std::ostream& out, const int depth) const; + + friend inline void intrusive_ptr_add_ref(op_t * op) { + op->acquire(); + } + friend inline void intrusive_ptr_release(op_t * op) { + op->release(); } }; -class valexpr_context : public error_context { - public: - const ledger::value_expr_t * expr; - const ledger::value_expr_t * error_node; +class op_predicate : public noncopyable +{ + ptr_op_t op; - valexpr_context(const ledger::value_expr_t * _expr, - const std::string& desc = "") throw(); - virtual ~valexpr_context() throw(); + op_predicate(); + +public: + explicit op_predicate(ptr_op_t _op) : op(_op) { + TRACE_CTOR(op_predicate, "ptr_op_t"); + } + ~op_predicate() throw() { + TRACE_DTOR(op_predicate); + } + bool operator()(scope_t& scope) { + return op->calc(scope).to_boolean(); + } +}; + +class valexpr_context : public error_context +{ +public: + ptr_op_t expr; + ptr_op_t error_node; + + valexpr_context(const ptr_op_t& _expr, + const string& desc = "") throw() + : error_context(desc), expr(_expr), error_node(_expr) {} + virtual ~valexpr_context() throw() {} virtual void describe(std::ostream& out) const throw(); }; -class compute_error : public error { - public: - compute_error(const std::string& reason, error_context * ctxt = NULL) throw() +class compute_error : public error +{ +public: + compute_error(const string& reason, error_context * ctxt = NULL) throw() : error(reason, ctxt) {} virtual ~compute_error() throw() {} }; -class value_expr_error : public error { - public: - value_expr_error(const std::string& reason, +class value_expr_error : public error +{ +public: + value_expr_error(const string& reason, error_context * ctxt = NULL) throw() : error(reason, ctxt) {} virtual ~value_expr_error() throw() {} }; -struct scope_t -{ - scope_t * parent; - - typedef std::map<const std::string, value_expr_t *> symbol_map; - typedef std::pair<const std::string, value_expr_t *> symbol_pair; - - symbol_map symbols; - - scope_t(scope_t * _parent = NULL) : parent(_parent) { - DEBUG_PRINT("ledger.memory.ctors", "ctor scope_t"); - } - ~scope_t() { - DEBUG_PRINT("ledger.memory.dtors", "dtor scope_t"); - for (symbol_map::iterator i = symbols.begin(); - i != symbols.end(); - i++) - (*i).second->release(); - } - - void define(const std::string& name, value_expr_t * def) { - DEBUG_PRINT("ledger.valexpr.syms", - "Defining '" << name << "' = " << def); - std::pair<symbol_map::iterator, bool> result - = symbols.insert(symbol_pair(name, def)); - if (! result.second) { - symbols.erase(name); - std::pair<symbol_map::iterator, bool> result - = symbols.insert(symbol_pair(name, def)); - if (! result.second) { - def->release(); - throw new compute_error(std::string("Redefinition of '") + - name + "' in same scope"); - } - } - def->acquire(); - } - value_expr_t * lookup(const std::string& name) { - symbol_map::const_iterator i = symbols.find(name); - if (i != symbols.end()) - return (*i).second; - else if (parent) - return parent->lookup(name); - return NULL; - } -}; - -extern std::auto_ptr<scope_t> global_scope; +extern std::auto_ptr<symbol_scope_t> global_scope; extern datetime_t terminus; -extern bool initialized; - -void init_value_expr(); -bool compute_amount(value_expr_t * expr, amount_t& amt, +bool compute_amount(const ptr_op_t expr, amount_t& amt, const transaction_t * xact, - value_expr_t * context = NULL); - -#define PARSE_VALEXPR_NORMAL 0x00 -#define PARSE_VALEXPR_PARTIAL 0x01 -#define PARSE_VALEXPR_RELAXED 0x02 -#define PARSE_VALEXPR_NO_MIGRATE 0x04 -#define PARSE_VALEXPR_NO_REDUCE 0x08 -#define PARSE_VALEXPR_NO_ASSIGN 0x10 - -value_expr_t * parse_value_expr(std::istream& in, - scope_t * scope = NULL, - const short flags = PARSE_VALEXPR_RELAXED); - -inline value_expr_t * -parse_value_expr(const std::string& str, - scope_t * scope = NULL, - const short flags = PARSE_VALEXPR_RELAXED) { - std::istringstream stream(str); - try { - return parse_value_expr(stream, scope, flags); - } - catch (error * err) { - err->context.push_back - (new line_context(str, (long)stream.tellg() - 1, - "While parsing value expression:")); - throw err; - } -} - -inline value_expr_t * -parse_value_expr(const char * p, - scope_t * scope = NULL, - const short flags = PARSE_VALEXPR_RELAXED) { - return parse_value_expr(std::string(p), scope, flags); -} - -void dump_value_expr(std::ostream& out, const value_expr_t * node, - const int depth = 0); - -bool write_value_expr(std::ostream& out, - const value_expr_t * node, - const bool relaxed = true, - const value_expr_t * node_to_find = NULL, - unsigned long * start_pos = NULL, - unsigned long * end_pos = NULL); + const ptr_op_t context = NULL); ////////////////////////////////////////////////////////////////////// -inline void guarded_compute(const value_expr_t * expr, - value_t& result, - const details_t& details = details_t(), - value_expr_t * context = NULL) { +inline void guarded_compute(const ptr_op_t expr, + value_t& result, + const details_t& details = details_t(), + const ptr_op_t context = NULL) { try { expr->compute(result, details); } @@ -334,153 +753,191 @@ inline void guarded_compute(const value_expr_t * expr, err->context.push_back(new valexpr_context(expr)); error_context * last = err->context.back(); if (valexpr_context * ctxt = dynamic_cast<valexpr_context *>(last)) { - ctxt->expr = expr->acquire(); + ctxt->expr = expr; ctxt->desc = "While computing value expression:"; } throw err; } } -inline value_t guarded_compute(const value_expr_t * expr, +inline value_t guarded_compute(const ptr_op_t expr, const details_t& details = details_t(), - value_expr_t * context = NULL) { + ptr_op_t context = NULL) { value_t temp; guarded_compute(expr, temp, details, context); return temp; } +template<> +inline symbol_scope_t& +scope_t::find_scope<symbol_scope_t>(bool skip_this) { + optional<scope_t&> scope = find_scope(SYMBOL_SCOPE, skip_this); + assert(scope); + return downcast<symbol_scope_t>(*scope); +} + +template<> +inline call_scope_t& +scope_t::find_scope<call_scope_t>(bool skip_this) { + optional<scope_t&> scope = find_scope(CALL_SCOPE, skip_this); + assert(scope); + return downcast<call_scope_t>(*scope); +} + +#if 0 +template<> +inline context_scope_t& +scope_t::find_scope<context_scope_t>(bool skip_this) { + optional<scope_t&> scope = find_scope(CONTEXT_SCOPE, skip_this); + assert(scope); + return downcast<context_scope_t>(*scope); +} +#endif + +#define FIND_SCOPE(scope_type, scope_ref) \ + downcast<scope_t>(scope_ref).find_scope<scope_type>() + +#define CALL_SCOPE(scope_ref) \ + FIND_SCOPE(call_scope_t, scope_ref) +#define SYMBOL_SCOPE(scope_ref) \ + FIND_SCOPE(symbol_scope_t, scope_ref) +#if 0 +#define CONTEXT_SCOPE(scope_ref) \ + FIND_SCOPE(context_scope_t, scope_ref) +#endif + +inline ptr_op_t op_t::new_node(kind_t _kind, ptr_op_t _left, ptr_op_t _right) { + ptr_op_t node(new op_t(_kind)); + node->set_left(_left); + node->set_right(_right); + return node; +} + +inline ptr_op_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 ptr_op_t op_t::wrap_functor(const function_t& fobj) { + ptr_op_t temp(new op_t(op_t::FUNCTION)); + temp->set_function(fobj); + return temp; +} + +class parser_t; + +} // namespace expr + ////////////////////////////////////////////////////////////////////// class value_expr { - value_expr_t * ptr; + expr::ptr_op_t ptr; + public: - std::string expr; + string expr_str; - value_expr() : ptr(NULL) {} + typedef expr::details_t details_t; - value_expr(const std::string& _expr) : expr(_expr) { - DEBUG_PRINT("ledger.memory.ctors", "ctor value_expr"); - if (! _expr.empty()) - ptr = parse_value_expr(expr)->acquire(); - else - ptr = NULL; + value_expr() { + TRACE_CTOR(value_expr, ""); } - value_expr(value_expr_t * _ptr) - : ptr(_ptr ? _ptr->acquire(): NULL) { - DEBUG_PRINT("ledger.memory.ctors", "ctor value_expr"); + + value_expr(const string& _expr_str); + value_expr(const expr::ptr_op_t _ptr, const string& _expr_str = "") + : ptr(_ptr), expr_str(_expr_str) { + TRACE_CTOR(value_expr, "const expr::ptr_op_t"); } value_expr(const value_expr& other) - : ptr(other.ptr ? other.ptr->acquire() : NULL), - expr(other.expr) { - DEBUG_PRINT("ledger.memory.ctors", "ctor value_expr"); + : ptr(other.ptr), expr_str(other.expr_str) { + TRACE_CTOR(value_expr, "copy"); } - virtual ~value_expr() { - DEBUG_PRINT("ledger.memory.dtors", "dtor value_expr"); - if (ptr) - ptr->release(); + virtual ~value_expr() throw() { + TRACE_DTOR(value_expr); } - value_expr& operator=(const std::string& _expr) { - expr = _expr; - reset(parse_value_expr(expr)); - return *this; - } - value_expr& operator=(value_expr_t * _expr) { - expr = ""; - reset(_expr); - return *this; - } value_expr& operator=(const value_expr& _expr) { - expr = _expr.expr; + expr_str = _expr.expr_str; reset(_expr.get()); return *this; } + value_expr& operator=(const string& _expr) { + return *this = value_expr(_expr); + } operator bool() const throw() { - return ptr != NULL; + return ptr.get() != NULL; } - operator std::string() const throw() { - return expr; + operator string() const throw() { + return expr_str; } - operator value_expr_t *() const throw() { + operator const expr::ptr_op_t() const throw() { return ptr; } - value_expr_t& operator*() const throw() { - return *ptr; - } - value_expr_t * operator->() const throw() { + const expr::ptr_op_t operator->() const throw() { return ptr; } - value_expr_t * get() const throw() { return ptr; } - value_expr_t * release() throw() { - value_expr_t * tmp = ptr; - ptr = 0; + const expr::ptr_op_t get() const throw() { return ptr; } + const expr::ptr_op_t release() throw() { + const expr::ptr_op_t tmp = ptr; + ptr = expr::ptr_op_t(); return tmp; } - void reset(value_expr_t * p = 0) throw() { - if (p != ptr) { - if (ptr) - ptr->release(); - ptr = p ? p->acquire() : NULL; - } + void reset(const expr::ptr_op_t p = expr::ptr_op_t()) throw() { + ptr = p; } virtual void compute(value_t& result, const details_t& details = details_t(), - value_expr_t * context = NULL) { + expr::ptr_op_t context = NULL) { guarded_compute(ptr, result, details, context); } virtual value_t compute(const details_t& details = details_t(), - value_expr_t * context = NULL) { + expr::ptr_op_t context = NULL) { value_t temp; guarded_compute(ptr, temp, details, context); return temp; } - friend bool write_value_expr(std::ostream& out, - const value_expr_t * node, - const value_expr_t * node_to_find, + friend bool print_value_expr(std::ostream& out, + const expr::ptr_op_t node, + const expr::ptr_op_t node_to_find, unsigned long * start_pos, unsigned long * end_pos); + + static std::auto_ptr<value_expr> amount_expr; + static std::auto_ptr<value_expr> total_expr; + static std::auto_ptr<expr::parser_t> parser; + + static void initialize(); + static void shutdown(); }; -extern value_expr amount_expr; -extern value_expr total_expr; +typedef value_expr::details_t details_t; // jww (2008-07-20): remove inline void compute_amount(value_t& result, const details_t& details = details_t()) { - if (amount_expr) - amount_expr->compute(result, details); + if (value_expr::amount_expr.get()) + value_expr::amount_expr->compute(result, details); } inline value_t compute_amount(const details_t& details = details_t()) { - if (amount_expr) - return amount_expr->compute(details); + if (value_expr::amount_expr.get()) + return value_expr::amount_expr->compute(details); } inline void compute_total(value_t& result, const details_t& details = details_t()) { - if (total_expr) - total_expr->compute(result, details); + if (value_expr::total_expr.get()) + value_expr::total_expr->compute(result, details); } inline value_t compute_total(const details_t& details = details_t()) { - if (total_expr) - return total_expr->compute(details); -} - -value_expr_t * parse_boolean_expr(std::istream& in, scope_t * scope, - const short flags); - -inline void parse_value_definition(const std::string& str, - scope_t * scope = NULL) { - std::istringstream def(str); - value_expr expr - (parse_boolean_expr(def, scope ? scope : global_scope.get(), - PARSE_VALEXPR_RELAXED)); + if (value_expr::total_expr.get()) + return value_expr::total_expr->compute(details); } ////////////////////////////////////////////////////////////////////// @@ -488,28 +945,28 @@ inline void parse_value_definition(const std::string& str, template <typename T> class item_predicate { - public: - const value_expr_t * predicate; +public: + value_expr predicate; - item_predicate(const std::string& _predicate) : predicate(NULL) { - DEBUG_PRINT("ledger.memory.ctors", "ctor item_predicate<T>"); - if (! _predicate.empty()) - predicate = parse_value_expr(_predicate)->acquire(); + item_predicate() { + TRACE_CTOR(item_predicate, ""); } - item_predicate(const value_expr_t * _predicate = NULL) - : predicate(_predicate->acquire()) { - DEBUG_PRINT("ledger.memory.ctors", "ctor item_predicate<T>"); + item_predicate(const item_predicate& other) : predicate(other.predicate) { + TRACE_CTOR(item_predicate, "copy"); } - - ~item_predicate() { - DEBUG_PRINT("ledger.memory.dtors", "dtor item_predicate<T>"); - if (predicate) - predicate->release(); + item_predicate(const value_expr& _predicate) : predicate(_predicate) { + TRACE_CTOR(item_predicate, "const value_expr&"); + } + item_predicate(const string& _predicate) : predicate(_predicate) { + TRACE_CTOR(item_predicate, "const string&"); + } + ~item_predicate() throw() { + TRACE_DTOR(item_predicate); } bool operator()(const T& item) const { return (! predicate || - predicate->compute(details_t(item)).strip_annotations()); + predicate->compute(value_expr::details_t(item)).strip_annotations()); } }; |