summaryrefslogtreecommitdiff
path: root/valexpr.h
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2006-02-27 23:52:31 +0000
committerJohn Wiegley <johnw@newartisans.com>2008-04-13 02:41:27 -0400
commit7901598f1d1e419e19c860e81749805371298030 (patch)
treef3b4b42ad4217cd5a59eafb8cb8ffacea83b60ca /valexpr.h
parent4507573d4fbc4ece6a4bb832b2e1fffae0885db8 (diff)
downloadfork-ledger-7901598f1d1e419e19c860e81749805371298030.tar.gz
fork-ledger-7901598f1d1e419e19c860e81749805371298030.tar.bz2
fork-ledger-7901598f1d1e419e19c860e81749805371298030.zip
Checked in all major updates.
Diffstat (limited to 'valexpr.h')
-rw-r--r--valexpr.h272
1 files changed, 231 insertions, 41 deletions
diff --git a/valexpr.h b/valexpr.h
index c9db4601..0bb9aa32 100644
--- a/valexpr.h
+++ b/valexpr.h
@@ -16,6 +16,7 @@ struct details_t
const transaction_t * xact;
const account_t * account;
+ details_t() : entry(NULL), xact(NULL), account(NULL) {}
details_t(const entry_t& _entry)
: entry(&_entry), xact(NULL), account(NULL) {
DEBUG_PRINT("ledger.memory.ctors", "ctor details_t");
@@ -32,6 +33,29 @@ struct details_t
#endif
};
+typedef void (*value_func_t)(value_t& result, const details_t& details,
+ value_expr_t * context);
+
+class value_calc
+{
+public:
+ virtual ~value_calc() {}
+ virtual void compute(value_t& result, const details_t& details,
+ value_expr_t * context = NULL) = 0;
+};
+
+class value_func : public value_calc
+{
+ value_func_t func;
+public:
+ value_func(value_func_t _func) : func(_func) {}
+
+ virtual void compute(value_t& result, const details_t& details,
+ value_expr_t * context = NULL) {
+ func(result, details, context);
+ }
+};
+
struct value_expr_t
{
enum kind_t {
@@ -39,10 +63,14 @@ struct value_expr_t
CONSTANT_I,
CONSTANT_T,
CONSTANT_A,
+ CONSTANT_V,
+
+ CONSTANTS,
// Item details
AMOUNT,
COST,
+ PRICE,
DATE,
CLEARED,
PENDING,
@@ -55,6 +83,7 @@ struct value_expr_t
COUNT,
TOTAL,
COST_TOTAL,
+ PRICE_TOTAL,
// Relating to format_t
VALUE_EXPR,
@@ -62,13 +91,12 @@ struct value_expr_t
// Functions
F_NOW,
- F_PARENT,
F_ARITH_MEAN,
+ F_QUANTITY,
+ F_COMMODITY,
+ F_SET_COMMODITY,
F_VALUE,
- F_FUNC,
- F_NEG,
F_ABS,
- F_STRIP,
F_CODE_MASK,
F_PAYEE_MASK,
F_NOTE_MASK,
@@ -76,11 +104,18 @@ struct value_expr_t
F_SHORT_ACCOUNT_MASK,
F_COMMODITY_MASK,
+ TERMINALS,
+
+ F_PARENT,
+
// Binary operators
+ O_NEG,
O_ADD,
O_SUB,
O_MUL,
O_DIV,
+ O_PERC,
+ O_NEQ,
O_EQ,
O_LT,
O_LTE,
@@ -91,88 +126,244 @@ struct value_expr_t
O_OR,
O_QUES,
O_COL,
+ O_COM,
+ O_DEF,
+ O_REF,
O_ARG,
LAST
};
kind_t kind;
+ mutable short refc;
value_expr_t * left;
- value_expr_t * right;
union {
- std::time_t constant_t;
- long constant_i;
+ std::time_t constant_t;
+ long constant_i;
+ amount_t * constant_a;
+ value_t * constant_v;
+ mask_t * mask;
+ value_expr_t * right;
};
- std::string constant_s;
- amount_t constant_a;
- mask_t * mask;
value_expr_t(const kind_t _kind)
- : kind(_kind), left(NULL), right(NULL), mask(NULL) {
+ : kind(_kind), refc(0), left(NULL), right(NULL) {
DEBUG_PRINT("ledger.memory.ctors", "ctor value_expr_t");
}
+ ~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;
+ }
+ value_expr_t * acquire() {
+ DEBUG_PRINT("ledger.valexpr.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;
+ }
- ~value_expr_t() {
- DEBUG_PRINT("ledger.memory.dtors", "dtor value_expr_t");
- if (mask) delete mask;
- if (left) delete left;
- if (right) delete right;
+ void set_left(value_expr_t * expr) {
+ assert(kind > TERMINALS);
+ if (left)
+ left->release();
+ left = expr ? expr->acquire() : NULL;
}
- void compute(value_t& result, const details_t& details) const;
+ void set_right(value_expr_t * expr) {
+ assert(kind > TERMINALS);
+ if (right)
+ right->release();
+ right = expr ? expr->acquire() : NULL;
+ }
+
+ void compute(value_t& result, const details_t& details,
+ value_expr_t * context = NULL) const;
+};
+
+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) {}
+ ~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->acquire()));
+ if (! result.second)
+ throw value_expr_error(std::string("Redefinition of '") +
+ name + "' in same scope");
+ }
+ 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<value_expr_t> amount_expr;
-extern std::auto_ptr<value_expr_t> total_expr;
+extern std::auto_ptr<scope_t> global_scope;
+
extern std::time_t terminus;
+extern bool initialized;
+
+void init_value_expr();
bool compute_amount(value_expr_t * expr, amount_t& amt, transaction_t& xact);
-inline void compute_amount(value_t& result, const details_t& details) {
- if (amount_expr.get())
- amount_expr->compute(result, details);
+struct scope_t;
+value_expr_t * parse_boolean_expr(std::istream& in, scope_t * scope);
+
+inline value_expr_t * parse_boolean_expr(const char * p,
+ scope_t * scope = NULL) {
+ std::istringstream stream(p);
+ return parse_boolean_expr(stream, scope);
}
-inline void compute_total(value_t& result, const details_t& details) {
- if (total_expr.get())
- total_expr->compute(result, details);
+inline value_expr_t * parse_boolean_expr(const std::string& str,
+ scope_t * scope = NULL) {
+ return parse_boolean_expr(str.c_str(), scope);
}
value_expr_t * parse_value_expr(std::istream& in,
+ scope_t * scope = NULL,
const bool partial = false);
inline value_expr_t * parse_value_expr(const char * p,
+ scope_t * scope = NULL,
const bool partial = false) {
std::istringstream stream(p);
- return parse_value_expr(stream, partial);
+ return parse_value_expr(stream, scope, partial);
}
inline value_expr_t * parse_value_expr(const std::string& str,
+ scope_t * scope = NULL,
const bool partial = false) {
- return parse_value_expr(str.c_str());
+ return parse_value_expr(str.c_str(), scope);
}
-#ifdef DEBUG_ENABLED
-void dump_value_expr(std::ostream& out, const value_expr_t * node);
-#endif
+void dump_value_expr(std::ostream& out, const value_expr_t * node,
+ const int depth = 0);
+
+//////////////////////////////////////////////////////////////////////
+//
+// This class is used so that during the "in between" stages of value
+// expression parsing -- while no one yet holds a reference to the
+// value_expr_t object -- we can be assured of deletion should an
+// exception happen to whip by.
+
+struct value_auto_ptr {
+ value_expr_t * ptr;
+ value_auto_ptr() : ptr(NULL) {}
+ explicit value_auto_ptr(value_expr_t * _ptr) : ptr(_ptr) {}
+ ~value_auto_ptr() {
+ if (ptr && ptr->refc == 0)
+ delete ptr;
+ }
+ value_expr_t& operator*() const throw() {
+ return *ptr;
+ }
+ value_expr_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;
+ return tmp;
+ }
+ void reset(value_expr_t * p = 0) throw() {
+ if (p != ptr) {
+ if (ptr && ptr->refc == 0)
+ delete ptr;
+ ptr = p;
+ }
+ }
+};
+
+//////////////////////////////////////////////////////////////////////
+
+class value_expr : public value_calc
+{
+ std::string expr;
+ value_expr_t * parsed;
+
+public:
+ value_expr(const std::string& _expr) : expr(_expr) {
+ try {
+ parsed = parse_value_expr(expr);
+ parsed->acquire();
+ }
+ catch (const value_expr_error& err) {
+ throw error(std::string("In value expression '") +
+ expr + "': " + err.what());
+ }
+ }
+ value_expr(value_expr_t * _parsed) : parsed(_parsed->acquire()) {}
+
+ virtual ~value_expr() {
+ if (parsed != NULL)
+ parsed->release();
+ }
+
+ virtual void compute(value_t& result, const details_t& details,
+ value_expr_t * context = NULL) {
+ parsed->compute(result, details, context);
+ }
+};
+
+extern std::auto_ptr<value_calc> amount_expr;
+extern std::auto_ptr<value_calc> total_expr;
+
+inline void compute_amount(value_t& result, const details_t& details) {
+ if (amount_expr.get() != NULL)
+ amount_expr->compute(result, details);
+}
+
+inline void compute_total(value_t& result, const details_t& details) {
+ if (total_expr.get() != NULL)
+ total_expr->compute(result, details);
+}
//////////////////////////////////////////////////////////////////////
template <typename T>
class item_predicate
{
+ public:
const value_expr_t * predicate;
- bool allocated;
- public:
- item_predicate(const std::string& _predicate)
- : predicate(NULL), allocated(false) {
+ item_predicate(const std::string& _predicate) : predicate(NULL) {
DEBUG_PRINT("ledger.memory.ctors", "ctor item_predicate<T>");
if (! _predicate.empty()) {
try {
- predicate = parse_value_expr(_predicate);
- allocated = true;
+ predicate = parse_value_expr(_predicate)->acquire();
}
catch (value_expr_error& err) {
throw value_expr_error(std::string("In predicate '") +
@@ -181,14 +372,14 @@ class item_predicate
}
}
item_predicate(const value_expr_t * _predicate = NULL)
- : predicate(_predicate), allocated(false) {
+ : predicate(_predicate->acquire()) {
DEBUG_PRINT("ledger.memory.ctors", "ctor item_predicate<T>");
}
~item_predicate() {
DEBUG_PRINT("ledger.memory.dtors", "dtor item_predicate<T>");
- if (predicate && allocated)
- delete predicate;
+ if (predicate)
+ predicate->release();
}
bool operator()(const T& item) const {
@@ -196,9 +387,8 @@ class item_predicate
value_t result;
predicate->compute(result, details_t(item));
return result;
- } else {
- return true;
}
+ return true;
}
};