summaryrefslogtreecommitdiff
path: root/valexpr.cc
diff options
context:
space:
mode:
Diffstat (limited to 'valexpr.cc')
-rw-r--r--valexpr.cc1085
1 files changed, 0 insertions, 1085 deletions
diff --git a/valexpr.cc b/valexpr.cc
deleted file mode 100644
index 9091672f..00000000
--- a/valexpr.cc
+++ /dev/null
@@ -1,1085 +0,0 @@
-#include "valexpr.h"
-#include "walk.h"
-#include "error.h"
-#include "datetime.h"
-#include "debug.h"
-#include "util.h"
-#ifdef USE_BOOST_PYTHON
-#include "py_eval.h"
-#endif
-
-namespace ledger {
-
-std::auto_ptr<value_expr_t> amount_expr;
-std::auto_ptr<value_expr_t> total_expr;
-
-void value_expr_t::compute(value_t& result, const details_t& details) const
-{
- switch (kind) {
- case CONSTANT_I:
- result = constant_i;
- break;
- case CONSTANT_T:
- result = long(constant_t);
- break;
-
- case CONSTANT_A:
- result = constant_a;
- break;
-
- case AMOUNT:
- if (details.xact) {
- if (transaction_has_xdata(*details.xact) &&
- transaction_xdata_(*details.xact).dflags & TRANSACTION_COMPOSITE)
- result = transaction_xdata_(*details.xact).composite_amount;
- else
- result = details.xact->amount;
- }
- else if (details.account && account_has_xdata(*details.account)) {
- result = account_xdata(*details.account).value;
- }
- else {
- result = 0L;
- }
- break;
-
- case COST:
- if (details.xact) {
- bool set = false;
- if (transaction_has_xdata(*details.xact)) {
- transaction_xdata_t& xdata(transaction_xdata_(*details.xact));
- if (xdata.dflags & TRANSACTION_COMPOSITE) {
- if (xdata.composite_amount.type == value_t::BALANCE_PAIR &&
- ((balance_pair_t *) xdata.composite_amount.data)->cost)
- result = *((balance_pair_t *) xdata.composite_amount.data)->cost;
- else
- result = xdata.composite_amount;
- set = true;
- }
- }
-
- if (! set) {
- if (details.xact->cost)
- result = *details.xact->cost;
- else
- result = details.xact->amount;
- }
- }
- else if (details.account && account_has_xdata(*details.account)) {
- result = account_xdata(*details.account).value.cost();
- }
- else {
- result = 0L;
- }
- break;
-
- case TOTAL:
- if (details.xact && transaction_has_xdata(*details.xact))
- result = transaction_xdata_(*details.xact).total;
- else if (details.account && account_has_xdata(*details.account))
- result = account_xdata(*details.account).total;
- else
- result = 0L;
- break;
- case COST_TOTAL:
- if (details.xact && transaction_has_xdata(*details.xact))
- result = transaction_xdata_(*details.xact).total.cost();
- else if (details.account && account_has_xdata(*details.account))
- result = account_xdata(*details.account).total.cost();
- else
- result = 0L;
- break;
-
- case VALUE_EXPR:
- if (amount_expr.get())
- amount_expr->compute(result, details);
- else
- result = 0L;
- break;
- case TOTAL_EXPR:
- if (total_expr.get())
- total_expr->compute(result, details);
- else
- result = 0L;
- break;
-
- case DATE:
- if (details.xact && transaction_has_xdata(*details.xact) &&
- transaction_xdata_(*details.xact).date)
- result = long(transaction_xdata_(*details.xact).date);
- else if (details.entry)
- result = long(details.entry->date);
- else
- result = long(now);
- break;
-
- case CLEARED:
- if (details.entry)
- result = details.entry->state == entry_t::CLEARED;
- else
- result = false;
- break;
-
- case REAL:
- if (details.xact)
- result = ! (details.xact->flags & TRANSACTION_VIRTUAL);
- else
- result = true;
- break;
-
- case ACTUAL:
- if (details.xact)
- result = ! (details.xact->flags & TRANSACTION_AUTO);
- else
- result = true;
- break;
-
- case INDEX:
- if (details.xact && transaction_has_xdata(*details.xact))
- result = long(transaction_xdata_(*details.xact).index + 1);
- else if (details.account && account_has_xdata(*details.account))
- result = long(account_xdata(*details.account).count);
- else
- result = 0L;
- break;
-
- case COUNT:
- if (details.xact && transaction_has_xdata(*details.xact))
- result = long(transaction_xdata_(*details.xact).index + 1);
- else if (details.account && account_has_xdata(*details.account))
- result = long(account_xdata(*details.account).total_count);
- else
- result = 0L;
- break;
-
- case DEPTH:
- if (details.account)
- result = long(details.account->depth);
- else
- result = 0L;
- break;
-
- case F_ARITH_MEAN:
- if (details.xact && transaction_has_xdata(*details.xact)) {
- assert(left);
- left->compute(result, details);
- result /= amount_t(long(transaction_xdata_(*details.xact).index + 1));
- }
- else if (details.account && account_has_xdata(*details.account) &&
- account_xdata(*details.account).total_count) {
- assert(left);
- left->compute(result, details);
- result /= amount_t(long(account_xdata(*details.account).total_count));
- }
- else {
- result = 0L;
- }
- break;
-
- case F_PARENT:
- if (details.account && details.account->parent)
- left->compute(result, details_t(*details.account->parent));
- break;
-
- case F_NEG:
- assert(left);
- left->compute(result, details);
- result.negate();
- break;
-
- case F_ABS:
- assert(left);
- left->compute(result, details);
- result.abs();
- break;
-
- case F_STRIP: {
- assert(left);
- left->compute(result, details);
-
- balance_t * bal = NULL;
- switch (result.type) {
- case value_t::BALANCE_PAIR:
- bal = &((balance_pair_t *) result.data)->quantity;
- // fall through...
-
- case value_t::BALANCE:
- if (! bal)
- bal = (balance_t *) result.data;
-
- if (bal->amounts.size() < 2) {
- result.cast(value_t::AMOUNT);
- } else {
- value_t temp;
- for (amounts_map::const_iterator i = bal->amounts.begin();
- i != bal->amounts.end();
- i++) {
- amount_t x = (*i).second;
- x.clear_commodity();
- temp += x;
- }
- result = temp;
- assert(temp.type == value_t::AMOUNT);
- }
- // fall through...
-
- case value_t::AMOUNT:
- ((amount_t *) result.data)->clear_commodity();
- break;
-
- default:
- break;
- }
- break;
- }
-
- case F_CODE_MASK:
- assert(mask);
- if (details.entry)
- result = mask->match(details.entry->code);
- else
- result = false;
- break;
-
- case F_PAYEE_MASK:
- assert(mask);
- if (details.entry)
- result = mask->match(details.entry->payee);
- else
- result = false;
- break;
-
- case F_NOTE_MASK:
- assert(mask);
- if (details.xact)
- result = mask->match(details.xact->note);
- else
- result = false;
- break;
-
- case F_ACCOUNT_MASK:
- assert(mask);
- if (details.account)
- result = mask->match(details.account->fullname());
- else
- result = false;
- break;
-
- case F_SHORT_ACCOUNT_MASK:
- assert(mask);
- if (details.account)
- result = mask->match(details.account->name);
- else
- result = false;
- break;
-
- case F_VALUE: {
- assert(left);
- left->compute(result, details);
-
- std::time_t moment = now;
- if (right) {
- switch (right->kind) {
- case DATE:
- if (details.xact && transaction_has_xdata(*details.xact) &&
- transaction_xdata_(*details.xact).date)
- moment = transaction_xdata_(*details.xact).date;
- else if (details.entry)
- moment = details.entry->date;
- break;
- case CONSTANT_T:
- moment = right->constant_t;
- break;
- default:
- throw compute_error("Invalid date passed to P(value,date)");
- }
- }
-
- result = result.value(moment);
- break;
- }
-
- case F_INTERP_FUNC: {
-#ifdef USE_BOOST_PYTHON
- if (! python_call(constant_s, right, details, result))
- result = 0L;
-#else
- result = 0L;
-#endif
- break;
- }
-
- case O_NOT:
- left->compute(result, details);
- result.negate();
- break;
-
- case O_QUES: {
- assert(left);
- assert(right);
- assert(right->kind == O_COL);
- left->compute(result, details);
- if (result)
- right->left->compute(result, details);
- else
- right->right->compute(result, details);
- break;
- }
-
- case O_AND:
- assert(left);
- assert(right);
- left->compute(result, details);
- if (result)
- right->compute(result, details);
- break;
-
- case O_OR:
- assert(left);
- assert(right);
- left->compute(result, details);
- if (! result)
- right->compute(result, details);
- break;
-
- case O_EQ:
- case O_LT:
- case O_LTE:
- case O_GT:
- case O_GTE: {
- assert(left);
- assert(right);
- value_t temp;
- left->compute(temp, details);
- right->compute(result, details);
- switch (kind) {
- case O_EQ: result = temp == result; break;
- case O_LT: result = temp < result; break;
- case O_LTE: result = temp <= result; break;
- case O_GT: result = temp > result; break;
- case O_GTE: result = temp >= result; break;
- default: assert(0); break;
- }
- break;
- }
-
- case O_ADD:
- case O_SUB:
- case O_MUL:
- case O_DIV: {
- assert(left);
- assert(right);
- value_t temp;
- right->compute(temp, details);
- left->compute(result, details);
- switch (kind) {
- case O_ADD: result += temp; break;
- case O_SUB: result -= temp; break;
- case O_MUL: result *= temp; break;
- case O_DIV: result /= temp; break;
- default: assert(0); break;
- }
- break;
- }
-
- case LAST:
- default:
- assert(0);
- break;
- }
-}
-
-static inline void unexpected(char c, char wanted = '\0') {
- if ((unsigned char) c == 0xff) {
- if (wanted)
- throw value_expr_error(std::string("Missing '") + wanted + "'");
- else
- throw value_expr_error("Unexpected end");
- } else {
- if (wanted)
- throw value_expr_error(std::string("Invalid char '") + c +
- "' (wanted '" + wanted + "')");
- else
- throw value_expr_error(std::string("Invalid char '") + c + "'");
- }
-}
-
-value_expr_t * parse_value_term(std::istream& in);
-
-inline value_expr_t * parse_value_term(const char * p) {
- std::istringstream stream(p);
- return parse_value_term(stream);
-}
-
-value_expr_t * parse_value_term(std::istream& in)
-{
- std::auto_ptr<value_expr_t> node;
-
- char buf[256];
- char c = peek_next_nonws(in);
- if (std::isdigit(c)) {
- READ_INTO(in, buf, 255, c, std::isdigit(c));
-
- node.reset(new value_expr_t(value_expr_t::CONSTANT_I));
- node->constant_i = std::atol(buf);
- return node.release();
- }
- else if (c == '{') {
- in.get(c);
- READ_INTO(in, buf, 255, c, c != '}');
- if (c == '}')
- in.get(c);
- else
- unexpected(c, '}');
-
- node.reset(new value_expr_t(value_expr_t::CONSTANT_A));
- node->constant_a.parse(buf);
- return node.release();
- }
-
- in.get(c);
- switch (c) {
- // Basic terms
- case 'm':
- node.reset(new value_expr_t(value_expr_t::CONSTANT_T));
- node->constant_t = now;
- break;
-
- case 'a': node.reset(new value_expr_t(value_expr_t::AMOUNT)); break;
- case 'b': node.reset(new value_expr_t(value_expr_t::COST)); break;
- case 'd': node.reset(new value_expr_t(value_expr_t::DATE)); break;
- case 'X': node.reset(new value_expr_t(value_expr_t::CLEARED)); break;
- case 'R': node.reset(new value_expr_t(value_expr_t::REAL)); break;
- case 'L': node.reset(new value_expr_t(value_expr_t::ACTUAL)); break;
- case 'n': node.reset(new value_expr_t(value_expr_t::INDEX)); break;
- case 'N': node.reset(new value_expr_t(value_expr_t::COUNT)); break;
- case 'l': node.reset(new value_expr_t(value_expr_t::DEPTH)); break;
- case 'O': node.reset(new value_expr_t(value_expr_t::TOTAL)); break;
- case 'B': node.reset(new value_expr_t(value_expr_t::COST_TOTAL)); break;
-
- // Relating to format_t
- case 't': node.reset(new value_expr_t(value_expr_t::VALUE_EXPR)); break;
- case 'T': node.reset(new value_expr_t(value_expr_t::TOTAL_EXPR)); break;
-
- // Compound terms
- case 'v': node.reset(parse_value_expr("P(a,d)")); break;
- case 'V': node.reset(parse_value_term("P(O,d)")); break;
- case 'g': node.reset(parse_value_expr("v-b")); break;
- case 'G': node.reset(parse_value_expr("V-B")); break;
-
- // Functions
- case '^':
- node.reset(new value_expr_t(value_expr_t::F_PARENT));
- node->left = parse_value_term(in);
- break;
-
- case '-':
- node.reset(new value_expr_t(value_expr_t::F_NEG));
- node->left = parse_value_term(in);
- break;
-
- case 'U':
- node.reset(new value_expr_t(value_expr_t::F_ABS));
- node->left = parse_value_term(in);
- break;
-
- case 'S':
- node.reset(new value_expr_t(value_expr_t::F_STRIP));
- node->left = parse_value_term(in);
- break;
-
- case 'A':
- node.reset(new value_expr_t(value_expr_t::F_ARITH_MEAN));
- node->left = parse_value_term(in);
- break;
-
- case 'P':
- node.reset(new value_expr_t(value_expr_t::F_VALUE));
- if (peek_next_nonws(in) == '(') {
- in.get(c);
- node->left = parse_value_expr(in, true);
- if (peek_next_nonws(in) == ',') {
- in.get(c);
- node->right = parse_value_expr(in, true);
- }
- in.get(c);
- if (c != ')')
- unexpected(c, ')');
- } else {
- node->left = parse_value_term(in);
- }
- break;
-
- // Other
- case 'c':
- case 'p':
- case 'w':
- case 'W':
- case 'e':
- case '/': {
- bool code_mask = c == 'c';
- bool payee_mask = c == 'p';
- bool note_mask = c == 'e';
- bool short_account_mask = c == 'w';
-
- if (c == '/') {
- c = peek_next_nonws(in);
- if (c == '/') {
- in.get(c);
- c = in.peek();
- if (c == '/') {
- in.get(c);
- c = in.peek();
- short_account_mask = true;
- } else {
- payee_mask = true;
- }
- }
- } else {
- in.get(c);
- }
-
- // Read in the regexp
- READ_INTO(in, buf, 255, c, c != '/');
- if (c != '/')
- unexpected(c, '/');
-
- value_expr_t::kind_t kind;
-
- if (short_account_mask)
- kind = value_expr_t::F_SHORT_ACCOUNT_MASK;
- else if (code_mask)
- kind = value_expr_t::F_CODE_MASK;
- else if (payee_mask)
- kind = value_expr_t::F_PAYEE_MASK;
- else if (note_mask)
- kind = value_expr_t::F_NOTE_MASK;
- else
- kind = value_expr_t::F_ACCOUNT_MASK;
-
- in.get(c);
- node.reset(new value_expr_t(kind));
- node->mask = new mask_t(buf);
- break;
- }
-
- case '@': {
- READ_INTO(in, buf, 255, c, c != '(');
- if (c != '(')
- unexpected(c, '(');
-
- node.reset(new value_expr_t(value_expr_t::F_INTERP_FUNC));
- node->constant_s = buf;
-
- in.get(c);
- if (peek_next_nonws(in) == ')') {
- in.get(c);
- } else {
- node->right = new value_expr_t(value_expr_t::O_ARG);
- value_expr_t * cur = node->right;
- cur->left = parse_value_expr(in, true);
- in.get(c);
- while (! in.eof() && c == ',') {
- cur->right = new value_expr_t(value_expr_t::O_ARG);
- cur = cur->right;
- cur->left = parse_value_expr(in, true);
- in.get(c);
- }
- if (c != ')')
- unexpected(c, ')');
- }
- break;
- }
-
- case '(':
- node.reset(parse_value_expr(in, true));
- in.get(c);
- if (c != ')')
- unexpected(c, ')');
- break;
-
- case '[': {
- READ_INTO(in, buf, 255, c, c != ']');
- if (c != ']')
- unexpected(c, ']');
- in.get(c);
-
- node.reset(new value_expr_t(value_expr_t::CONSTANT_T));
-
- interval_t timespan(buf);
- node->constant_t = timespan.first();
- break;
- }
-
- default:
- in.unget();
- break;
- }
-
- return node.release();
-}
-
-value_expr_t * parse_mul_expr(std::istream& in)
-{
- std::auto_ptr<value_expr_t> node(parse_value_term(in));
-
- if (node.get() && ! in.eof()) {
- char c = peek_next_nonws(in);
- while (c == '*' || c == '/') {
- in.get(c);
- switch (c) {
- case '*': {
- std::auto_ptr<value_expr_t> prev(node.release());
- node.reset(new value_expr_t(value_expr_t::O_MUL));
- node->left = prev.release();
- node->right = parse_value_term(in);
- break;
- }
-
- case '/': {
- std::auto_ptr<value_expr_t> prev(node.release());
- node.reset(new value_expr_t(value_expr_t::O_DIV));
- node->left = prev.release();
- node->right = parse_value_term(in);
- break;
- }
- }
- c = peek_next_nonws(in);
- }
- }
-
- return node.release();
-}
-
-value_expr_t * parse_add_expr(std::istream& in)
-{
- std::auto_ptr<value_expr_t> node(parse_mul_expr(in));
-
- if (node.get() && ! in.eof()) {
- char c = peek_next_nonws(in);
- while (c == '+' || c == '-') {
- in.get(c);
- switch (c) {
- case '+': {
- std::auto_ptr<value_expr_t> prev(node.release());
- node.reset(new value_expr_t(value_expr_t::O_ADD));
- node->left = prev.release();
- node->right = parse_mul_expr(in);
- break;
- }
-
- case '-': {
- std::auto_ptr<value_expr_t> prev(node.release());
- node.reset(new value_expr_t(value_expr_t::O_SUB));
- node->left = prev.release();
- node->right = parse_mul_expr(in);
- break;
- }
- }
- c = peek_next_nonws(in);
- }
- }
-
- return node.release();
-}
-
-value_expr_t * parse_logic_expr(std::istream& in)
-{
- std::auto_ptr<value_expr_t> node;
-
- if (peek_next_nonws(in) == '!') {
- char c;
- in.get(c);
- node.reset(new value_expr_t(value_expr_t::O_NOT));
- node->left = parse_logic_expr(in);
- return node.release();
- }
-
- node.reset(parse_add_expr(in));
-
- if (node.get() && ! in.eof()) {
- char c = peek_next_nonws(in);
- if (c == '=' || c == '<' || c == '>') {
- in.get(c);
- switch (c) {
- case '=': {
- std::auto_ptr<value_expr_t> prev(node.release());
- node.reset(new value_expr_t(value_expr_t::O_EQ));
- node->left = prev.release();
- node->right = parse_add_expr(in);
- break;
- }
-
- case '<': {
- std::auto_ptr<value_expr_t> prev(node.release());
- node.reset(new value_expr_t(value_expr_t::O_LT));
- if (peek_next_nonws(in) == '=') {
- in.get(c);
- node->kind = value_expr_t::O_LTE;
- }
- node->left = prev.release();
- node->right = parse_add_expr(in);
- break;
- }
-
- case '>': {
- std::auto_ptr<value_expr_t> prev(node.release());
- node.reset(new value_expr_t(value_expr_t::O_GT));
- if (peek_next_nonws(in) == '=') {
- in.get(c);
- node->kind = value_expr_t::O_GTE;
- }
- node->left = prev.release();
- node->right = parse_add_expr(in);
- break;
- }
-
- default:
- if (! in.eof())
- unexpected(c);
- break;
- }
- }
- }
-
- return node.release();
-}
-
-value_expr_t * parse_value_expr(std::istream& in, const bool partial)
-{
- std::auto_ptr<value_expr_t> node(parse_logic_expr(in));
-
- if (node.get() && ! in.eof()) {
- char c = peek_next_nonws(in);
- while (c == '&' || c == '|' || c == '?') {
- in.get(c);
- switch (c) {
- case '&': {
- std::auto_ptr<value_expr_t> prev(node.release());
- node.reset(new value_expr_t(value_expr_t::O_AND));
- node->left = prev.release();
- node->right = parse_logic_expr(in);
- break;
- }
-
- case '|': {
- std::auto_ptr<value_expr_t> prev(node.release());
- node.reset(new value_expr_t(value_expr_t::O_OR));
- node->left = prev.release();
- node->right = parse_logic_expr(in);
- break;
- }
-
- case '?': {
- std::auto_ptr<value_expr_t> prev(node.release());
- node.reset(new value_expr_t(value_expr_t::O_QUES));
- node->left = prev.release();
- value_expr_t * choices;
- node->right = choices = new value_expr_t(value_expr_t::O_COL);
- choices->left = parse_logic_expr(in);
- c = peek_next_nonws(in);
- if (c != ':')
- unexpected(c, ':');
- in.get(c);
- choices->right = parse_logic_expr(in);
- break;
- }
-
- default:
- if (! in.eof())
- unexpected(c);
- break;
- }
- c = peek_next_nonws(in);
- }
- }
-
- char c;
- if (! node.get()) {
- in.get(c);
- if (in.eof())
- throw value_expr_error(std::string("Failed to parse value expression"));
- else
- unexpected(c);
- } else if (! partial) {
- in.get(c);
- if (! in.eof())
- unexpected(c);
- else
- in.unget();
- }
-
- return node.release();
-}
-
-#ifdef DEBUG_ENABLED
-
-void dump_value_expr(std::ostream& out, const value_expr_t * node)
-{
- switch (node->kind) {
- case value_expr_t::CONSTANT_I:
- out << "UINT[" << node->constant_i << ']';
- break;
- case value_expr_t::CONSTANT_T:
- out << "DATE/TIME[" << node->constant_t << ']';
- break;
- case value_expr_t::CONSTANT_A:
- out << "CONST[" << node->constant_a << ']';
- break;
-
- case value_expr_t::AMOUNT: out << "AMOUNT"; break;
- case value_expr_t::COST: out << "COST"; break;
- case value_expr_t::DATE: out << "DATE"; break;
- case value_expr_t::CLEARED: out << "CLEARED"; break;
- case value_expr_t::REAL: out << "REAL"; break;
- case value_expr_t::ACTUAL: out << "ACTUAL"; break;
- case value_expr_t::INDEX: out << "INDEX"; break;
- case value_expr_t::COUNT: out << "COUNT"; break;
- case value_expr_t::DEPTH: out << "DEPTH"; break;
- case value_expr_t::TOTAL: out << "TOTAL"; break;
- case value_expr_t::COST_TOTAL: out << "COST_TOTAL"; break;
-
- case value_expr_t::F_ARITH_MEAN:
- out << "MEAN(";
- dump_value_expr(out, node->left);
- out << ')';
- break;
-
- case value_expr_t::F_NEG:
- out << "ABS(";
- dump_value_expr(out, node->left);
- out << ')';
- break;
-
- case value_expr_t::F_ABS:
- out << "ABS(";
- dump_value_expr(out, node->left);
- out << ')';
- break;
-
- case value_expr_t::F_STRIP:
- out << "STRIP(";
- dump_value_expr(out, node->left);
- out << ')';
- break;
-
- case value_expr_t::F_CODE_MASK:
- assert(node->mask);
- out << "M_CODE(" << node->mask->pattern << ')';
- break;
-
- case value_expr_t::F_PAYEE_MASK:
- assert(node->mask);
- out << "M_PAYEE(" << node->mask->pattern << ')';
- break;
-
- case value_expr_t::F_NOTE_MASK:
- assert(node->mask);
- out << "M_NOTE(" << node->mask->pattern << ')';
- break;
-
- case value_expr_t::F_ACCOUNT_MASK:
- assert(node->mask);
- out << "M_ACCT(" << node->mask->pattern << ')';
- break;
-
- case value_expr_t::F_SHORT_ACCOUNT_MASK:
- assert(node->mask);
- out << "M_SACCT(" << node->mask->pattern << ')';
- break;
-
- case value_expr_t::F_VALUE:
- out << "VALUE(";
- dump_value_expr(out, node->left);
- if (node->right) {
- out << ", ";
- dump_value_expr(out, node->right);
- }
- out << ')';
- break;
-
- case value_expr_t::F_INTERP_FUNC:
- out << "F_INTERP[" << node->constant_s << "](";
- dump_value_expr(out, node->right);
- out << ')';
- break;
-
- case value_expr_t::O_NOT:
- out << '!';
- dump_value_expr(out, node->left);
- break;
-
- case value_expr_t::O_ARG:
- dump_value_expr(out, node->left);
- if (node->right) {
- out << ',';
- dump_value_expr(out, node->right);
- }
- break;
-
- case value_expr_t::O_QUES:
- dump_value_expr(out, node->left);
- out << '?';
- dump_value_expr(out, node->right->left);
- out << ':';
- dump_value_expr(out, node->right->right);
- break;
-
- case value_expr_t::O_AND:
- case value_expr_t::O_OR:
- out << '(';
- dump_value_expr(out, node->left);
- switch (node->kind) {
- case value_expr_t::O_AND: out << " & "; break;
- case value_expr_t::O_OR: out << " | "; break;
- default: assert(0); break;
- }
- dump_value_expr(out, node->right);
- out << ')';
- break;
-
- case value_expr_t::O_EQ:
- case value_expr_t::O_LT:
- case value_expr_t::O_LTE:
- case value_expr_t::O_GT:
- case value_expr_t::O_GTE:
- out << '(';
- dump_value_expr(out, node->left);
- switch (node->kind) {
- case value_expr_t::O_EQ: out << '='; break;
- case value_expr_t::O_LT: out << '<'; break;
- case value_expr_t::O_LTE: out << "<="; break;
- case value_expr_t::O_GT: out << '>'; break;
- case value_expr_t::O_GTE: out << ">="; break;
- default: assert(0); break;
- }
- dump_value_expr(out, node->right);
- out << ')';
- break;
-
- case value_expr_t::O_ADD:
- case value_expr_t::O_SUB:
- case value_expr_t::O_MUL:
- case value_expr_t::O_DIV:
- out << '(';
- dump_value_expr(out, node->left);
- switch (node->kind) {
- case value_expr_t::O_ADD: out << '+'; break;
- case value_expr_t::O_SUB: out << '-'; break;
- case value_expr_t::O_MUL: out << '*'; break;
- case value_expr_t::O_DIV: out << '/'; break;
- default: assert(0); break;
- }
- dump_value_expr(out, node->right);
- out << ')';
- break;
-
- case value_expr_t::LAST:
- default:
- assert(0);
- break;
- }
-}
-
-#endif // DEBUG_ENABLED
-
-} // namespace ledger
-
-#ifdef USE_BOOST_PYTHON
-
-#include <boost/python.hpp>
-
-using namespace boost::python;
-using namespace ledger;
-
-value_t py_compute_1(value_expr_t& value_expr, const details_t& item)
-{
- value_t result;
- value_expr.compute(result, item);
- return result;
-}
-
-template <typename T>
-value_t py_compute(value_expr_t& value_expr, const T& item)
-{
- value_t result;
- value_expr.compute(result, details_t(item));
- return result;
-}
-
-value_expr_t * py_parse_value_expr_1(const std::string& str)
-{
- return parse_value_expr(str);
-}
-
-value_expr_t * py_parse_value_expr_2(const std::string& str, const bool partial)
-{
- return parse_value_expr(str, partial);
-}
-
-#define EXC_TRANSLATOR(type) \
- void exc_translate_ ## type(const type& err) { \
- PyErr_SetString(PyExc_RuntimeError, err.what()); \
- }
-
-EXC_TRANSLATOR(value_expr_error)
-EXC_TRANSLATOR(compute_error)
-EXC_TRANSLATOR(mask_error)
-
-void export_valexpr()
-{
- class_< details_t > ("Details", init<const entry_t&>())
- .def(init<const transaction_t&>())
- .def(init<const account_t&>())
- .add_property("entry",
- make_getter(&details_t::entry,
- return_value_policy<reference_existing_object>()))
- .add_property("xact",
- make_getter(&details_t::xact,
- return_value_policy<reference_existing_object>()))
- .add_property("account",
- make_getter(&details_t::account,
- return_value_policy<reference_existing_object>()))
- ;
-
- class_< value_expr_t > ("ValueExpr", init<value_expr_t::kind_t>())
- .def("compute", py_compute_1)
- .def("compute", py_compute<account_t>)
- .def("compute", py_compute<entry_t>)
- .def("compute", py_compute<transaction_t>)
- ;
-
- def("parse_value_expr", py_parse_value_expr_1,
- return_value_policy<manage_new_object>());
- def("parse_value_expr", py_parse_value_expr_2,
- return_value_policy<manage_new_object>());
-
- class_< item_predicate<transaction_t> >
- ("TransactionPredicate", init<std::string>())
- .def("__call__", &item_predicate<transaction_t>::operator())
- ;
-
- class_< item_predicate<account_t> >
- ("AccountPredicate", init<std::string>())
- .def("__call__", &item_predicate<account_t>::operator())
- ;
-
-#define EXC_TRANSLATE(type) \
- register_exception_translator<type>(&exc_translate_ ## type);
-
- EXC_TRANSLATE(value_expr_error);
- EXC_TRANSLATE(compute_error);
- EXC_TRANSLATE(mask_error);
-}
-
-#endif // USE_BOOST_PYTHON
-
-#ifdef TEST
-
-int main(int argc, char *argv[])
-{
- ledger::dump_value_expr(std::cout, ledger::parse_value_expr(argv[1]));
- std::cout << std::endl;
-}
-
-#endif // TEST