summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2010-02-05 05:35:14 -0500
committerJohn Wiegley <johnw@newartisans.com>2010-02-05 05:35:14 -0500
commit547137096051ab985dca6f8e5c7be191b62ccb0c (patch)
tree2f3a39c4b71b8cb8b232502401e8dd2c8c2247ef /src
parentc6873d32aa121289e87be7eb16ff531c6d468d2a (diff)
parent69da18cd303b10f9badd542141ffdfd546009508 (diff)
downloadfork-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.cc2
-rw-r--r--src/balance.cc3
-rw-r--r--src/chain.cc12
-rw-r--r--src/commodity.cc4
-rw-r--r--src/commodity.h8
-rw-r--r--src/filters.cc25
-rw-r--r--src/item.cc49
-rw-r--r--src/item.h10
-rw-r--r--src/journal.cc5
-rw-r--r--src/output.cc9
-rw-r--r--src/post.cc26
-rw-r--r--src/post.h17
-rw-r--r--src/report.cc8
-rw-r--r--src/report.h5
-rw-r--r--src/textual.cc316
-rw-r--r--src/times.cc18
-rw-r--r--src/value.cc2
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':
diff --git a/src/item.h b/src/item.h
index 84385eb7..f23350fc 100644
--- a/src/item.h
+++ b/src/item.h
@@ -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) {
diff --git a/src/post.h b/src/post.h
index a0ab5ffd..8852e7b2 100644
--- a/src/post.h
+++ b/src/post.h
@@ -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;