diff options
author | John Wiegley <johnw@newartisans.com> | 2010-02-05 05:35:14 -0500 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2010-02-05 05:35:14 -0500 |
commit | 547137096051ab985dca6f8e5c7be191b62ccb0c (patch) | |
tree | 2f3a39c4b71b8cb8b232502401e8dd2c8c2247ef /src | |
parent | c6873d32aa121289e87be7eb16ff531c6d468d2a (diff) | |
parent | 69da18cd303b10f9badd542141ffdfd546009508 (diff) | |
download | fork-ledger-547137096051ab985dca6f8e5c7be191b62ccb0c.tar.gz fork-ledger-547137096051ab985dca6f8e5c7be191b62ccb0c.tar.bz2 fork-ledger-547137096051ab985dca6f8e5c7be191b62ccb0c.zip |
Merge branch 'next'
Diffstat (limited to 'src')
-rw-r--r-- | src/account.cc | 2 | ||||
-rw-r--r-- | src/balance.cc | 3 | ||||
-rw-r--r-- | src/chain.cc | 12 | ||||
-rw-r--r-- | src/commodity.cc | 4 | ||||
-rw-r--r-- | src/commodity.h | 8 | ||||
-rw-r--r-- | src/filters.cc | 25 | ||||
-rw-r--r-- | src/item.cc | 49 | ||||
-rw-r--r-- | src/item.h | 10 | ||||
-rw-r--r-- | src/journal.cc | 5 | ||||
-rw-r--r-- | src/output.cc | 9 | ||||
-rw-r--r-- | src/post.cc | 26 | ||||
-rw-r--r-- | src/post.h | 17 | ||||
-rw-r--r-- | src/report.cc | 8 | ||||
-rw-r--r-- | src/report.h | 5 | ||||
-rw-r--r-- | src/textual.cc | 316 | ||||
-rw-r--r-- | src/times.cc | 18 | ||||
-rw-r--r-- | src/value.cc | 2 |
17 files changed, 298 insertions, 221 deletions
diff --git a/src/account.cc b/src/account.cc index e6c7af56..f8729409 100644 --- a/src/account.cc +++ b/src/account.cc @@ -512,7 +512,7 @@ void account_t::xdata_t::details_t::update(post_t& post, if (post.has_flags(POST_VIRTUAL)) posts_virtuals_count++; - if (gather_all) + if (gather_all && post.pos) filenames.insert(post.pos->pathname); date_t date = post.date(); diff --git a/src/balance.cc b/src/balance.cc index 4ff51ffc..4fcc83fa 100644 --- a/src/balance.cc +++ b/src/balance.cc @@ -271,7 +271,8 @@ void balance_t::print(std::ostream& out, if (pair.second) sorted.push_back(&pair.second); - std::stable_sort(sorted.begin(), sorted.end(), compare_amount_commodities()); + std::stable_sort(sorted.begin(), sorted.end(), + commodity_t::compare_by_commodity()); foreach (const amount_t * amount, sorted) { int width; diff --git a/src/chain.cc b/src/chain.cc index 113a71d8..ecb39e0b 100644 --- a/src/chain.cc +++ b/src/chain.cc @@ -158,11 +158,21 @@ post_handler_ptr chain_post_handlers(report_t& report, report.session.journal->master, report.HANDLER(date_).str(), report)); - if (report.HANDLED(account_)) + + if (report.HANDLED(account_)) { handler.reset(new transfer_details(handler, transfer_details::SET_ACCOUNT, report.session.journal->master, report.HANDLER(account_).str(), report)); + } + else if (report.HANDLED(pivot_)) { + string pivot = report.HANDLER(pivot_).str(); + pivot = string("\"") + pivot + ":\" + tag(/" + pivot + "/)"; + handler.reset(new transfer_details(handler, transfer_details::SET_ACCOUNT, + report.session.journal->master, pivot, + report)); + } + if (report.HANDLED(payee_)) handler.reset(new transfer_details(handler, transfer_details::SET_PAYEE, report.session.journal->master, diff --git a/src/commodity.cc b/src/commodity.cc index 79ed77fe..24016830 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -587,8 +587,8 @@ bool commodity_t::valid() const return true; } -bool compare_amount_commodities::operator()(const amount_t * left, - const amount_t * right) const +bool commodity_t::compare_by_commodity::operator()(const amount_t * left, + const amount_t * right) const { commodity_t& leftcomm(left->commodity()); commodity_t& rightcomm(right->commodity()); diff --git a/src/commodity.h b/src/commodity.h index 3370f3f2..d2d8af21 100644 --- a/src/commodity.h +++ b/src/commodity.h @@ -386,6 +386,10 @@ public: bool valid() const; + struct compare_by_commodity { + bool operator()(const amount_t * left, const amount_t * right) const; + }; + #if defined(HAVE_BOOST_SERIALIZATION) private: supports_flags<uint_least16_t> temp_flags; @@ -419,10 +423,6 @@ inline std::ostream& operator<<(std::ostream& out, const commodity_t& comm) { return out; } -struct compare_amount_commodities { - bool operator()(const amount_t * left, const amount_t * right) const; -}; - void to_xml(std::ostream& out, const commodity_t& comm, bool commodity_details = false); diff --git a/src/filters.cc b/src/filters.cc index 0084fac7..2926eb08 100644 --- a/src/filters.cc +++ b/src/filters.cc @@ -793,12 +793,25 @@ void transfer_details::operator()(post_t& post) break; case SET_ACCOUNT: { - std::list<string> account_names; - temp.account->remove_post(&temp); - split_string(substitute.to_string(), ':', account_names); - temp.account = create_temp_account_from_path(account_names, temps, - xact.journal->master); - temp.account->add_post(&temp); + string account_name = substitute.to_string(); + if (! account_name.empty() && + account_name[account_name.length() - 1] != ':') { + account_t * prev_account = temp.account; + temp.account->remove_post(&temp); + + account_name += ':'; + account_name += prev_account->fullname(); + + std::list<string> account_names; + split_string(account_name, ':', account_names); + temp.account = create_temp_account_from_path(account_names, temps, + xact.journal->master); + temp.account->add_post(&temp); + + temp.account->add_flags(prev_account->flags()); + if (prev_account->has_xdata()) + temp.account->xdata().add_flags(prev_account->xdata().flags()); + } break; } diff --git a/src/item.cc b/src/item.cc index f86b8ec8..8d1ba34f 100644 --- a/src/item.cc +++ b/src/item.cc @@ -199,6 +199,9 @@ namespace { value_t get_date(item_t& item) { return item.date(); } + value_t get_actual_date(item_t& item) { + return item.actual_date(); + } value_t get_effective_date(item_t& item) { if (optional<date_t> effective = item.effective_date()) return *effective; @@ -238,11 +241,39 @@ namespace { return false; } - value_t get_tag(call_scope_t& scope) { - in_context_t<item_t> env(scope, "s"); - if (optional<string> value = env->get_tag(env.get<string>(0))) - return string_value(*value); - return string_value(empty_string); + value_t get_tag(call_scope_t& args) { + item_t& item(find_scope<item_t>(args)); + optional<string> str; + + if (args.size() == 1) { + if (args[0].is_string()) + str = item.get_tag(args[0].as_string()); + else if (args[0].is_mask()) + str = item.get_tag(args[0].as_mask()); + else + throw_(std::runtime_error, + _("Expected string or mask for argument 1, but received %1") + << args[0].label()); + } + else if (args.size() == 2) { + if (args[0].is_mask() && args[1].is_mask()) + str = item.get_tag(args[0].to_mask(), args[1].to_mask()); + else + throw_(std::runtime_error, + _("Expected masks for arguments 1 and 2, but received %1 and %2") + << args[0].label() << args[1].label()); + } + else if (args.size() == 0) { + throw_(std::runtime_error, _("Too few arguments to function")); + } + else { + throw_(std::runtime_error, _("Too many arguments to function")); + } + + if (str) + return string_value(*str); + else + return string_value(empty_string); } value_t get_pathname(item_t& item) { @@ -268,6 +299,10 @@ namespace { return item.pos ? long(item.pos->end_line) : 0L; } + value_t get_seq(item_t& item) { + return item.pos ? long(item.pos->sequence) : 0L; + } + value_t get_depth(item_t&) { return 0L; } @@ -319,6 +354,8 @@ expr_t::ptr_op_t item_t::lookup(const symbol_t::kind_t kind, case 'a': if (name == "actual") return WRAP_FUNCTOR(get_wrapper<&get_actual>); + else if (name == "actual_date") + return WRAP_FUNCTOR(get_wrapper<&get_actual_date>); break; case 'b': @@ -388,6 +425,8 @@ expr_t::ptr_op_t item_t::lookup(const symbol_t::kind_t kind, case 's': if (name == "status") return WRAP_FUNCTOR(get_wrapper<&get_status>); + else if (name == "seq") + return WRAP_FUNCTOR(get_wrapper<&get_seq>); break; case 't': @@ -53,8 +53,10 @@ struct position_t std::size_t beg_line; istream_pos_type end_pos; std::size_t end_line; + std::size_t sequence; - position_t() : beg_pos(0), beg_line(0), end_pos(0), end_line(0) { + position_t() + : beg_pos(0), beg_line(0), end_pos(0), end_line(0), sequence(0) { TRACE_CTOR(position_t, ""); } position_t(const position_t& pos) { @@ -72,6 +74,7 @@ struct position_t beg_line = pos.beg_line; end_pos = pos.end_pos; end_line = pos.end_line; + sequence = pos.sequence; } return *this; } @@ -89,6 +92,7 @@ private: ar & beg_line; ar & end_pos; ar & end_line; + ar & sequence; } #endif // HAVE_BOOST_SERIALIZATION }; @@ -169,6 +173,10 @@ public: return *effective; return *_date; } + virtual date_t actual_date() const { + assert(_date); + return *_date; + } virtual optional<date_t> effective_date() const { return _date_eff; } diff --git a/src/journal.cc b/src/journal.cc index 6ebccd66..5aa2e7f7 100644 --- a/src/journal.cc +++ b/src/journal.cc @@ -64,9 +64,8 @@ journal_t::~journal_t() { TRACE_DTOR(journal_t); - // Don't bother unhooking each xact's posts from the - // accounts they refer to, because all accounts are about to - // be deleted. + // Don't bother unhooking each xact's posts from the accounts they refer to, + // because all accounts are about to be deleted. foreach (xact_t * xact, xacts) checked_delete(xact); diff --git a/src/output.cc b/src/output.cc index 71ec6d88..bb7eff5c 100644 --- a/src/output.cc +++ b/src/output.cc @@ -152,13 +152,12 @@ format_accounts::format_accounts(report_t& _report, std::size_t format_accounts::post_account(account_t& account, const bool flat) { + if (! flat && account.parent) + post_account(*account.parent, flat); + if (account.xdata().has_flags(ACCOUNT_EXT_TO_DISPLAY) && ! account.xdata().has_flags(ACCOUNT_EXT_DISPLAYED)) { - if (! flat && account.parent && - account.parent->xdata().has_flags(ACCOUNT_EXT_TO_DISPLAY) && - ! account.parent->xdata().has_flags(ACCOUNT_EXT_DISPLAYED)) - post_account(*account.parent, flat); - + DEBUG("account.display", "Displaying account: " << account.fullname()); account.xdata().add_flags(ACCOUNT_EXT_DISPLAYED); bind_scope_t bound_scope(report, account); diff --git a/src/post.cc b/src/post.cc index 34284e1b..43cfe55f 100644 --- a/src/post.cc +++ b/src/post.cc @@ -97,6 +97,18 @@ date_t post_t::date() const return *_date; } +date_t post_t::actual_date() const +{ + if (xdata_ && is_valid(xdata_->date)) + return xdata_->date; + + if (! _date) { + assert(xact); + return xact->date(); + } + return *_date; +} + optional<date_t> post_t::effective_date() const { optional<date_t> date = item_t::effective_date(); @@ -405,6 +417,20 @@ expr_t::ptr_op_t post_t::lookup(const symbol_t::kind_t kind, return item_t::lookup(kind, name); } +amount_t post_t::resolve_expr(scope_t& scope, expr_t& expr) +{ + bind_scope_t bound_scope(scope, *this); + value_t result(expr.calc(bound_scope)); + if (result.is_long()) { + return result.to_amount(); + } else { + if (! result.is_amount()) + throw_(amount_error, + _("Amount expressions must result in a simple amount")); + return result.as_amount(); + } +} + bool post_t::valid() const { if (! xact) { @@ -105,6 +105,7 @@ public: const optional<mask_t>& value_mask = none) const; virtual date_t date() const; + virtual date_t actual_date() const; virtual optional<date_t> effective_date() const; bool must_balance() const { @@ -114,6 +115,8 @@ public: virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, const string& name); + amount_t resolve_expr(scope_t& scope, expr_t& expr); + bool valid() const; struct xdata_t : public supports_flags<uint_least16_t> @@ -198,6 +201,20 @@ public: friend class xact_t; + struct compare_by_date_and_sequence + { + bool operator()(const post_t * left, const post_t * right) const { + gregorian::date_duration duration = + left->actual_date() - right->actual_date(); + if (duration.days() == 0) { + return ((left->pos ? left->pos->sequence : 0) < + (right->pos ? right->pos->sequence : 0)); + } else { + return duration.days() < 0; + } + } + }; + #if defined(HAVE_BOOST_SERIALIZATION) private: /** Serialization. */ diff --git a/src/report.cc b/src/report.cc index 2d9d7cc6..fa71e584 100644 --- a/src/report.cc +++ b/src/report.cc @@ -293,12 +293,15 @@ void report_t::accounts_report(acct_handler_ptr handler) sort_expr, HANDLED(flat))); } - if (HANDLED(display_)) + if (HANDLED(display_)) { + DEBUG("report.predicate", + "Display predicate = " << HANDLER(display_).str()); pass_down_accounts(handler, *iter.get(), predicate_t(HANDLER(display_).str(), what_to_keep()), *this); - else + } else { pass_down_accounts(handler, *iter.get()); + } session.journal->clear_xdata(); } @@ -870,6 +873,7 @@ option_t<report_t> * report_t::lookup_option(const char * p) else OPT(percent); else OPT_(period_); else OPT_ALT(sort_xacts_, period_sort_); + else OPT(pivot_); else OPT(plot_amount_format_); else OPT(plot_total_format_); else OPT(price); diff --git a/src/report.h b/src/report.h index 94d39215..08819e23 100644 --- a/src/report.h +++ b/src/report.h @@ -273,6 +273,7 @@ public: HANDLER(pending).report(out); HANDLER(percent).report(out); HANDLER(period_).report(out); + HANDLER(pivot_).report(out); HANDLER(plot_amount_format_).report(out); HANDLER(plot_total_format_).report(out); HANDLER(prepend_format_).report(out); @@ -362,7 +363,7 @@ public: OPTION_(report_t, average, DO() { // -A parent->HANDLER(display_total_) - .set_expr(string("--average"), "total_expr/count"); + .set_expr(string("--average"), "count>0?(total_expr/count):0"); }); OPTION__(report_t, balance_format_, CTOR(report_t, balance_format_) { @@ -715,6 +716,8 @@ public: string_value(text.as_string() + " " + str())); }); + OPTION(report_t, pivot_); + OPTION__(report_t, plot_amount_format_, CTOR(report_t, plot_amount_format_) { on(none, "%(format_date(date, \"%Y-%m-%d\")) %(quantity(scrub(display_amount)))\n"); diff --git a/src/textual.cc b/src/textual.cc index cbeb6358..8953d2b8 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -49,50 +49,26 @@ namespace ledger { namespace { - class instance_t : public noncopyable, public scope_t - { - static const std::size_t MAX_LINE = 1024; + typedef std::pair<commodity_t *, amount_t> fixed_rate_t; + typedef variant<account_t *, string, fixed_rate_t> state_t; + class parse_context_t : public noncopyable + { public: - typedef std::pair<commodity_t *, amount_t> fixed_rate_t; - typedef variant<account_t *, string, fixed_rate_t> state_t; - - std::list<state_t>& state_stack; - -#if defined(TIMELOG_SUPPORT) - time_log_t& timelog; -#endif - instance_t * parent; - std::istream& in; - scope_t& scope; - journal_t& journal; - account_t * master; - const path * original_file; - accounts_map account_aliases; - bool strict; - path pathname; - char linebuf[MAX_LINE + 1]; - std::size_t linenum; - istream_pos_type line_beg_pos; - istream_pos_type curr_pos; - std::size_t count; - std::size_t errors; - - optional<date_t::year_type> current_year; - - instance_t(std::list<state_t>& _state_stack, + journal_t& journal; + scope_t& scope; + std::list<state_t> state_stack; #if defined(TIMELOG_SUPPORT) - time_log_t& _timelog, + time_log_t timelog; #endif - std::istream& _in, - scope_t& _scope, - journal_t& _journal, - account_t * _master = NULL, - const path * _original_file = NULL, - bool _strict = false, - instance_t * _parent = NULL); + bool strict; + std::size_t count; + std::size_t errors; + std::size_t sequence; - ~instance_t(); + parse_context_t(journal_t& _journal, scope_t& _scope) + : journal(_journal), scope(_scope), timelog(journal), + strict(false), count(0), errors(0), sequence(1) {} bool front_is_account() { return state_stack.front().type() == typeid(account_t *); @@ -110,6 +86,34 @@ namespace { return boost::get<account_t *>(state); return NULL; } + }; + + class instance_t : public noncopyable, public scope_t + { + static const std::size_t MAX_LINE = 1024; + + public: + parse_context_t& context; + instance_t * parent; + account_t * master; + accounts_map account_aliases; + const path * original_file; + path pathname; + std::istream& in; + char linebuf[MAX_LINE + 1]; + std::size_t linenum; + istream_pos_type line_beg_pos; + istream_pos_type curr_pos; + + optional<date_t::year_type> current_year; + + instance_t(parse_context_t& _context, + std::istream& _in, + account_t * _master = NULL, + const path * _original_file = NULL, + instance_t * _parent = NULL); + + ~instance_t(); void parse(); std::streamsize read_line(char *& line); @@ -148,7 +152,6 @@ namespace { std::streamsize len, account_t * account, xact_t * xact, - bool honor_strict = true, bool defer_expr = false); bool parse_posts(account_t * account, @@ -163,13 +166,13 @@ namespace { const string& name); }; - void parse_amount_expr(scope_t& scope, - std::istream& in, + void parse_amount_expr(std::istream& in, + scope_t& scope, + post_t& post, amount_t& amount, - optional<expr_t> * amount_expr, - post_t * post, - const parse_flags_t& flags = PARSE_DEFAULT, - const bool defer_expr = false) + const parse_flags_t& flags = PARSE_DEFAULT, + const bool defer_expr = false, + optional<expr_t> * amount_expr = NULL) { expr_t expr(in, flags.plus_flags(PARSE_PARTIAL)); @@ -185,51 +188,27 @@ namespace { #endif if (expr) { - bind_scope_t bound_scope(scope, *post); - if (defer_expr) { - assert(amount_expr); + if (amount_expr) *amount_expr = expr; - (*amount_expr)->compile(bound_scope); - } else { - value_t result(expr.calc(bound_scope)); - if (result.is_long()) { - amount = result.to_amount(); - } else { - if (! result.is_amount()) - throw_(amount_error, - _("Amount expressions must result in a simple amount")); - amount = result.as_amount(); - } - DEBUG("textual.parse", "The posting amount is " << amount); - } + if (! defer_expr) + amount = post.resolve_expr(scope, expr); } } } -instance_t::instance_t(std::list<state_t>& _state_stack, -#if defined(TIMELOG_SUPPORT) - time_log_t& _timelog, -#endif - std::istream& _in, - scope_t& _scope, - journal_t& _journal, - account_t * _master, - const path * _original_file, - bool _strict, - instance_t * _parent) - : state_stack(_state_stack), -#if defined(TIMELOG_SUPPORT) - timelog(_timelog), -#endif - parent(_parent), in(_in), scope(_scope), - journal(_journal), master(_master), - original_file(_original_file), strict(_strict) +instance_t::instance_t(parse_context_t& _context, + std::istream& _in, + account_t * _master, + const path * _original_file, + instance_t * _parent) + : context(_context), parent(_parent), master(_master), + original_file(_original_file), in(_in) { TRACE_CTOR(instance_t, "..."); if (! master) - master = journal.master; - state_stack.push_front(master); + master = context.journal.master; + context.state_stack.push_front(master); if (_original_file) pathname = *_original_file; @@ -241,8 +220,8 @@ instance_t::~instance_t() { TRACE_DTOR(instance_t); - assert(! state_stack.empty()); - state_stack.pop_front(); + assert(! context.state_stack.empty()); + context.state_stack.pop_front(); } void instance_t::parse() @@ -256,8 +235,6 @@ void instance_t::parse() return; linenum = 0; - errors = 0; - count = 0; curr_pos = in.tellg(); while (in.good() && ! in.eof()) { @@ -286,15 +263,15 @@ void instance_t::parse() if (caught_signal != NONE_CAUGHT) throw; - string context = error_context(); - if (! context.empty()) - std::cerr << context << std::endl; + string err_context = error_context(); + if (! err_context.empty()) + std::cerr << err_context << std::endl; if (! current_context.empty()) std::cerr << current_context << std::endl; std::cerr << _("Error: ") << err.what() << std::endl; - errors++; + context.errors++; } } @@ -452,13 +429,14 @@ void instance_t::clock_in_directive(char * line, position.beg_line = linenum; position.end_pos = curr_pos; position.end_line = linenum; + position.sequence = context.sequence++; time_xact_t event(position, parse_datetime(datetime, current_year), - p ? top_account()->find_account(p) : NULL, + p ? context.top_account()->find_account(p) : NULL, n ? n : "", end ? end : ""); - timelog.clock_in(event); + context.timelog.clock_in(event); } void instance_t::clock_out_directive(char * line, @@ -481,14 +459,15 @@ void instance_t::clock_out_directive(char * line, position.beg_line = linenum; position.end_pos = curr_pos; position.end_line = linenum; + position.sequence = context.sequence++; time_xact_t event(position, parse_datetime(datetime, current_year), - p ? top_account()->find_account(p) : NULL, + p ? context.top_account()->find_account(p) : NULL, n ? n : "", end ? end : ""); - timelog.clock_out(event); - count++; + context.timelog.clock_out(event); + context.count++; } #endif // TIMELOG_SUPPORT @@ -503,8 +482,8 @@ void instance_t::default_commodity_directive(char * line) void instance_t::default_account_directive(char * line) { - journal.bucket = top_account()->find_account(skip_ws(line + 1)); - journal.bucket->add_flags(ACCOUNT_KNOWN); + context.journal.bucket = context.top_account()->find_account(skip_ws(line + 1)); + context.journal.bucket->add_flags(ACCOUNT_KNOWN); } void instance_t::price_conversion_directive(char * line) @@ -548,14 +527,13 @@ void instance_t::option_directive(char * line) *p++ = '\0'; } - if (! process_option(pathname.string(), line + 2, scope, p, line)) + if (! process_option(pathname.string(), line + 2, context.scope, p, line)) throw_(option_error, _("Illegal option --%1") << line + 2); } void instance_t::automated_xact_directive(char * line) { - istream_pos_type pos = line_beg_pos; - std::size_t lnum = linenum; + istream_pos_type pos= line_beg_pos; bool reveal_context = true; @@ -564,19 +542,20 @@ void instance_t::automated_xact_directive(char * line) std::auto_ptr<auto_xact_t> ae (new auto_xact_t(query_t(string(skip_ws(line + 1)), keep_details_t(true, true, true)))); + ae->pos = position_t(); + ae->pos->pathname = pathname; + ae->pos->beg_pos = line_beg_pos; + ae->pos->beg_line = linenum; + ae->pos->sequence = context.sequence++; reveal_context = false; - if (parse_posts(top_account(), *ae.get(), true)) { + if (parse_posts(context.top_account(), *ae.get(), true)) { reveal_context = true; - journal.auto_xacts.push_back(ae.get()); + context.journal.auto_xacts.push_back(ae.get()); - ae->journal = &journal; - ae->pos = position_t(); - ae->pos->pathname = pathname; - ae->pos->beg_pos = pos; - ae->pos->beg_line = lnum; + ae->journal = &context.journal; ae->pos->end_pos = curr_pos; ae->pos->end_line = linenum; @@ -595,29 +574,29 @@ void instance_t::automated_xact_directive(char * line) void instance_t::period_xact_directive(char * line) { - istream_pos_type pos = line_beg_pos; - std::size_t lnum = linenum; + istream_pos_type pos = line_beg_pos; bool reveal_context = true; try { std::auto_ptr<period_xact_t> pe(new period_xact_t(skip_ws(line + 1))); + pe->pos = position_t(); + pe->pos->pathname = pathname; + pe->pos->beg_pos = line_beg_pos; + pe->pos->beg_line = linenum; + pe->pos->sequence = context.sequence++; reveal_context = false; - if (parse_posts(top_account(), *pe.get())) { + if (parse_posts(context.top_account(), *pe.get())) { reveal_context = true; - pe->journal = &journal; + pe->journal = &context.journal; if (pe->finalize()) { - journal.extend_xact(pe.get()); - journal.period_xacts.push_back(pe.get()); + context.journal.extend_xact(pe.get()); + context.journal.period_xacts.push_back(pe.get()); - pe->pos = position_t(); - pe->pos->pathname = pathname; - pe->pos->beg_pos = pos; - pe->pos->beg_line = lnum; pe->pos->end_pos = curr_pos; pe->pos->end_line = linenum; @@ -642,12 +621,12 @@ void instance_t::xact_directive(char * line, std::streamsize len) { TRACE_START(xacts, 1, "Time spent handling transactions:"); - if (xact_t * xact = parse_xact(line, len, top_account())) { + if (xact_t * xact = parse_xact(line, len, context.top_account())) { std::auto_ptr<xact_t> manager(xact); - if (journal.add_xact(xact)) { + if (context.journal.add_xact(xact)) { manager.release(); // it's owned by the journal now - count++; + context.count++; } // It's perfectly valid for the journal to reject the xact, which it will // do if the xact has no substantive effect (for example, a checking @@ -690,22 +669,14 @@ void instance_t::include_directive(char * line) ifstream stream(filename); - instance_t instance(state_stack, -#if defined(TIMELOG_SUPPORT) - timelog, -#endif - stream, scope, journal, master, - &filename, strict, this); + instance_t instance(context, stream, master, &filename, this); instance.parse(); - - errors += instance.errors; - count += instance.count; } void instance_t::master_account_directive(char * line) { - if (account_t * acct = top_account()->find_account(line)) - state_stack.push_front(acct); + if (account_t * acct = context.top_account()->find_account(line)) + context.state_stack.push_front(acct); else assert(! "Failed to create account"); } @@ -714,21 +685,21 @@ void instance_t::end_directive(char * kind) { string name(kind); - if ((name.empty() || name == "account") && ! front_is_account()) + if ((name.empty() || name == "account") && ! context.front_is_account()) throw_(std::runtime_error, _("'end account' directive does not match open directive")); - else if (name == "tag" && ! front_is_string()) + else if (name == "tag" && ! context.front_is_string()) throw_(std::runtime_error, _("'end tag' directive does not match open directive")); - else if (name == "fixed" && ! front_is_fixed_rate()) + else if (name == "fixed" && ! context.front_is_fixed_rate()) throw_(std::runtime_error, _("'end fixed' directive does not match open directive")); - if (state_stack.size() <= 1) + if (context.state_stack.size() <= 1) throw_(std::runtime_error, _("'end' found, but no enclosing tag or account directive")); else - state_stack.pop_front(); + context.state_stack.pop_front(); } void instance_t::alias_directive(char * line) @@ -745,7 +716,7 @@ void instance_t::alias_directive(char * line) // name (e), add a reference to the account in the // `account_aliases' map, which is used by the post // parser to resolve alias references. - account_t * acct = top_account()->find_account(e); + account_t * acct = context.top_account()->find_account(e); std::pair<accounts_map::iterator, bool> result = account_aliases.insert(accounts_map::value_type(b, acct)); assert(result.second); @@ -757,8 +728,8 @@ void instance_t::fixed_directive(char * line) if (optional<std::pair<commodity_t *, price_point_t> > price_point = commodity_pool_t::current_pool->parse_price_directive(trim_ws(line), true)) { - state_stack.push_front(fixed_rate_t(price_point->first, - price_point->second.price)); + context.state_stack.push_front(fixed_rate_t(price_point->first, + price_point->second.price)); } else { throw_(std::runtime_error, _("Error in fixed directive")); } @@ -771,13 +742,13 @@ void instance_t::tag_directive(char * line) if (tag.find(':') == string::npos) tag = string(":") + tag + ":"; - state_stack.push_front(tag); + context.state_stack.push_front(tag); } void instance_t::define_directive(char * line) { expr_t def(skip_ws(line)); - def.compile(scope); // causes definitions to be established + def.compile(context.scope); // causes definitions to be established } bool instance_t::general_directive(char * line) @@ -868,7 +839,6 @@ post_t * instance_t::parse_post(char * line, std::streamsize len, account_t * account, xact_t * xact, - bool honor_strict, bool defer_expr) { TRACE_START(post_details, 1, "Time spent parsing postings:"); @@ -880,6 +850,7 @@ post_t * instance_t::parse_post(char * line, post->pos->pathname = pathname; post->pos->beg_pos = line_beg_pos; post->pos->beg_line = linenum; + post->pos->sequence = context.sequence++; char buf[MAX_LINE + 1]; std::strcpy(buf, line); @@ -951,7 +922,7 @@ post_t * instance_t::parse_post(char * line, if (! post->account) post->account = account->find_account(name); - if (honor_strict && strict && ! post->account->has_flags(ACCOUNT_KNOWN)) { + if (context.strict && ! post->account->has_flags(ACCOUNT_KNOWN)) { if (post->_state == item_t::UNCLEARED) warning_(_("\"%1\", line %2: Unknown account '%3'") << pathname << linenum << post->account->fullname()); @@ -971,13 +942,13 @@ post_t * instance_t::parse_post(char * line, if (*next != '(') // indicates a value expression post->amount.parse(stream, PARSE_NO_REDUCE); else - parse_amount_expr(scope, stream, post->amount, &post->amount_expr, - post.get(), PARSE_NO_REDUCE | PARSE_SINGLE | - PARSE_NO_ASSIGN, defer_expr); + parse_amount_expr(stream, context.scope, *post.get(), post->amount, + PARSE_NO_REDUCE | PARSE_SINGLE | PARSE_NO_ASSIGN, + defer_expr, &post->amount_expr); if (! post->amount.is_null() && post->amount.has_commodity()) { - if (honor_strict && strict && - ! post->amount.commodity().has_flags(COMMODITY_KNOWN)) { + if (context.strict && + ! post->amount.commodity().has_flags(COMMODITY_KNOWN)) { if (post->_state == item_t::UNCLEARED) warning_(_("\"%1\", line %2: Unknown commodity '%3'") << pathname << linenum << post->amount.commodity()); @@ -985,7 +956,7 @@ post_t * instance_t::parse_post(char * line, } if (! post->amount.has_annotation()) { - foreach (state_t& state, state_stack) { + foreach (state_t& state, context.state_stack) { if (state.type() == typeid(fixed_rate_t)) { fixed_rate_t& rate(boost::get<fixed_rate_t>(state)); if (*rate.first == post->amount.commodity()) { @@ -1033,9 +1004,8 @@ post_t * instance_t::parse_post(char * line, if (*p != '(') // indicates a value expression post->cost->parse(cstream, PARSE_NO_MIGRATE); else - parse_amount_expr(scope, cstream, *post->cost, NULL, post.get(), - PARSE_NO_MIGRATE | PARSE_SINGLE | PARSE_NO_ASSIGN, - defer_expr); + parse_amount_expr(cstream, context.scope, *post.get(), *post->cost, + PARSE_NO_MIGRATE | PARSE_SINGLE | PARSE_NO_ASSIGN); if (post->cost->sign() < 0) throw parse_error(_("A posting's cost may not be negative")); @@ -1088,9 +1058,9 @@ post_t * instance_t::parse_post(char * line, if (*p != '(') // indicates a value expression post->assigned_amount->parse(stream, PARSE_NO_MIGRATE); else - parse_amount_expr(scope, stream, *post->assigned_amount, NULL, - post.get(), PARSE_SINGLE | PARSE_NO_MIGRATE, - defer_expr); + parse_amount_expr(stream, context.scope, *post.get(), + *post->assigned_amount, + PARSE_SINGLE | PARSE_NO_MIGRATE); if (post->assigned_amount->is_null()) { if (post->amount.is_null()) @@ -1173,8 +1143,8 @@ post_t * instance_t::parse_post(char * line, post->pos->end_pos = curr_pos; post->pos->end_line = linenum; - if (! state_stack.empty()) { - foreach (const state_t& state, state_stack) + if (! context.state_stack.empty()) { + foreach (const state_t& state, context.state_stack) if (state.type() == typeid(string)) post->parse_tags(boost::get<string>(state).c_str()); } @@ -1204,9 +1174,7 @@ bool instance_t::parse_posts(account_t * account, std::streamsize len = read_line(line); assert(len > 0); - if (post_t * post = - parse_post(line, len, account, NULL, /* honor_strict= */ false, - defer_expr)) { + if (post_t * post = parse_post(line, len, account, NULL, defer_expr)) { xact.add_post(post); added = true; } @@ -1229,6 +1197,7 @@ xact_t * instance_t::parse_xact(char * line, xact->pos->pathname = pathname; xact->pos->beg_pos = line_beg_pos; xact->pos->beg_line = linenum; + xact->pos->sequence = context.sequence++; bool reveal_context = true; @@ -1338,8 +1307,8 @@ xact_t * instance_t::parse_xact(char * line, xact->pos->end_pos = curr_pos; xact->pos->end_line = linenum; - if (! state_stack.empty()) { - foreach (const state_t& state, state_stack) + if (! context.state_stack.empty()) { + foreach (const state_t& state, context.state_stack) if (state.type() == typeid(string)) xact->parse_tags(boost::get<string>(state).c_str()); } @@ -1362,7 +1331,7 @@ xact_t * instance_t::parse_xact(char * line, expr_t::ptr_op_t instance_t::lookup(const symbol_t::kind_t kind, const string& name) { - return scope.lookup(kind, name); + return context.scope.lookup(kind, name); } std::size_t journal_t::parse(std::istream& in, @@ -1373,18 +1342,11 @@ std::size_t journal_t::parse(std::istream& in, { TRACE_START(parsing_total, 1, "Total time spent parsing text:"); - std::list<instance_t::state_t> state_stack; -#if defined(TIMELOG_SUPPORT) - time_log_t timelog(*this); -#endif + parse_context_t context(*this, scope); + context.strict = strict; - instance_t parsing_instance(state_stack, -#if defined(TIMELOG_SUPPORT) - timelog, -#endif - in, scope, *this, master, - original_file, strict); - parsing_instance.parse(); + instance_t instance(context, in, master, original_file); + instance.parse(); TRACE_STOP(parsing_total, 1); @@ -1396,10 +1358,10 @@ std::size_t journal_t::parse(std::istream& in, TRACE_FINISH(instance_parse, 1); // report per-instance timers TRACE_FINISH(parsing_total, 1); - if (parsing_instance.errors > 0) - throw static_cast<int>(parsing_instance.errors); + if (context.errors > 0) + throw static_cast<int>(context.errors); - return parsing_instance.count; + return context.count; } } // namespace ledger diff --git a/src/times.cc b/src/times.cc index 7ea3ae32..963639f1 100644 --- a/src/times.cc +++ b/src/times.cc @@ -824,15 +824,6 @@ date_interval_t date_parser_t::parse() break; } - case lexer_t::token_t::TOK_MONTH: { - date_t temp(today); - temp += gregorian::months(adjust); - inclusion_specifier = - date_specifier_t(static_cast<date_specifier_t::year_type>(temp.year()), - temp.month()); - break; - } - case lexer_t::token_t::TOK_WEEK: { date_t temp = date_duration_t::find_nearest(today, date_duration_t::WEEKS); @@ -852,10 +843,15 @@ date_interval_t date_parser_t::parse() } default: - tok.unexpected(); + case lexer_t::token_t::TOK_MONTH: { + date_t temp(today); + temp += gregorian::months(adjust); + inclusion_specifier = + date_specifier_t(static_cast<date_specifier_t::year_type>(temp.year()), + temp.month()); break; } - break; + } } case lexer_t::token_t::TOK_TODAY: diff --git a/src/value.cc b/src/value.cc index cce4c4e8..7d079caf 100644 --- a/src/value.cc +++ b/src/value.cc @@ -861,7 +861,7 @@ bool value_t::is_less_than(const value_t& val) const return as_amount() < val.as_amount(); } catch (const amount_error&) { - return compare_amount_commodities()(&as_amount(), &val.as_amount()); + return commodity_t::compare_by_commodity()(&as_amount(), &val.as_amount()); } default: break; |