diff options
author | John Wiegley <johnw@newartisans.com> | 2008-08-05 13:17:04 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2008-08-05 18:05:49 -0400 |
commit | f6f4a46cf5b14f9a2170cd6475958efbf320caec (patch) | |
tree | 05bc1defcdebc201de3dd10477483d906a842821 /src/op.cc | |
parent | b7970b29855563e4c67f85af8b31233eda80c22a (diff) | |
download | fork-ledger-f6f4a46cf5b14f9a2170cd6475958efbf320caec.tar.gz fork-ledger-f6f4a46cf5b14f9a2170cd6475958efbf320caec.tar.bz2 fork-ledger-f6f4a46cf5b14f9a2170cd6475958efbf320caec.zip |
Moved around most of the files so that source code is in src/, documentation
is in doc/, etc.
Diffstat (limited to 'src/op.cc')
-rw-r--r-- | src/op.cc | 1130 |
1 files changed, 1130 insertions, 0 deletions
diff --git a/src/op.cc b/src/op.cc new file mode 100644 index 00000000..b412c47f --- /dev/null +++ b/src/op.cc @@ -0,0 +1,1130 @@ +/* + * 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. + */ + +#include "op.h" +#include "scope.h" +#include "binary.h" + +namespace ledger { + +#if 0 +void expr_t::op_t::compute(value_t& result, + const details_t& details, + ptr_op_t context) const +{ + try { + switch (kind) { + case INDEX: + throw compute_error("Cannot directly compute an argument index"); + + case VALUE: + result = as_value(); + break; + + case F_NOW: + result = terminus; + break; + + case AMOUNT: + if (details.xact) { + if (xact_has_xdata(*details.xact) && + xact_xdata_(*details.xact).dflags & XACT_COMPOUND) + result = xact_xdata_(*details.xact).value; + 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 PRICE: + if (details.xact) { + bool set = false; + if (xact_has_xdata(*details.xact)) { + xact_xdata_t& xdata(xact_xdata_(*details.xact)); + if (xdata.dflags & XACT_COMPOUND) { + result = xdata.value.value(); + set = true; + } + } + if (! set) { + optional<amount_t> value = details.xact->amount.value(); + if (value) + result = *value; + else + result = 0L; + } + } + else if (details.account && account_has_xdata(*details.account)) { + result = account_xdata(*details.account).value.value(); + } + else { + result = 0L; + } + break; + + case COST: + if (details.xact) { + bool set = false; + if (xact_has_xdata(*details.xact)) { + xact_xdata_t& xdata(xact_xdata_(*details.xact)); + if (xdata.dflags & XACT_COMPOUND) { + result = xdata.value.cost(); + 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 && xact_has_xdata(*details.xact)) + result = xact_xdata_(*details.xact).total; + else if (details.account && account_has_xdata(*details.account)) + result = account_xdata(*details.account).total; + else + result = 0L; + break; + case PRICE_TOTAL: + if (details.xact && xact_has_xdata(*details.xact)) + result = xact_xdata_(*details.xact).total.value(); + else if (details.account && account_has_xdata(*details.account)) + result = account_xdata(*details.account).total.value(); + else + result = 0L; + break; + case COST_TOTAL: + if (details.xact && xact_has_xdata(*details.xact)) + result = xact_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 (value_expr::amount_expr.get()) + value_expr::amount_expr->compute(result, details, context); + else + result = 0L; + break; + case TOTAL_EXPR: + if (value_expr::total_expr.get()) + value_expr::total_expr->compute(result, details, context); + else + result = 0L; + break; + + case DATE: + if (details.xact && xact_has_xdata(*details.xact) && + is_valid(xact_xdata_(*details.xact).date)) + result = xact_xdata_(*details.xact).date; + else if (details.xact) + result = details.xact->date(); + else if (details.entry) + result = details.entry->date(); + else + result = terminus; + break; + + case ACT_DATE: + if (details.xact && xact_has_xdata(*details.xact) && + is_valid(xact_xdata_(*details.xact).date)) + result = xact_xdata_(*details.xact).date; + else if (details.xact) + result = details.xact->actual_date(); + else if (details.entry) + result = details.entry->actual_date(); + else + result = terminus; + break; + + case EFF_DATE: + if (details.xact && xact_has_xdata(*details.xact) && + is_valid(xact_xdata_(*details.xact).date)) + result = xact_xdata_(*details.xact).date; + else if (details.xact) + result = details.xact->effective_date(); + else if (details.entry) + result = details.entry->effective_date(); + else + result = terminus; + break; + + case CLEARED: + if (details.xact) + result = details.xact->state == xact_t::CLEARED; + else + result = false; + break; + case PENDING: + if (details.xact) + result = details.xact->state == xact_t::PENDING; + else + result = false; + break; + + case REAL: + if (details.xact) + result = ! (details.xact->has_flags(XACT_VIRTUAL)); + else + result = true; + break; + + case ACTUAL: + if (details.xact) + result = ! (details.xact->has_flags(XACT_AUTO)); + else + result = true; + break; + + case INDEX: + if (details.xact && xact_has_xdata(*details.xact)) + result = long(xact_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 && xact_has_xdata(*details.xact)) + result = long(xact_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_PRICE: { + long arg_index = 0; + ptr_op_t expr = find_leaf(context, 0, arg_index); + expr->compute(result, details, context); + result = result.value(); + break; + } + + case F_DATE: { + long arg_index = 0; + ptr_op_t expr = find_leaf(context, 0, arg_index); + expr->compute(result, details, context); + result = result.as_datetime(); + break; + } + + case F_DATECMP: { + long arg_index = 0; + ptr_op_t expr = find_leaf(context, 0, arg_index); + expr->compute(result, details, context); + result = result.as_datetime(); + if (! result) + break; + + arg_index = 0; + expr = find_leaf(context, 1, arg_index); + value_t moment; + expr->compute(moment, details, context); + if (moment.is_type(value_t::DATETIME)) { + result.cast(value_t::INTEGER); + moment.cast(value_t::INTEGER); + result -= moment; + } else { + add_error_context(expr_context(expr)); + throw compute_error("Invalid date passed to datecmp(value,date)"); + } + break; + } + + case F_YEAR: + case F_MONTH: + case F_DAY: { + long arg_index = 0; + ptr_op_t expr = find_leaf(context, 0, arg_index); + expr->compute(result, details, context); + + if (! result.is_type(value_t::DATETIME)) { + add_error_context(expr_context(expr)); + throw compute_error("Invalid date passed to year|month|day(date)"); + } + + const date_t& moment(result.as_date()); + switch (kind) { + case F_YEAR: + result = (long)moment.year(); + break; + case F_MONTH: + result = (long)moment.month(); + break; + case F_DAY: + result = (long)moment.day(); + break; + default: + break; + } + break; + } + + case F_ARITH_MEAN: { + long arg_index = 0; + ptr_op_t expr = find_leaf(context, 0, arg_index); + if (details.xact && xact_has_xdata(*details.xact)) { + expr->compute(result, details, context); + result /= amount_t(long(xact_xdata_(*details.xact).index + 1)); + } + else if (details.account && account_has_xdata(*details.account) && + account_xdata(*details.account).total_count) { + expr->compute(result, details, context); + 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), context); + break; + + case F_ABS: { + long arg_index = 0; + ptr_op_t expr = find_leaf(context, 0, arg_index); + expr->compute(result, details, context); + result.abs(); + break; + } + + case F_ROUND: { + long arg_index = 0; + ptr_op_t expr = find_leaf(context, 0, arg_index); + expr->compute(result, details, context); + result.round(); + break; + } + + case F_COMMODITY: { + long arg_index = 0; + ptr_op_t expr = find_leaf(context, 0, arg_index); + expr->compute(result, details, context); + if (! result.is_type(value_t::AMOUNT)) { + add_error_context(expr_context(expr)); + throw compute_error("Argument to commodity() must be a commoditized amount"); + } + amount_t temp("1"); + temp.set_commodity(result.as_amount().commodity()); + result = temp; + break; + } + + case F_SET_COMMODITY: { + long arg_index = 0; + ptr_op_t expr = find_leaf(context, 0, arg_index); + value_t temp; + expr->compute(temp, details, context); + + arg_index = 0; + expr = find_leaf(context, 1, arg_index); + expr->compute(result, details, context); + if (! result.is_type(value_t::AMOUNT)) { + add_error_context(expr_context(expr)); + throw compute_error("Second argument to set_commodity() must be a commoditized amount"); + } + amount_t one("1"); + one.set_commodity(result.as_amount().commodity()); + result = one; + + result *= temp; + break; + } + + case F_QUANTITY: { + long arg_index = 0; + ptr_op_t expr = find_leaf(context, 0, arg_index); + expr->compute(result, details, context); + + const balance_t * bal = NULL; + switch (result.type()) { + case value_t::BALANCE_PAIR: + bal = &(result.as_balance_pair().quantity()); + // fall through... + + case value_t::BALANCE: + if (! bal) + bal = &result.as_balance(); + + if (bal->amounts.size() < 2) { + result.cast(value_t::AMOUNT); + } else { + value_t temp; + for (balance_t::amounts_map::value_type pair, bal->amounts) { + amount_t x = pair.second; + x.clear_commodity(); + temp += x; + } + result = temp; + assert(temp.is_type(value_t::AMOUNT)); + } + // fall through... + + case value_t::AMOUNT: + result.as_amount_lval().clear_commodity(); + break; + + default: + break; + } + break; + } + + case O_ARG: { + long arg_index = 0; + assert(left()->kind == INDEX); + ptr_op_t expr = find_leaf(context, left()->as_long(), arg_index); + if (expr) + expr->compute(result, details, context); + else + result = 0L; + break; + } + + case O_COMMA: + if (! left()) { + add_error_context(expr_context(*this)); + throw compute_error("Comma operator missing left operand"); + } + if (! right()) { + add_error_context(expr_context(*this)); + throw compute_error("Comma operator missing right operand"); + } + right()->compute(result, details, context); + break; + + case O_DEF: + result = 0L; + break; + + case O_REF: { + assert(left()); + if (right()) { + value_expr args(reduce_leaves(right(), details, context)); + left()->compute(result, details, args.get()); + } else { + left()->compute(result, details, context); + } + break; + } + + case F_VALUE: { + long arg_index = 0; + ptr_op_t expr = find_leaf(context, 0, arg_index); + expr->compute(result, details, context); + + arg_index = 0; + expr = find_leaf(context, 1, arg_index); + value_t moment; + expr->compute(moment, details, context); + if (! moment.is_type(value_t::DATETIME)) { + add_error_context(expr_context(expr)); + throw compute_error("Invalid date passed to P(value,date)"); + } + result = result.value(moment.as_datetime()); + break; + } + + case O_NOT: + left()->compute(result, details, context); + if (result.strip_annotations()) + result = false; + else + result = true; + break; + + case O_QUES: { + assert(left()); + assert(right()); + assert(right()->kind == O_COL); + left()->compute(result, details, context); + if (result.strip_annotations()) + right()->left()->compute(result, details, context); + else + right()->right()->compute(result, details, context); + break; + } + + case O_AND: + assert(left()); + assert(right()); + left()->compute(result, details, context); + result = result.strip_annotations(); + if (result) + right()->compute(result, details, context); + break; + + case O_OR: + assert(left()); + assert(right()); + left()->compute(result, details, context); + if (! result.strip_annotations()) + right()->compute(result, details, context); + break; + + case O_NEQ: + 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, context); + right()->compute(result, details, context); + switch (kind) { + case O_NEQ: result = temp != result; break; + 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(false); break; + } + break; + } + + case O_NEG: + assert(left()); + left()->compute(result, details, context); + result.negate(); + break; + + case O_ADD: + case O_SUB: + case O_MUL: + case O_DIV: { + assert(left()); + assert(right()); + value_t temp; + right()->compute(temp, details, context); + left()->compute(result, details, context); + 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(false); break; + } + break; + } + + case O_PERC: { + assert(left()); + result = "100.0%"; + value_t temp; + left()->compute(temp, details, context); + result *= temp; + break; + } + + case LAST: + default: + assert(false); + break; + } + } + catch (const std::exception& err) { + add_error_context(expr_context(*this)); + throw err; + } +} +#endif + +expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope) +{ + switch (kind) { + case IDENT: + if (ptr_op_t def = scope.lookup(as_ident())) { +#if 1 + return def; +#else + // jww (2008-08-02): Aren't definitions compiled when they go in? + // Would recompiling here really add any benefit? + return def->compile(scope); +#endif + } + return this; + + default: + break; + } + + if (kind < TERMINALS) + return this; + + ptr_op_t lhs(left()->compile(scope)); + ptr_op_t rhs(kind > UNARY_OPERATORS ? right()->compile(scope) : ptr_op_t()); + + if (lhs == left() && (! rhs || rhs == right())) + return this; + + ptr_op_t intermediate(copy(lhs, rhs)); + + if (lhs->is_value() && (! rhs || rhs->is_value())) + return wrap_value(intermediate->calc(scope)); + + return intermediate; +} + +value_t expr_t::op_t::calc(scope_t& scope) +{ + switch (kind) { + case VALUE: + return as_value(); + + case IDENT: +#if 0 + if (ptr_op_t reference = compile(scope)) { + if (reference != this) + return reference->calc(scope); + } +#endif + throw_(calc_error, "Unknown identifier '" << as_ident() << "'"); + + case FUNCTION: { + // Evaluating a FUNCTION is the same as calling it directly; this happens + // when certain functions-that-look-like-variables (such as "amount") are + // resolved. + call_scope_t call_args(scope); + return as_function()(call_args); + } + + case O_CALL: { + call_scope_t call_args(scope); + + if (right()) + call_args.set_args(right()->calc(scope)); + + ptr_op_t func = left(); + string name; + +#if 0 + // The expression must be compiled beforehand in order to resolve this + // into a function. + if (func->kind == IDENT) { + name = func->as_ident(); + ptr_op_t def = func->compile(scope); + if (def == func) + throw_(calc_error, + "Calling unknown function '" << name << "'"); + func = def; + } +#endif + + if (func->kind != FUNCTION) + throw_(calc_error, "Calling non-function"); + + return func->as_function()(call_args); + } + + case O_MATCH: + assert(right()->is_mask()); + return right()->as_mask().match(left()->calc(scope).to_string()); + + case INDEX: { + const call_scope_t& args(downcast<const call_scope_t>(scope)); + + if (as_index() < args.size()) + return args[as_index()]; + else + throw_(calc_error, "Reference to non-existing argument " << as_index()); + break; + } + + case O_NEQ: + return left()->calc(scope) != right()->calc(scope); + case O_EQ: + return left()->calc(scope) == right()->calc(scope); + case O_LT: + return left()->calc(scope) < right()->calc(scope); + case O_LTE: + return left()->calc(scope) <= right()->calc(scope); + case O_GT: + return left()->calc(scope) > right()->calc(scope); + case O_GTE: + return left()->calc(scope) >= right()->calc(scope); + + case O_ADD: + return left()->calc(scope) + right()->calc(scope); + case O_SUB: + return left()->calc(scope) - right()->calc(scope); + case O_MUL: + return left()->calc(scope) * right()->calc(scope); + case O_DIV: + return left()->calc(scope) / right()->calc(scope); + + case O_NEG: + assert(! right()); + return left()->calc(scope).negate(); + + case O_NOT: + assert(! right()); + return ! left()->calc(scope); + + case O_AND: + return ! left()->calc(scope) ? value_t(false) : right()->calc(scope); + + case O_OR: + if (value_t temp = left()->calc(scope)) + return temp; + else + return right()->calc(scope); + + case O_COMMA: { + value_t result(left()->calc(scope)); + + ptr_op_t next = right(); + while (next) { + ptr_op_t value_op; + if (next->kind == O_COMMA /* || next->kind == O_UNION */) { + value_op = next->left(); + next = next->right(); + } else { + value_op = next; + next = NULL; + } + + result.push_back(value_op->calc(scope)); + } + return result; + } + + case LAST: + default: + assert(false); + break; + } + + return NULL_VALUE; +} + +bool expr_t::op_t::print(std::ostream& out, print_context_t& context) const +{ + bool found = false; + + if (context.start_pos && this == context.op_to_find) { + *context.start_pos = static_cast<unsigned long>(out.tellp()) - 1; + found = true; + } + + string symbol; + + switch (kind) { + case VALUE: { + as_value().print(out, context.relaxed); + break; + } + + case IDENT: + out << as_ident(); + break; + + case FUNCTION: + out << "<FUNCTION>"; + break; + + case INDEX: + out << '@' << as_index(); + break; + + case O_NOT: + out << "!"; + if (left() && left()->print(out, context)) + found = true; + break; + case O_NEG: + out << "-"; + if (left() && left()->print(out, context)) + found = true; + break; + + case O_ADD: + out << "("; + if (left() && left()->print(out, context)) + found = true; + out << " + "; + if (right() && right()->print(out, context)) + found = true; + out << ")"; + break; + case O_SUB: + out << "("; + if (left() && left()->print(out, context)) + found = true; + out << " - "; + if (right() && right()->print(out, context)) + found = true; + out << ")"; + break; + case O_MUL: + out << "("; + if (left() && left()->print(out, context)) + found = true; + out << " * "; + if (right() && right()->print(out, context)) + found = true; + out << ")"; + break; + case O_DIV: + out << "("; + if (left() && left()->print(out, context)) + found = true; + out << " / "; + if (right() && right()->print(out, context)) + found = true; + out << ")"; + break; + + case O_NEQ: + out << "("; + if (left() && left()->print(out, context)) + found = true; + out << " != "; + if (right() && right()->print(out, context)) + found = true; + out << ")"; + break; + case O_EQ: + out << "("; + if (left() && left()->print(out, context)) + found = true; + out << " == "; + if (right() && right()->print(out, context)) + found = true; + out << ")"; + break; + case O_LT: + out << "("; + if (left() && left()->print(out, context)) + found = true; + out << " < "; + if (right() && right()->print(out, context)) + found = true; + out << ")"; + break; + case O_LTE: + out << "("; + if (left() && left()->print(out, context)) + found = true; + out << " <= "; + if (right() && right()->print(out, context)) + found = true; + out << ")"; + break; + case O_GT: + out << "("; + if (left() && left()->print(out, context)) + found = true; + out << " > "; + if (right() && right()->print(out, context)) + found = true; + out << ")"; + break; + case O_GTE: + out << "("; + if (left() && left()->print(out, context)) + found = true; + out << " >= "; + if (right() && right()->print(out, context)) + found = true; + out << ")"; + break; + + case O_AND: + out << "("; + if (left() && left()->print(out, context)) + found = true; + out << " & "; + if (right() && right()->print(out, context)) + found = true; + out << ")"; + break; + case O_OR: + out << "("; + if (left() && left()->print(out, context)) + found = true; + out << " | "; + if (right() && right()->print(out, context)) + found = true; + out << ")"; + break; + + case O_COMMA: + if (left() && left()->print(out, context)) + found = true; + out << ", "; + if (right() && right()->print(out, context)) + found = true; + break; + + case O_CALL: + if (left() && left()->print(out, context)) + found = true; + out << "("; + if (right() && right()->print(out, context)) + found = true; + out << ")"; + break; + + case O_MATCH: + out << '/'; + if (left() && left()->print(out, context)) + found = true; + out << "/ =~ "; + if (right() && right()->print(out, context)) + found = true; + break; + + case LAST: + default: + assert(false); + break; + } + + if (! symbol.empty()) { + if (amount_t::current_pool->find(symbol)) + out << '@'; + out << symbol; + } + + if (context.end_pos && this == context.op_to_find) + *context.end_pos = static_cast<unsigned long>(out.tellp()) - 1; + + return found; +} + +void expr_t::op_t::dump(std::ostream& out, const int depth) const +{ + out.setf(std::ios::left); + out.width(10); + out << this; + + for (int i = 0; i < depth; i++) + out << " "; + + switch (kind) { + case VALUE: + out << "VALUE - " << as_value(); + break; + + case IDENT: + out << "IDENT - " << as_ident(); + break; + + case INDEX: + out << "INDEX - " << as_index(); + break; + + case FUNCTION: + out << "FUNCTION"; + break; + + case O_CALL: out << "O_CALL"; break; + case O_MATCH: out << "O_MATCH"; break; + + case O_NOT: out << "O_NOT"; break; + case O_NEG: out << "O_NEG"; break; + + case O_ADD: out << "O_ADD"; break; + case O_SUB: out << "O_SUB"; break; + case O_MUL: out << "O_MUL"; break; + case O_DIV: out << "O_DIV"; break; + + case O_NEQ: out << "O_NEQ"; break; + case O_EQ: out << "O_EQ"; break; + case O_LT: out << "O_LT"; break; + case O_LTE: out << "O_LTE"; break; + case O_GT: out << "O_GT"; break; + case O_GTE: out << "O_GTE"; break; + + case O_AND: out << "O_AND"; break; + case O_OR: out << "O_OR"; break; + + case O_COMMA: out << "O_COMMA"; break; + + case LAST: + default: + assert(false); + break; + } + + out << " (" << refc << ')' << std::endl; + + if (kind > TERMINALS) { + if (left()) { + left()->dump(out, depth + 1); + if (right()) + right()->dump(out, depth + 1); + } else { + assert(! right()); + } + } +} + +void expr_t::op_t::read(const char *& data) +{ +#if 0 + if (! read_bool(data)) + return expr_t::ptr_op_t(); + + expr_t::op_t::kind_t kind; + read_number(data, kind); + + expr_t::ptr_op_t expr = new expr_t::op_t(kind); + + if (kind > expr_t::op_t::TERMINALS) + expr->set_left(read_value_expr(data)); + + switch (expr->kind) { + case expr_t::op_t::INDEX: { + long temp; + read_long(data, temp); + expr->set_index(temp); + break; + } + case expr_t::op_t::VALUE: { + value_t temp; + read_value(data, temp); + expr->set_value(temp); + break; + } + + case expr_t::op_t::MASK: + if (read_bool(data)) + read_mask(data, expr->as_mask_lval()); + break; + + default: + if (kind > expr_t::op_t::TERMINALS) + expr->set_right(read_value_expr(data)); + break; + } + + return expr; +#endif +} + +void expr_t::op_t::write(std::ostream& out) const +{ +#if 0 + if (! expr) { + write_bool(out, false); + return; + } + + write_bool(out, true); + write_number(out, expr->kind); + + if (expr->kind > expr_t::op_t::TERMINALS) + write_value_expr(out, expr->left()); + + switch (expr->kind) { + case expr_t::op_t::INDEX: + write_long(out, expr->as_index()); + break; + case expr_t::op_t::IDENT: + write_long(out, expr->as_ident()); + break; + case expr_t::op_t::VALUE: + write_value(out, expr->as_value()); + break; + + case expr_t::op_t::MASK: + if (expr->as_mask()) { + write_bool(out, true); + write_mask(out, expr->as_mask()); + } else { + write_bool(out, false); + } + break; + + default: + if (expr->kind > expr_t::op_t::TERMINALS) + write_value_expr(out, expr->right()); + break; + } +#endif +} + +#if 0 +class op_predicate : public noncopyable +{ + ptr_op_t op; + + 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(); + } +}; + +#endif + +} // namespace ledger |