diff options
-rw-r--r-- | expr.cc | 10 | ||||
-rw-r--r-- | expr.h | 2 | ||||
-rw-r--r-- | format.cc | 34 | ||||
-rw-r--r-- | format.h | 3 | ||||
-rw-r--r-- | op.cc | 33 | ||||
-rw-r--r-- | op.h | 9 | ||||
-rw-r--r-- | option.cc | 10 | ||||
-rw-r--r-- | parser.cc | 21 | ||||
-rw-r--r-- | predicate.h | 2 | ||||
-rw-r--r-- | report.cc | 10 | ||||
-rw-r--r-- | report.h | 15 | ||||
-rw-r--r-- | session.cc | 4 | ||||
-rw-r--r-- | textual.cc | 19 | ||||
-rw-r--r-- | token.cc | 13 | ||||
-rw-r--r-- | token.h | 1 | ||||
-rw-r--r-- | walk.cc | 39 | ||||
-rw-r--r-- | walk.h | 26 | ||||
-rw-r--r-- | xact.cc | 18 |
18 files changed, 133 insertions, 136 deletions
@@ -125,11 +125,6 @@ value_t expr_t::calc(scope_t& scope) return NULL_VALUE; } -value_t expr_t::calc(scope_t& scope) const -{ - return ptr.get() ? ptr->calc(scope) : NULL_VALUE; -} - bool expr_t::is_constant() const { return ptr.get() && ptr->is_value(); @@ -165,11 +160,6 @@ void expr_t::dump(std::ostream& out) const if (ptr) ptr->dump(out, 0); } -void expr_t::read(std::ostream& in) -{ - if (ptr) ptr->read(in); -} - void expr_t::read(const char *& data) { if (ptr) ptr->read(data); @@ -107,8 +107,6 @@ public: void print(std::ostream& out, scope_t& scope) const; void dump(std::ostream& out) const; - - void read(std::ostream& in); void read(const char *& data); void write(std::ostream& out) const; @@ -90,7 +90,6 @@ format_t::element_t * format_t::parse_elements(const string& fmt) // T: TOTAL // N: NOTE // n: OPT_NOTE - // |: SPACER // _: DEPTH_SPACER // // xB: XACT_BEG_POS @@ -173,6 +172,11 @@ format_t::element_t * format_t::parse_elements(const string& fmt) current->chars = "%"; break; + case '|': + current->type = element_t::STRING; + current->chars = " "; + break; + case '(': case '[': { std::istringstream str(p); @@ -183,11 +187,16 @@ format_t::element_t * format_t::parse_elements(const string& fmt) break; } - default: - current->type = element_t::EXPR; + default: { + current->type = element_t::EXPR; + char buf[2]; + buf[0] = *p; + buf[1] = '\0'; + current->chars = buf; current->expr.parse(string("fmt_") + *p); break; } + } } if (q != buf) { @@ -211,9 +220,9 @@ namespace { } } -void format_t::format(std::ostream& out_str, scope_t& scope) const +void format_t::format(std::ostream& out_str, scope_t& scope) { - for (const element_t * elem = elements.get(); elem; elem = elem->next.get()) { + for (element_t * elem = elements.get(); elem; elem = elem->next.get()) { std::ostringstream out; string name; bool ignore_max_width = false; @@ -232,7 +241,16 @@ void format_t::format(std::ostream& out_str, scope_t& scope) const break; case element_t::EXPR: - out << elem->expr.calc(scope); + try { + if (elem->max_width == 0) + elem->expr.calc(scope).dump(out, elem->min_width); + else + out << truncate(elem->expr.calc(scope).as_string(), + elem->max_width); + } + catch (const calc_error&) { + out << (string("%") + elem->chars); + } break; #if 0 @@ -622,10 +640,6 @@ void format_t::format(std::ostream& out_str, scope_t& scope) const } break; - case element_t::SPACER: - out << " "; - break; - case element_t::DEPTH_SPACER: for (const account_t * acct = details.account; acct; @@ -20,7 +20,6 @@ class format_t : public noncopyable STRING, EXPR, #if 0 - SPACER, DEPTH_SPACER #endif }; @@ -92,7 +91,7 @@ public: format_string = _format; } - void format(std::ostream& out, scope_t& scope) const; + void format(std::ostream& out, scope_t& scope); void dump(std::ostream& out) const { for (const element_t * elem = elements.get(); @@ -640,8 +640,8 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope) #if 1 return def; #else - // Aren't definitions compiled when they go in? Would - // recompiling here really add any benefit? + // jww (2008-08-02): Aren't definitions compiled when they go in? + // Would recompiling here really add any benefit? return def->compile(scope); #endif } @@ -655,7 +655,7 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope) return this; ptr_op_t lhs(left()->compile(scope)); - ptr_op_t rhs(right() ? right()->compile(scope) : ptr_op_t()); + ptr_op_t rhs(kind > UNARY_OPERATORS ? right()->compile(scope) : ptr_op_t()); if (lhs == left() && (! rhs || rhs == right())) return this; @@ -675,10 +675,12 @@ value_t expr_t::op_t::calc(scope_t& scope) 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: { @@ -698,6 +700,9 @@ value_t expr_t::op_t::calc(scope_t& 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); @@ -706,6 +711,7 @@ value_t expr_t::op_t::calc(scope_t& scope) "Calling unknown function '" << name << "'"); func = def; } +#endif if (func->kind != FUNCTION) throw_(calc_error, "Calling non-function"); @@ -713,8 +719,12 @@ value_t expr_t::op_t::calc(scope_t& scope) return func->as_function()(call_args); } + case O_MATCH: + assert(left()->is_mask()); + return left()->as_mask().match(right()->calc(scope).to_string()); + case INDEX: { - call_scope_t args(scope); + const call_scope_t& args(downcast<const call_scope_t>(scope)); if (as_index() < args.size()) return args[as_index()]; @@ -755,6 +765,7 @@ value_t expr_t::op_t::calc(scope_t& 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; @@ -957,6 +968,15 @@ bool expr_t::op_t::print(std::ostream& out, print_context_t& context) const 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); @@ -1002,6 +1022,7 @@ void expr_t::op_t::dump(std::ostream& out, const int depth) const 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; @@ -1042,10 +1063,6 @@ void expr_t::op_t::dump(std::ostream& out, const int depth) const } } -void expr_t::op_t::read(std::ostream& in) -{ -} - void expr_t::op_t::read(const char *& data) { #if 0 @@ -75,6 +75,10 @@ public: // Binary operators O_NOT, + O_NEG, + + UNARY_OPERATORS, + O_EQ, O_NEQ, O_LT, @@ -85,7 +89,6 @@ public: O_AND, O_OR, - O_NEG, O_ADD, O_SUB, O_MUL, @@ -97,6 +100,9 @@ public: O_COMMA, O_CALL, + O_MATCH, + + BINARY_OPERATORS, OPERATORS, @@ -288,7 +294,6 @@ public: bool print(std::ostream& out, print_context_t& context) const; void dump(std::ostream& out, const int depth) const; - void read(std::ostream& in); void read(const char *& data); void write(std::ostream& out) const; @@ -62,16 +62,16 @@ namespace { op_bool_tuple find_option(scope_t& scope, const char letter) { char buf[10]; - std::strcpy(buf, "option_"); - buf[7] = letter; - buf[8] = '\0'; + std::strcpy(buf, "opt_"); + buf[4] = letter; + buf[5] = '\0'; expr_t::ptr_op_t op = scope.lookup(buf); if (op) return op_bool_tuple(op, false); - buf[8] = '_'; - buf[9] = '\0'; + buf[5] = '_'; + buf[6] = '\0'; return op_bool_tuple(scope.lookup(buf), true); } @@ -49,22 +49,15 @@ expr_t::parser_t::parse_value_term(std::istream& in, case token_t::MASK: { // A /mask/ is just a shorthand for calling match(). - node = new op_t(op_t::O_CALL); - - ptr_op_t ident = new op_t(op_t::IDENT); - ident->set_ident("match"); - node->set_left(ident); - - ptr_op_t args = new op_t(op_t::O_COMMA); - node->set_right(args); + node = new op_t(op_t::O_MATCH); ptr_op_t mask = new op_t(op_t::MASK); mask->set_mask(tok.value.as_string()); - ident = new op_t(op_t::IDENT); + ptr_op_t ident = new op_t(op_t::IDENT); - args->set_left(mask); - args->set_right(ident); + node->set_left(mask); + node->set_right(ident); switch (tok.flags()) { case TOKEN_SHORT_ACCOUNT_MASK: @@ -301,6 +294,12 @@ expr_t::parser_t::parse_logic_expr(std::istream& in, case token_t::NEQUAL: kind = op_t::O_NEQ; break; + case token_t::MATCH: + kind = op_t::O_MATCH; + assert(node->kind == op_t::O_MATCH); + node = node->left(); + assert(node->kind == op_t::MASK); + break; case token_t::LESS: kind = op_t::O_LT; break; diff --git a/predicate.h b/predicate.h index c9ceb7ae..624d3d65 100644 --- a/predicate.h +++ b/predicate.h @@ -59,7 +59,7 @@ public: TRACE_DTOR(item_predicate); } - bool operator()(T& item) const { + bool operator()(T& item) { return ! predicate || predicate.calc(item).strip_annotations(); } }; @@ -557,9 +557,9 @@ void print_entry(std::ostream& out, const entry_base_t& entry_base, #endif } -bool disp_subaccounts_p(const account_t& account, - const optional<item_predicate<account_t> >& disp_pred, - const account_t *& to_show) +bool disp_subaccounts_p(const account_t& account, + item_predicate<account_t>& disp_pred, + const account_t *& to_show) { bool display = false; #if 0 @@ -596,7 +596,7 @@ bool disp_subaccounts_p(const account_t& account, } bool display_account(const account_t& account, - const optional<item_predicate<account_t> >& disp_pred) + item_predicate<account_t>& disp_pred) { // Never display an account that has already been displayed. if (account_has_xdata(account) && @@ -615,7 +615,7 @@ bool display_account(const account_t& account, return true; return (! account_to_show && - (! disp_pred || (*disp_pred)(const_cast<account_t&>(account)))); + disp_pred(const_cast<account_t&>(account))); } void format_accounts::operator()(account_t& account) @@ -351,17 +351,12 @@ class format_entries : public format_xacts void print_entry(std::ostream& out, const entry_base_t& entry, const string& prefix = ""); -bool disp_subaccounts_p(const account_t& account, - const optional<item_predicate<account_t> >& disp_pred, - const account_t *& to_show); +bool disp_subaccounts_p(const account_t& account, + item_predicate<account_t>& disp_pred, + const account_t *& to_show); -inline bool disp_subaccounts_p(const account_t& account) { - const account_t * temp; - return disp_subaccounts_p(account, none, temp); -} - -bool display_account(const account_t& account, - const optional<item_predicate<account_t> >& disp_pred); +bool display_account(const account_t& account, + item_predicate<account_t>& disp_pred); class format_accounts : public item_handler<account_t> { @@ -68,10 +68,10 @@ void release_session_context() session_t::session_t() : register_format - ("%D %-.20P %-.22A %12.67t %!12.80T\n%/" + ("%-.10D %-.20P %-.22A %12.67t %!12.80T\n%/" "%32|%-.22A %12.67t %!12.80T\n"), wide_register_format - ("%D %-.35P %-.38A %22.108t %!22.132T\n%/" + ("%-.10D %-.35P %-.38A %22.108t %!22.132T\n%/" "%48|%-.38A %22.108t %!22.132T\n"), print_format ("\n%d %Y%C%P\n %-34W %12o%n\n%/ %-34W %12o%n\n"), @@ -5,6 +5,8 @@ #include "textual.h" #include "expr.h" #include "parser.h" +#include "session.h" +#include "option.h" #include "acconf.h" #define TIMELOG_SUPPORT 1 @@ -298,6 +300,8 @@ xact_t * parse_xact(char * line, account_t * account, try { #if 0 + // jww (2008-08-02): This data must be saved so that it can be + // restored on "print". unsigned long beg = static_cast<unsigned long>(in.tellg()); #endif @@ -825,9 +829,7 @@ unsigned int textual_parser_t::parse(std::istream& in, if (p) *p++ = '\0'; } -#if 0 - process_option(config_options, line + 2, p); -#endif + process_option(line + 2, session, p); break; } @@ -932,11 +934,8 @@ unsigned int textual_parser_t::parse(std::istream& in, } } else if (word == "def") { -#if 0 - if (! expr_t::global_scope.get()) - init_value_expr(); - parse_value_definition(p); -#endif + expr_t def(p); + def.compile(session); // causes definitions to be established } break; } @@ -1064,9 +1063,7 @@ void write_textual_journal(journal_t& journal, while (! in.eof()) { entry_base_t * base = NULL; if (el != journal.entries.end() && pos == (*el)->beg_pos) { -#if 0 - hdr_fmt.format(out, details_t(**el)); -#endif + hdr_fmt.format(out, **el); base = *el++; } else if (al != journal.auto_entries.end() && pos == (*al)->beg_pos) { @@ -148,6 +148,10 @@ void expr_t::token_t::next(std::istream& in, const unsigned int pflags) in.get(c); kind = KW_AND; break; + case '|': + in.get(c); + kind = KW_OR; + break; case '(': in.get(c); @@ -300,6 +304,15 @@ void expr_t::token_t::next(std::istream& in, const unsigned int pflags) case '=': in.get(c); + c = in.peek(); + if (c == '~') { + in.get(c); + symbol[1] = c; + symbol[2] = '\0'; + kind = MATCH; + length = 2; + break; + } kind = EQUAL; break; @@ -61,6 +61,7 @@ struct expr_t::token_t : public noncopyable, public supports_flags<> GREATEREQ, // >= ASSIGN, // = + MATCH, // =~ MINUS, // - PLUS, // + STAR, // * @@ -9,22 +9,21 @@ namespace ledger { template <> bool compare_items<xact_t>::operator()(const xact_t * left, - const xact_t * right) + const xact_t * right) { assert(left); assert(right); -#if 0 xact_xdata_t& lxdata(xact_xdata(*left)); if (! (lxdata.dflags & XACT_SORT_CALC)) { - sort_order.compute(lxdata.sort_value, details_t(*left)); + lxdata.sort_value = sort_order.calc(const_cast<xact_t&>(*left)); lxdata.sort_value.reduce(); lxdata.dflags |= XACT_SORT_CALC; } xact_xdata_t& rxdata(xact_xdata(*right)); if (! (rxdata.dflags & XACT_SORT_CALC)) { - sort_order.compute(rxdata.sort_value, details_t(*right)); + rxdata.sort_value = sort_order.calc(const_cast<xact_t&>(*right)); rxdata.sort_value.reduce(); rxdata.dflags |= XACT_SORT_CALC; } @@ -35,9 +34,6 @@ bool compare_items<xact_t>::operator()(const xact_t * left, "rxdata.sort_value = " << rxdata.sort_value); return lxdata.sort_value < rxdata.sort_value; -#else - return false; -#endif } xact_xdata_t& xact_xdata(const xact_t& xact) @@ -382,8 +378,9 @@ void changed_value_xacts::output_diff(const date_t& date) compute_total(cur_bal, details_t(*last_xact)); #endif cur_bal.round(); - // jww (2008-04-24): What does this do? + #if 0 + // jww (2008-04-24): What does this do? xact_xdata(*last_xact).date = 0; #endif @@ -634,10 +631,7 @@ void set_code_as_payee::operator()(xact_t& xact) void dow_xacts::flush() { for (int i = 0; i < 7; i++) { - // jww (2008-04-24): What to use here? -#if 0 - start = finish = 0; -#endif + start = finish = date_t(); foreach (xact_t * xact, days_of_the_week[i]) subtotal_xacts::operator()(*xact); subtotal_xacts::report_subtotal("%As"); @@ -681,12 +675,7 @@ void budget_xacts::report_budget_items(const date_t& date) xact_t& xact = *pair.second; DEBUG("ledger.walk.budget", "Reporting budget for " - << xact_account(xact)->fullname()); -#if 0 - // jww (2008-04-24): Need a new debug macro here - DEBUG_TIME("ledger.walk.budget", begin); - DEBUG_TIME("ledger.walk.budget", date); -#endif + << xact_account(xact)->fullname()); entry_temps.push_back(entry_t()); entry_t& entry = entry_temps.back(); @@ -787,12 +776,8 @@ void forecast_xacts::flush() entry.add_xact(&temp); date_t next = (*least).first.increment(begin); -#if 0 - // jww (2008-04-24): Does seconds() here give the total seconds? - if (next < begin || // wraparound - (is_valid(last) && (next - last).seconds() > 365 * 5 * 24 * 3600)) + if (next < begin || (is_valid(last) && (next - last).days() > 365 * 5)) break; -#endif begin = next; item_handler<xact_t>::operator()(temp); @@ -829,23 +814,19 @@ bool compare_items<account_t>::operator()(const account_t * left, assert(left); assert(right); -#if 0 account_xdata_t& lxdata(account_xdata(*left)); if (! (lxdata.dflags & ACCOUNT_SORT_CALC)) { - sort_order.compute(lxdata.sort_value, details_t(*left)); + lxdata.sort_value = sort_order.calc(const_cast<account_t&>(*left)); lxdata.dflags |= ACCOUNT_SORT_CALC; } account_xdata_t& rxdata(account_xdata(*right)); if (! (rxdata.dflags & ACCOUNT_SORT_CALC)) { - sort_order.compute(rxdata.sort_value, details_t(*right)); + rxdata.sort_value = sort_order.calc(const_cast<account_t&>(*right)); rxdata.dflags |= ACCOUNT_SORT_CALC; } return lxdata.sort_value < rxdata.sort_value; -#else - return false; -#endif } account_xdata_t& account_xdata(const account_t& account) @@ -59,15 +59,7 @@ bool compare_items<T>::operator()(const T * left, const T * right) { assert(left); assert(right); - - value_t left_result; - value_t right_result; -#if 0 - sort_order.compute(left_result, details_t(*left)); - sort_order.compute(right_result, details_t(*right)); -#endif - - return left_result < right_result; + return sort_order.calc(*left) < sort_order.calc(*right); } template <> @@ -434,14 +426,14 @@ class filter_xacts : public item_handler<xact_t> public: filter_xacts(xact_handler_ptr handler, - const expr_t& predicate) + const expr_t& predicate) : item_handler<xact_t>(handler), pred(predicate) { TRACE_CTOR(filter_xacts, "xact_handler_ptr, const value_expr&"); } filter_xacts(xact_handler_ptr handler, - const string& predicate) + const string& predicate) : item_handler<xact_t>(handler), pred(predicate) { TRACE_CTOR(filter_xacts, "xact_handler_ptr, const string&"); @@ -1031,18 +1023,6 @@ public: ////////////////////////////////////////////////////////////////////// -#if 0 -inline void clear_journal_xdata(journal_t& journal) { - clear_xact_xdata xact_cleaner; - walk_entries(journal.entries, xact_cleaner); - - clear_account_xdata acct_cleaner; - walk_accounts(*journal.master, acct_cleaner); -} -#endif - -////////////////////////////////////////////////////////////////////// - class journals_iterator : public noncopyable { ptr_list<journal_t>::iterator journals_i; @@ -79,6 +79,8 @@ namespace { { xact_t& xact(downcast<xact_t>(*scope.parent)); + // jww (2008-08-02): Accept a width here so that we can abbreviate the + // string. string name = xact.account->fullname(); if (xact.has_flags(XACT_VIRTUAL)) { @@ -102,19 +104,25 @@ expr_t::ptr_op_t xact_t::lookup(const string& name) switch (name[0]) { case 'a': if (name[1] == '\0' || name == "amount") - return WRAP_FUNCTOR(bind(get_amount, _1)); + return WRAP_FUNCTOR(get_amount); else if (name == "account") - return WRAP_FUNCTOR(bind(get_account, _1)); + return WRAP_FUNCTOR(get_account); else if (name == "account_base") - return WRAP_FUNCTOR(bind(get_account_base, _1)); + return WRAP_FUNCTOR(get_account_base); break; case 'd': if (name[1] == '\0' || name == "date") - return WRAP_FUNCTOR(bind(get_date, _1)); + return WRAP_FUNCTOR(get_date); + break; + case 'f': + if (name.find("fmt_") == 0) { + if (name == "fmt_A") + return WRAP_FUNCTOR(get_account); + } break; case 'p': if (name[1] == '\0' || name == "payee") - return WRAP_FUNCTOR(bind(get_payee, _1)); + return WRAP_FUNCTOR(get_payee); break; } return entry->lookup(name); |