summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2010-06-14 17:14:56 -0400
committerJohn Wiegley <johnw@newartisans.com>2010-06-14 17:14:56 -0400
commitf3bedb88b24ae8b2047ad86e57b161265c2812f5 (patch)
treee6e5954f40a09e7fd002f242523c1eb0f318b397 /src
parent0c699e4d57fe91fa04c4c2f23f9c2f2a6a5da582 (diff)
parent63b4bdaecff5a865bff22e8e7914bef6ab46fa6b (diff)
downloadfork-ledger-f3bedb88b24ae8b2047ad86e57b161265c2812f5.tar.gz
fork-ledger-f3bedb88b24ae8b2047ad86e57b161265c2812f5.tar.bz2
fork-ledger-f3bedb88b24ae8b2047ad86e57b161265c2812f5.zip
Merge branch 'next'
Diffstat (limited to 'src')
-rw-r--r--src/account.cc4
-rw-r--r--src/commodity.cc10
-rw-r--r--src/filters.cc54
-rw-r--r--src/format.cc155
-rw-r--r--src/global.cc2
-rw-r--r--src/item.cc20
-rw-r--r--src/item.h14
-rw-r--r--src/journal.cc10
-rw-r--r--src/journal.h6
-rw-r--r--src/op.cc6
-rw-r--r--src/post.cc12
-rw-r--r--src/precmd.cc2
-rw-r--r--src/report.cc4
-rw-r--r--src/report.h10
-rw-r--r--src/scope.cc2
-rw-r--r--src/scope.h16
-rw-r--r--src/session.cc55
-rw-r--r--src/session.h8
-rw-r--r--src/textual.cc65
-rw-r--r--src/times.cc159
-rw-r--r--src/times.h68
-rw-r--r--src/xact.cc23
-rw-r--r--src/xact.h6
23 files changed, 462 insertions, 249 deletions
diff --git a/src/account.cc b/src/account.cc
index 809b6e46..ceeb1c12 100644
--- a/src/account.cc
+++ b/src/account.cc
@@ -295,7 +295,7 @@ namespace {
foreach (post_t * p, account.posts) {
bind_scope_t bound_scope(args, *p);
- if (expr->calc(bound_scope).to_boolean())
+ if (expr->calc(bound_scope, args.locus, args.depth).to_boolean())
return true;
}
return false;
@@ -308,7 +308,7 @@ namespace {
foreach (post_t * p, account.posts) {
bind_scope_t bound_scope(args, *p);
- if (! expr->calc(bound_scope).to_boolean())
+ if (! expr->calc(bound_scope, args.locus, args.depth).to_boolean())
return false;
}
return true;
diff --git a/src/commodity.cc b/src/commodity.cc
index 230113e8..179bbc05 100644
--- a/src/commodity.cc
+++ b/src/commodity.cc
@@ -646,9 +646,13 @@ void commodity_t::print(std::ostream& out, bool elide_quotes) const
{
string sym = symbol();
if (elide_quotes && has_flags(COMMODITY_STYLE_SEPARATED) &&
- ! sym.empty() && sym[0] == '"' && ! std::strchr(sym.c_str(), ' ')) {
- DEBUG("foo", "contracting " << sym << " to " << string(sym, 1, sym.length() - 2));
- out << string(sym, 1, sym.length() - 2);
+ ! sym.empty() && sym[0] == '"' &&
+ ! std::strchr(sym.c_str(), ' ')) {
+ string subsym(sym, 1, sym.length() - 2);
+ if (! all(subsym, is_digit()))
+ out << subsym;
+ else
+ out << sym;
} else
out << sym;
}
diff --git a/src/filters.cc b/src/filters.cc
index 86386f58..69183991 100644
--- a/src/filters.cc
+++ b/src/filters.cc
@@ -501,26 +501,15 @@ void related_posts::flush()
{
if (posts.size() > 0) {
foreach (post_t * post, posts) {
- if (post->xact) {
- foreach (post_t * r_post, post->xact->posts) {
- post_t::xdata_t& xdata(r_post->xdata());
- if (! xdata.has_flags(POST_EXT_HANDLED) &&
- (! xdata.has_flags(POST_EXT_RECEIVED) ?
- ! r_post->has_flags(ITEM_GENERATED | POST_VIRTUAL) :
- also_matching)) {
- xdata.add_flags(POST_EXT_HANDLED);
- item_handler<post_t>::operator()(*r_post);
- }
- }
- } else {
- // This code should only be reachable from the "output"
- // command, since that is the only command which attempts to
- // output auto or period xacts.
- post_t::xdata_t& xdata(post->xdata());
+ assert(post->xact);
+ foreach (post_t * r_post, post->xact->posts) {
+ post_t::xdata_t& xdata(r_post->xdata());
if (! xdata.has_flags(POST_EXT_HANDLED) &&
- ! post->has_flags(ITEM_GENERATED)) {
+ (! xdata.has_flags(POST_EXT_RECEIVED) ?
+ ! r_post->has_flags(ITEM_GENERATED | POST_VIRTUAL) :
+ also_matching)) {
xdata.add_flags(POST_EXT_HANDLED);
- item_handler<post_t>::operator()(*post);
+ item_handler<post_t>::operator()(*r_post);
}
}
}
@@ -1228,18 +1217,16 @@ void budget_posts::operator()(post_t& post)
void forecast_posts::add_post(const date_interval_t& period, post_t& post)
{
- generate_posts::add_post(period, post);
+ date_interval_t i(period);
+ if (! i.start && ! i.find_period(CURRENT_DATE()))
+ return;
- // Advance the period's interval until it is at or beyond the current date.
- date_interval_t& i = pending_posts.back().first;
- if (! i.start) {
- if (! i.find_period(CURRENT_DATE()))
- throw_(std::runtime_error, _("Something odd has happened"));
+ generate_posts::add_post(i, post);
+
+ // Advance the period's interval until it is at or beyond the current
+ // date.
+ while (*i.start < CURRENT_DATE())
++i;
- } else {
- while (*i.start < CURRENT_DATE())
- ++i;
- }
}
void forecast_posts::flush()
@@ -1281,6 +1268,8 @@ void forecast_posts::flush()
for (pending_posts_list::iterator i = ++pending_posts.begin();
i != pending_posts.end();
i++) {
+ assert((*i).first.start);
+ assert((*least).first.start);
if (*(*i).first.start < *(*least).first.start)
least = i;
}
@@ -1307,7 +1296,6 @@ void forecast_posts::flush()
}
begin = next;
- ++(*least).first;
// `post' refers to the posting defined in the period transaction. We
// make a copy of it within a temporary transaction with the payee
@@ -1337,6 +1325,14 @@ void forecast_posts::flush()
continue;
}
}
+
+ // Increment the 'least', but remove it from pending_posts if it
+ // exceeds its own boundaries.
+ ++(*least).first;
+ if (! (*least).first.start) {
+ pending_posts.erase(least);
+ continue;
+ }
}
item_handler<post_t>::flush();
diff --git a/src/format.cc b/src/format.cc
index ae40e1c3..946dcf80 100644
--- a/src/format.cc
+++ b/src/format.cc
@@ -432,6 +432,23 @@ string format_t::truncate(const unistring& ustr,
case ABBREVIATE:
if (account_abbrev_length > 0) {
+ // The algorithm here is complex, but aims to preserve the most
+ // information in the most useful places.
+ //
+ // Consider: You have an account name like
+ // 'Assets:Banking:Check:Register'. This account name, which is
+ // 29 characters long, must be shortened to fit in 20. How would
+ // you shorten it?
+ //
+ // The approach taken below is to compute the difference, or 9
+ // characters, and then distribute this difference semi-evenly
+ // among first three segments of the account name, by taking
+ // characters until the difference is gone. Further, earlier
+ // segments will give up more of their share of letters than later
+ // segments, since the later segments usually contain more useful
+ // information.
+
+ // First, chop up the Unicode string into individual segments.
std::list<string> parts;
string::size_type beg = 0;
string strcopy(ustr.extract());
@@ -441,34 +458,140 @@ string format_t::truncate(const unistring& ustr,
parts.push_back(string(strcopy, beg, pos - beg));
parts.push_back(string(strcopy, beg));
- std::ostringstream result;
-
- std::size_t newlen = len;
+ DEBUG("format.abbrev", "Account name: " << strcopy);
+ DEBUG("format.abbrev",
+ "Must fit a " << len << " char string in " << width << " chars");
+
+ // Figure out the lengths of all the parts. The last part is
+ // always displayed in full, while the former parts are
+ // distributed, with the latter parts being longer than the
+ // former, but with none shorter than account_abbrev_length.
+ std::list<std::size_t> lens;
+#if defined(DEBUG_ON)
+ int index = 0;
+#endif
for (std::list<string>::iterator i = parts.begin();
i != parts.end();
i++) {
- // Don't contract the last element
+ std::size_t l = unistring(*i).length();
+ DEBUG("format.abbrev",
+ "Segment " << ++index << " is " << l << " chars wide");
+ lens.push_back(l);
+ }
+
+ // Determine the "overflow", or how many chars in excess we are.
+
+ std::size_t overflow = len - width;
+ DEBUG("format.abbrev",
+ "There are " << overflow << " chars of overflow");
+
+ // Walk through the first n-1 segments, and start subtracting
+ // letters to decrease the overflow. This is done in multiple
+ // passes until the overflow is gone, or we cannot reduce any
+ // further. The calculation to find the amount to remove is:
+ //
+ // overflow * (((len(segment) + counter) * iteration) /
+ // (len(string) - len(last_segment) - counter))
+ //
+ // Where:
+ // overflow - the amount that needs to be removed
+ // counter - starts at n-1 for the first segment, then
+ // decreases by one until it reaches 0 for the
+ // last segment (which is never shortened).
+ // This value is used to weight the shrinkage
+ // so that earlier segments shrink faster.
+ // iteration - starts at 1, increase by 1 for every
+ // iteration of the loop
+ //
+ // In the example above, we have this account name:
+ //
+ // Assets:Banking:Check:Register
+ //
+ // Therefore, the amount to be removed from Assets is calculated as:
+ //
+ // 9 * (((6 + 3) * 1) / (29 - 8 - 3)) = ceil(4.5) = 5
+ //
+ // However, since removing 5 chars would make the length of the
+ // segment shorter than the default minimum of 2, we can only
+ // remove 4 chars from Assets to reduce the overflow. And on it
+ // goes.
+ //
+ // The final result will be: As:Ban:Chec:Register
+
+ std::size_t iteration = 1;
+ std::size_t len_minus_last = len - lens.back();
+ while (overflow > 0) {
+ std::size_t overflow_at_start = overflow;
+ DEBUG("format.abbrev",
+ "Overflow starting at " << overflow << " chars");
+#if defined(DEBUG_ON)
+ index = 0;
+#endif
+ std::size_t counter = lens.size();
+ for (std::list<std::size_t>::iterator i = lens.begin();
+ i != lens.end();
+ i++) {
+ if (--counter == 0 || overflow == 0)
+ break;
+ DEBUG("format.abbrev", "Overflow is " << overflow << " chars");
+ std::size_t adjust;
+ if (overflow == 1)
+ adjust = 1;
+ else
+ adjust = std::size_t
+ (std::ceil(double(overflow) *
+ ((double(*i + counter) * double(iteration)) /
+ (double(len_minus_last) - double(counter)))));
+ DEBUG("format.abbrev", "Weight calc: (" << overflow
+ << " * (((" << *i << " + " << counter << ") * "
+ << iteration << ") / (" << len_minus_last
+ << " - " << counter << ")))");
+ if (adjust == 0)
+ adjust = 1;
+ else if (adjust > overflow)
+ adjust = overflow;
+ DEBUG("format.abbrev", "The weighted part is " << adjust << " chars");
+ std::size_t slack = *i - std::min(*i, account_abbrev_length);
+ if (adjust > slack)
+ adjust = slack;
+ if (adjust > 0) {
+ DEBUG("format.abbrev",
+ "Reducing segment " << ++index << " by " << adjust << " chars");
+ (*i) -= adjust;
+ DEBUG("format.abbrev",
+ "Segment " << index << " is now " << *i << " chars wide");
+ overflow -= adjust;
+ DEBUG("format.abbrev", "Overflow is now " << overflow << " chars");
+ }
+ }
+ DEBUG("format.abbrev",
+ "Overflow ending this time at " << overflow << " chars");
+ if (overflow == overflow_at_start)
+ break;
+ iteration++;
+ }
+
+ assert(parts.size() == lens.size());
+
+ std::list<string>::iterator i = parts.begin();
+ std::list<std::size_t>::iterator l = lens.begin();
+ std::ostringstream result;
+
+ for (; i != parts.end() && l != lens.end(); i++, l++) {
std::list<string>::iterator x = i;
if (++x == parts.end()) {
result << *i;
break;
}
- if (newlen > width) {
- unistring temp(*i);
- if (temp.length() > account_abbrev_length) {
- result << temp.extract(0, account_abbrev_length) << ":";
- newlen -= temp.length() - account_abbrev_length;
- } else {
- result << temp.extract() << ":";
- newlen -= temp.length();
- }
- } else {
+ unistring temp(*i);
+ if (temp.length() > *l)
+ result << temp.extract(0, *l) << ":";
+ else
result << *i << ":";
- }
}
- if (newlen > width) {
+ if (overflow > 0) {
// Even abbreviated its too big to show the last account, so
// abbreviate all but the last and truncate at the beginning.
unistring temp(result.str());
diff --git a/src/global.cc b/src/global.cc
index eb138f25..b1466cae 100644
--- a/src/global.cc
+++ b/src/global.cc
@@ -49,6 +49,8 @@ global_scope_t::global_scope_t(char ** envp)
{
TRACE_CTOR(global_scope_t, "");
+ epoch = CURRENT_TIME();
+
#if defined(HAVE_BOOST_PYTHON)
if (! python_session.get()) {
python_session.reset(new ledger::python_interpreter_t);
diff --git a/src/item.cc b/src/item.cc
index f0273e59..63f0f3a9 100644
--- a/src/item.cc
+++ b/src/item.cc
@@ -134,10 +134,9 @@ item_t::set_tag(const string& tag,
}
}
-void item_t::parse_tags(const char * p,
- scope_t& scope,
- bool overwrite_existing,
- optional<date_t::year_type> current_year)
+void item_t::parse_tags(const char * p,
+ scope_t& scope,
+ bool overwrite_existing)
{
if (const char * b = std::strchr(p, '[')) {
if (*(b + 1) != '\0' &&
@@ -149,10 +148,10 @@ void item_t::parse_tags(const char * p,
if (char * p = std::strchr(buf, '=')) {
*p++ = '\0';
- _date_eff = parse_date(p, current_year);
+ _date_eff = parse_date(p);
}
if (buf[0])
- _date = parse_date(buf, current_year);
+ _date = parse_date(buf);
}
}
}
@@ -202,10 +201,9 @@ void item_t::parse_tags(const char * p,
}
}
-void item_t::append_note(const char * p,
- scope_t& scope,
- bool overwrite_existing,
- optional<date_t::year_type> current_year)
+void item_t::append_note(const char * p,
+ scope_t& scope,
+ bool overwrite_existing)
{
if (note) {
*note += '\n';
@@ -214,7 +212,7 @@ void item_t::append_note(const char * p,
note = p;
}
- parse_tags(p, scope, overwrite_existing, current_year);
+ parse_tags(p, scope, overwrite_existing);
}
namespace {
diff --git a/src/item.h b/src/item.h
index 209b2dc2..8018db9a 100644
--- a/src/item.h
+++ b/src/item.h
@@ -162,14 +162,12 @@ public:
const optional<value_t>& value = none,
const bool overwrite_existing = true);
- virtual void parse_tags(const char * p,
- scope_t& scope,
- bool overwrite_existing = true,
- optional<date_t::year_type> current_year = none);
- virtual void append_note(const char * p,
- scope_t& scope,
- bool overwrite_existing = true,
- optional<date_t::year_type> current_year = none);
+ virtual void parse_tags(const char * p,
+ scope_t& scope,
+ bool overwrite_existing = true);
+ virtual void append_note(const char * p,
+ scope_t& scope,
+ bool overwrite_existing = true);
static bool use_effective_date;
diff --git a/src/journal.cc b/src/journal.cc
index ed1e26be..fd6d3eac 100644
--- a/src/journal.cc
+++ b/src/journal.cc
@@ -105,8 +105,7 @@ account_t * journal_t::find_account_re(const string& regexp)
return master->find_account_re(regexp);
}
-bool journal_t::add_xact(xact_t * xact,
- optional<date_t::year_type> current_year)
+bool journal_t::add_xact(xact_t * xact)
{
xact->journal = this;
@@ -115,17 +114,16 @@ bool journal_t::add_xact(xact_t * xact,
return false;
}
- extend_xact(xact, current_year);
+ extend_xact(xact);
xacts.push_back(xact);
return true;
}
-void journal_t::extend_xact(xact_base_t * xact,
- optional<date_t::year_type> current_year)
+void journal_t::extend_xact(xact_base_t * xact)
{
foreach (auto_xact_t * auto_xact, auto_xacts)
- auto_xact->extend_xact(*xact, current_year);
+ auto_xact->extend_xact(*xact);
}
bool journal_t::remove_xact(xact_t * xact)
diff --git a/src/journal.h b/src/journal.h
index 183d074d..ca6b6e4f 100644
--- a/src/journal.h
+++ b/src/journal.h
@@ -140,10 +140,8 @@ public:
account_t * find_account(const string& name, bool auto_create = true);
account_t * find_account_re(const string& regexp);
- bool add_xact(xact_t * xact,
- optional<date_t::year_type> current_year = none);
- void extend_xact(xact_base_t * xact,
- optional<date_t::year_type> current_year = none);
+ bool add_xact(xact_t * xact);
+ void extend_xact(xact_base_t * xact);
bool remove_xact(xact_t * xact);
xacts_list::iterator xacts_begin() {
diff --git a/src/op.cc b/src/op.cc
index c2001ec3..d7588b66 100644
--- a/src/op.cc
+++ b/src/op.cc
@@ -157,7 +157,7 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
// Evaluating an identifier is the same as calling its definition
// directly, so we create an empty call_scope_t to reflect the scope for
// this implicit call.
- call_scope_t call_args(scope, scope.type_context(), scope.type_required());
+ call_scope_t call_args(scope, locus, depth);
result = left()->compile(call_args, depth + 1)
->calc(call_args, locus, depth + 1);
check_type_context(scope, result);
@@ -168,7 +168,7 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
// 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, scope.type_context(), scope.type_required());
+ call_scope_t call_args(scope, locus, depth);
result = as_function()(call_args);
check_type_context(scope, result);
#if defined(DEBUG_ON)
@@ -235,7 +235,7 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
}
case O_CALL: {
- call_scope_t call_args(scope, scope.type_context(), scope.type_required());
+ call_scope_t call_args(scope, locus, depth);
if (has_right())
call_args.set_args(split_cons_expr(right()->kind == O_SEQ ?
right()->left() : right()));
diff --git a/src/post.cc b/src/post.cc
index bbf43227..675749fc 100644
--- a/src/post.cc
+++ b/src/post.cc
@@ -353,12 +353,14 @@ namespace {
foreach (post_t * p, post.xact->posts) {
bind_scope_t bound_scope(args, *p);
if (p == &post && args.has<expr_t::ptr_op_t>(1) &&
- ! args.get<expr_t::ptr_op_t>(1)->calc(bound_scope).to_boolean()) {
+ ! args.get<expr_t::ptr_op_t>(1)
+ ->calc(bound_scope, args.locus, args.depth).to_boolean()) {
// If the user specifies any(EXPR, false), and the context is a
// posting, then that posting isn't considered by the test.
; // skip it
}
- else if (expr->calc(bound_scope).to_boolean()) {
+ else if (expr->calc(bound_scope, args.locus,
+ args.depth).to_boolean()) {
return true;
}
}
@@ -373,12 +375,14 @@ namespace {
foreach (post_t * p, post.xact->posts) {
bind_scope_t bound_scope(args, *p);
if (p == &post && args.has<expr_t::ptr_op_t>(1) &&
- ! args.get<expr_t::ptr_op_t>(1)->calc(bound_scope).to_boolean()) {
+ ! args.get<expr_t::ptr_op_t>(1)
+ ->calc(bound_scope, args.locus, args.depth).to_boolean()) {
// If the user specifies any(EXPR, false), and the context is a
// posting, then that posting isn't considered by the test.
; // skip it
}
- else if (! expr->calc(bound_scope).to_boolean()) {
+ else if (! expr->calc(bound_scope, args.locus,
+ args.depth).to_boolean()) {
return false;
}
}
diff --git a/src/precmd.cc b/src/precmd.cc
index 4c916608..95f3e875 100644
--- a/src/precmd.cc
+++ b/src/precmd.cc
@@ -186,7 +186,7 @@ value_t period_command(call_scope_t& args)
out << std::endl;
date_interval_t interval(arg);
- interval.dump(out, report.session.current_year);
+ interval.dump(out);
return NULL_VALUE;
}
diff --git a/src/report.cc b/src/report.cc
index 6b52c52e..f7455440 100644
--- a/src/report.cc
+++ b/src/report.cc
@@ -148,8 +148,8 @@ void report_t::normalize_options(const string& verb)
if (HANDLED(period_)) {
date_interval_t interval(HANDLER(period_).str());
- optional<date_t> begin = interval.begin(session.current_year);
- optional<date_t> end = interval.end(session.current_year);
+ optional<date_t> begin = interval.begin();
+ optional<date_t> end = interval.end();
if (! HANDLED(begin_) && begin) {
string predicate = "date>=[" + to_iso_extended_string(*begin) + "]";
diff --git a/src/report.h b/src/report.h
index 44aed03b..6176c19b 100644
--- a/src/report.h
+++ b/src/report.h
@@ -393,7 +393,7 @@ public:
OPTION_(report_t, begin_, DO_(args) { // -b
date_interval_t interval(args.get<string>(1));
- optional<date_t> begin = interval.begin(parent->session.current_year);
+ optional<date_t> begin = interval.begin();
if (! begin)
throw_(std::invalid_argument,
_("Could not determine beginning of period '%1'")
@@ -543,8 +543,9 @@ public:
OPTION_(report_t, end_, DO_(args) { // -e
date_interval_t interval(args.get<string>(1));
// Use begin() here so that if the user says --end=2008, we end on
- // 2008/01/01 instead of 2009/01/01 (which is what end() would return).
- optional<date_t> end = interval.begin(parent->session.current_year);
+ // 2008/01/01 instead of 2009/01/01 (which is what end() would
+ // return).
+ optional<date_t> end = interval.begin();
if (! end)
throw_(std::invalid_argument,
_("Could not determine end of period '%1'")
@@ -665,13 +666,12 @@ public:
OPTION_(report_t, now_, DO_(args) {
date_interval_t interval(args.get<string>(1));
- optional<date_t> begin = interval.begin(parent->session.current_year);
+ optional<date_t> begin = interval.begin();
if (! begin)
throw_(std::invalid_argument,
_("Could not determine beginning of period '%1'")
<< args.get<string>(1));
ledger::epoch = parent->terminus = datetime_t(*begin);
- parent->session.current_year = ledger::epoch->date().year();
});
OPTION__
diff --git a/src/scope.cc b/src/scope.cc
index 52cf6a90..e18b5a0a 100644
--- a/src/scope.cc
+++ b/src/scope.cc
@@ -81,7 +81,7 @@ value_t& call_scope_t::resolve(const std::size_t index,
value_t& value(args[index]);
if (value.is_any()) {
context_scope_t scope(*this, context, required);
- value = as_expr(value)->calc(scope);
+ value = as_expr(value)->calc(scope, locus, depth);
if (required && ! value.is_type(context))
throw_(calc_error, _("Expected %1 for argument %2, but received %3")
<< value.label(context) << index
diff --git a/src/scope.h b/src/scope.h
index 98b0ee02..07b6bebe 100644
--- a/src/scope.h
+++ b/src/scope.h
@@ -335,11 +335,17 @@ class call_scope_t : public context_scope_t
const bool required = false);
public:
- explicit call_scope_t(scope_t& _parent,
- value_t::type_t _type_context = value_t::VOID,
- const bool _required = true)
- : context_scope_t(_parent, _type_context, _required), ptr(NULL) {
- TRACE_CTOR(call_scope_t, "scope_t&, value_t::type_t, bool");
+ expr_t::ptr_op_t * locus;
+ const int depth;
+
+ explicit call_scope_t(scope_t& _parent,
+ expr_t::ptr_op_t * _locus = NULL,
+ const int _depth = 0)
+ : context_scope_t(_parent, _parent.type_context(),
+ _parent.type_required()),
+ ptr(NULL), locus(_locus), depth(_depth) {
+ TRACE_CTOR(call_scope_t,
+ "scope_t&, value_t::type_t, bool, expr_t::ptr_op_t *, int");
}
virtual ~call_scope_t() {
TRACE_DTOR(call_scope_t);
diff --git a/src/session.cc b/src/session.cc
index df6eaf7d..85b5fab2 100644
--- a/src/session.cc
+++ b/src/session.cc
@@ -60,9 +60,7 @@ void set_session_context(session_t * session)
}
session_t::session_t()
- : flush_on_next_data_file(false),
- current_year(CURRENT_DATE().year()),
- journal(new journal_t)
+ : flush_on_next_data_file(false), journal(new journal_t)
{
TRACE_CTOR(session_t, "");
@@ -192,6 +190,40 @@ value_t session_t::fn_account(call_scope_t& args)
return NULL_VALUE;
}
+value_t session_t::fn_min(call_scope_t& args)
+{
+ return args[1] < args[0] ? args[1] : args[0];
+}
+value_t session_t::fn_max(call_scope_t& args)
+{
+ return args[1] > args[0] ? args[1] : args[0];
+}
+
+value_t session_t::fn_lot_price(call_scope_t& args)
+{
+ amount_t amt(args.get<amount_t>(1, false));
+ if (amt.has_annotation() && amt.annotation().price)
+ return *amt.annotation().price;
+ else
+ return NULL_VALUE;
+}
+value_t session_t::fn_lot_date(call_scope_t& args)
+{
+ amount_t amt(args.get<amount_t>(1, false));
+ if (amt.has_annotation() && amt.annotation().date)
+ return *amt.annotation().date;
+ else
+ return NULL_VALUE;
+}
+value_t session_t::fn_lot_tag(call_scope_t& args)
+{
+ amount_t amt(args.get<amount_t>(1, false));
+ if (amt.has_annotation() && amt.annotation().tag)
+ return string_value(*amt.annotation().tag);
+ else
+ return NULL_VALUE;
+}
+
option_t<session_t> * session_t::lookup_option(const char * p)
{
switch (*p) {
@@ -243,6 +275,23 @@ expr_t::ptr_op_t session_t::lookup(const symbol_t::kind_t kind,
if (is_eq(p, "account"))
return MAKE_FUNCTOR(session_t::fn_account);
break;
+
+ case 'l':
+ if (is_eq(p, "lot_price"))
+ return MAKE_FUNCTOR(session_t::fn_lot_price);
+ else if (is_eq(p, "lot_date"))
+ return MAKE_FUNCTOR(session_t::fn_lot_date);
+ else if (is_eq(p, "lot_tag"))
+ return MAKE_FUNCTOR(session_t::fn_lot_tag);
+ break;
+
+ case 'm':
+ if (is_eq(p, "min"))
+ return MAKE_FUNCTOR(session_t::fn_min);
+ else if (is_eq(p, "max"))
+ return MAKE_FUNCTOR(session_t::fn_max);
+ break;
+
default:
break;
}
diff --git a/src/session.h b/src/session.h
index 597268ee..6de4b2dd 100644
--- a/src/session.h
+++ b/src/session.h
@@ -56,8 +56,7 @@ class session_t : public symbol_scope_t
friend void set_session_context(session_t * session);
public:
- bool flush_on_next_data_file;
- date_t::year_type current_year;
+ bool flush_on_next_data_file;
std::auto_ptr<journal_t> journal;
explicit session_t();
@@ -75,6 +74,11 @@ public:
void close_journal_files();
value_t fn_account(call_scope_t& scope);
+ value_t fn_min(call_scope_t& scope);
+ value_t fn_max(call_scope_t& scope);
+ value_t fn_lot_price(call_scope_t& scope);
+ value_t fn_lot_date(call_scope_t& scope);
+ value_t fn_lot_tag(call_scope_t& scope);
void report_options(std::ostream& out)
{
diff --git a/src/textual.cc b/src/textual.cc
index 113bafe8..800d0c4e 100644
--- a/src/textual.cc
+++ b/src/textual.cc
@@ -93,18 +93,17 @@ namespace {
static const std::size_t MAX_LINE = 1024;
public:
- parse_context_t& context;
- instance_t * parent;
- 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;
+ parse_context_t& context;
+ instance_t * parent;
+ 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<datetime_t> prev_epoch;
instance_t(parse_context_t& _context,
std::istream& _in,
@@ -207,11 +206,15 @@ instance_t::instance_t(parse_context_t& _context,
pathname(original_file ? *original_file : "/dev/stdin"), in(_in)
{
TRACE_CTOR(instance_t, "...");
+ DEBUG("times.epoch", "Saving epoch " << epoch);
+ prev_epoch = epoch; // declared in times.h
}
instance_t::~instance_t()
{
TRACE_DTOR(instance_t);
+ epoch = prev_epoch;
+ DEBUG("times.epoch", "Restored epoch to " << epoch);
}
void instance_t::parse()
@@ -420,7 +423,7 @@ void instance_t::clock_in_directive(char * line, bool /*capitalized*/)
position.end_line = linenum;
position.sequence = context.sequence++;
- time_xact_t event(position, parse_datetime(datetime, current_year),
+ time_xact_t event(position, parse_datetime(datetime),
p ? context.top_account()->find_account(p) : NULL,
n ? n : "",
end ? end : "");
@@ -449,7 +452,7 @@ void instance_t::clock_out_directive(char * line, bool /*capitalized*/)
position.end_line = linenum;
position.sequence = context.sequence++;
- time_xact_t event(position, parse_datetime(datetime, current_year),
+ time_xact_t event(position, parse_datetime(datetime),
p ? context.top_account()->find_account(p) : NULL,
n ? n : "",
end ? end : "");
@@ -503,7 +506,12 @@ void instance_t::nomarket_directive(char * line)
void instance_t::year_directive(char * line)
{
- current_year = lexical_cast<unsigned short>(skip_ws(line + 1));
+ unsigned short year(lexical_cast<unsigned short>(skip_ws(line + 1)));
+ DEBUG("times.epoch", "Setting current year to " << year);
+ // This must be set to the last day of the year, otherwise partial
+ // dates like "11/01" will refer to last year's november, not the
+ // current year.
+ epoch = datetime_t(date_t(year, 12, 31));
}
void instance_t::option_directive(char * line)
@@ -554,7 +562,7 @@ void instance_t::automated_xact_directive(char * line)
item = ae.get();
// This is a trailing note, and possibly a metadata info tag
- item->append_note(p + 1, context.scope, true, current_year);
+ item->append_note(p + 1, context.scope, true);
item->pos->end_pos = curr_pos;
item->pos->end_line++;
@@ -634,7 +642,7 @@ void instance_t::period_xact_directive(char * line)
pe->journal = &context.journal;
if (pe->finalize()) {
- context.journal.extend_xact(pe.get(), current_year);
+ context.journal.extend_xact(pe.get());
context.journal.period_xacts.push_back(pe.get());
pe->pos->end_pos = curr_pos;
@@ -885,14 +893,14 @@ void instance_t::assert_directive(char * line)
{
expr_t expr(line);
if (! expr.calc(context.scope).to_boolean())
- throw_(parse_error, _("Assertion failed: %1" << line));
+ throw_(parse_error, _("Assertion failed: %1") << line);
}
void instance_t::check_directive(char * line)
{
expr_t expr(line);
if (! expr.calc(context.scope).to_boolean())
- warning_(_("Check failed: %1" << line));
+ warning_(_("Check failed: %1") << line);
}
void instance_t::expr_directive(char * line)
@@ -1324,7 +1332,7 @@ post_t * instance_t::parse_post(char * line,
// Parse the optional note
if (next && *next == ';') {
- post->append_note(++next, context.scope, true, current_year);
+ post->append_note(++next, context.scope, true);
next = line + len;
DEBUG("textual.parse", "line " << linenum << ": "
<< "Parsed a posting note");
@@ -1343,8 +1351,7 @@ post_t * instance_t::parse_post(char * line,
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(), context.scope,
- true, current_year);
+ post->parse_tags(boost::get<string>(state).c_str(), context.scope, true);
}
TRACE_STOP(post_details, 1);
@@ -1407,9 +1414,9 @@ xact_t * instance_t::parse_xact(char * line,
if (char * p = std::strchr(line, '=')) {
*p++ = '\0';
- xact->_date_eff = parse_date(p, current_year);
+ xact->_date_eff = parse_date(p);
}
- xact->_date = parse_date(line, current_year);
+ xact->_date = parse_date(line);
// Parse the optional cleared flag: *
@@ -1456,7 +1463,7 @@ xact_t * instance_t::parse_xact(char * line,
// Parse the xact note
if (next && *next == ';')
- xact->append_note(++next, context.scope, false, current_year);
+ xact->append_note(++next, context.scope, false);
TRACE_STOP(xact_text, 1);
@@ -1483,7 +1490,7 @@ xact_t * instance_t::parse_xact(char * line,
if (*p == ';') {
// This is a trailing note, and possibly a metadata info tag
- item->append_note(p + 1, context.scope, true, current_year);
+ item->append_note(p + 1, context.scope, true);
item->pos->end_pos = curr_pos;
item->pos->end_line++;
}
@@ -1502,9 +1509,9 @@ xact_t * instance_t::parse_xact(char * line,
}
else if (! expr.calc(bound_scope).to_boolean()) {
if (c == 'a') {
- throw_(parse_error, _("Transaction assertion failed: %1" << p));
+ throw_(parse_error, _("Transaction assertion failed: %1") << p);
} else {
- warning_(_("Transaction check failed: %1" << p));
+ warning_(_("Transaction check failed: %1") << p);
}
}
}
@@ -1542,7 +1549,7 @@ xact_t * instance_t::parse_xact(char * line,
foreach (const state_t& state, context.state_stack)
if (state.type() == typeid(string))
xact->parse_tags(boost::get<string>(state).c_str(), context.scope,
- false, current_year);
+ false);
}
TRACE_STOP(xact_details, 1);
diff --git a/src/times.cc b/src/times.cc
index a9768f4f..31367e34 100644
--- a/src/times.cc
+++ b/src/times.cc
@@ -194,7 +194,6 @@ namespace {
std::deque<shared_ptr<date_io_t> > readers;
date_t parse_date_mask_routine(const char * date_str, date_io_t& io,
- optional_year year,
date_traits_t * traits = NULL)
{
VERIFY(std::strlen(date_str) < 127);
@@ -229,29 +228,26 @@ namespace {
*traits = io.traits;
if (! io.traits.has_year) {
- when = date_t(year ? *year : CURRENT_DATE().year(),
- when.month(), when.day());
+ when = date_t(CURRENT_DATE().year(), when.month(), when.day());
- if (! year && when.month() > CURRENT_DATE().month())
+ if (when.month() > CURRENT_DATE().month())
when -= gregorian::years(1);
}
}
return when;
}
- date_t parse_date_mask(const char * date_str, optional_year year,
- date_traits_t * traits = NULL)
+ date_t parse_date_mask(const char * date_str, date_traits_t * traits = NULL)
{
if (input_date_io.get()) {
date_t when = parse_date_mask_routine(date_str, *input_date_io.get(),
- year, traits);
+ traits);
if (! when.is_not_a_date())
return when;
}
foreach (shared_ptr<date_io_t>& reader, readers) {
- date_t when = parse_date_mask_routine(date_str, *reader.get(),
- year, traits);
+ date_t when = parse_date_mask_routine(date_str, *reader.get(), traits);
if (! when.is_not_a_date())
return when;
}
@@ -312,7 +308,7 @@ string_to_month_of_year(const std::string& str)
return none;
}
-datetime_t parse_datetime(const char * str, optional_year)
+datetime_t parse_datetime(const char * str)
{
datetime_t when = input_datetime_io->parse(str);
if (when.is_not_a_date_time())
@@ -320,18 +316,16 @@ datetime_t parse_datetime(const char * str, optional_year)
return when;
}
-date_t parse_date(const char * str, optional_year current_year)
+date_t parse_date(const char * str)
{
- return parse_date_mask(str, current_year);
+ return parse_date_mask(str);
}
-date_t date_specifier_t::begin(const optional_year& current_year) const
+date_t date_specifier_t::begin() const
{
- assert(year || current_year);
-
- year_type the_year = year ? *year : static_cast<year_type>(*current_year);
+ year_type the_year = year ? *year : year_type(CURRENT_DATE().year());
month_type the_month = month ? *month : date_t::month_type(1);
- day_type the_day = day ? *day : date_t::day_type(1);
+ day_type the_day = day ? *day : date_t::day_type(1);
#if !defined(NO_ASSERTS)
if (day)
@@ -348,14 +342,14 @@ date_t date_specifier_t::begin(const optional_year& current_year) const
static_cast<date_t::day_type>(the_day));
}
-date_t date_specifier_t::end(const optional_year& current_year) const
+date_t date_specifier_t::end() const
{
if (day || wday)
- return begin(current_year) + gregorian::days(1);
+ return begin() + gregorian::days(1);
else if (month)
- return begin(current_year) + gregorian::months(1);
+ return begin() + gregorian::months(1);
else if (year)
- return begin(current_year) + gregorian::years(1);
+ return begin() + gregorian::years(1);
else {
assert(false);
return date_t();
@@ -667,6 +661,16 @@ void date_parser_t::determine_when(date_parser_t::lexer_t::token_t& tok,
(boost::get<date_time::weekdays>(*tok.value));
break;
+ case lexer_t::token_t::TOK_TODAY:
+ specifier = date_specifier_t(CURRENT_DATE());
+ break;
+ case lexer_t::token_t::TOK_TOMORROW:
+ specifier = date_specifier_t(CURRENT_DATE() + gregorian::days(1));
+ break;
+ case lexer_t::token_t::TOK_YESTERDAY:
+ specifier = date_specifier_t(CURRENT_DATE() - gregorian::days(1));
+ break;
+
default:
tok.unexpected();
break;
@@ -687,14 +691,6 @@ date_interval_t date_parser_t::parse()
tok.kind != lexer_t::token_t::END_REACHED;
tok = lexer.next_token()) {
switch (tok.kind) {
-#if 0
- case lexer_t::token_t::TOK_INT:
- // jww (2009-11-18): NYI
- assert(! "Need to allow for expressions like \"4 months ago\"");
- tok.unexpected();
- break;
-#endif
-
case lexer_t::token_t::TOK_DATE:
if (! inclusion_specifier)
inclusion_specifier = date_specifier_t();
@@ -782,11 +778,44 @@ date_interval_t date_parser_t::parse()
tok = lexer.next_token();
switch (tok.kind) {
- case lexer_t::token_t::TOK_INT:
- // jww (2009-11-18): Allow things like "last 5 weeks"
- assert(! "Need to allow for expressions like \"last 5 weeks\"");
- tok.unexpected();
+ case lexer_t::token_t::TOK_INT: {
+ unsigned short amount = boost::get<unsigned short>(*tok.value);
+
+ date_t base(today);
+ date_t end(today);
+
+ tok = lexer.next_token();
+ switch (tok.kind) {
+ case lexer_t::token_t::TOK_YEARS:
+ base += gregorian::years(amount * adjust);
+ break;
+ case lexer_t::token_t::TOK_QUARTERS:
+ base += gregorian::months(amount * adjust * 3);
+ break;
+ case lexer_t::token_t::TOK_MONTHS:
+ base += gregorian::months(amount * adjust);
+ break;
+ case lexer_t::token_t::TOK_WEEKS:
+ base += gregorian::weeks(amount * adjust);
+ break;
+ case lexer_t::token_t::TOK_DAYS:
+ base += gregorian::days(amount * adjust);
+ break;
+ default:
+ tok.unexpected();
+ break;
+ }
+
+ if (adjust >= 0) {
+ date_t temp = base;
+ base = end;
+ end = temp;
+ }
+
+ since_specifier = date_specifier_t(base);
+ until_specifier = date_specifier_t(end);
break;
+ }
case lexer_t::token_t::TOK_A_MONTH: {
inclusion_specifier = date_specifier_t();
@@ -822,26 +851,40 @@ date_interval_t date_parser_t::parse()
}
case lexer_t::token_t::TOK_QUARTER: {
- date_t temp =
+ date_t base =
date_duration_t::find_nearest(today, date_duration_t::QUARTERS);
- temp += gregorian::months(3 * adjust);
- inclusion_specifier =
- date_specifier_t(static_cast<date_specifier_t::year_type>(temp.year()),
- temp.month());
-#if 0
- period.duration = date_duration_t(date_duration_t::QUARTERS, 1);
-#endif
+ date_t temp;
+ if (adjust < 0) {
+ temp = base + gregorian::months(3 * adjust);
+ }
+ else if (adjust == 0) {
+ temp = base + gregorian::months(3);
+ }
+ else if (adjust > 0) {
+ base += gregorian::months(3 * adjust);
+ temp = base + gregorian::months(3 * adjust);
+ }
+ since_specifier = date_specifier_t(adjust < 0 ? temp : base);
+ until_specifier = date_specifier_t(adjust < 0 ? base : temp);
break;
}
case lexer_t::token_t::TOK_WEEK: {
- date_t temp =
+ date_t base =
date_duration_t::find_nearest(today, date_duration_t::WEEKS);
- temp += gregorian::days(7 * adjust);
- inclusion_specifier = date_specifier_t(today);
-#if 0
- period.duration = date_duration_t(date_duration_t::WEEKS, 1);
-#endif
+ date_t temp;
+ if (adjust < 0) {
+ temp = base + gregorian::days(7 * adjust);
+ }
+ else if (adjust == 0) {
+ temp = base + gregorian::days(7);
+ }
+ else if (adjust > 0) {
+ base += gregorian::days(7 * adjust);
+ temp = base + gregorian::days(7 * adjust);
+ }
+ since_specifier = date_specifier_t(adjust < 0 ? temp : base);
+ until_specifier = date_specifier_t(adjust < 0 ? base : temp);
break;
}
@@ -862,6 +905,7 @@ date_interval_t date_parser_t::parse()
break;
}
}
+ break;
}
case lexer_t::token_t::TOK_TODAY:
@@ -876,7 +920,7 @@ date_interval_t date_parser_t::parse()
case lexer_t::token_t::TOK_EVERY:
tok = lexer.next_token();
- if (tok == lexer_t::token_t::TOK_INT) {
+ if (tok.kind == lexer_t::token_t::TOK_INT) {
int quantity = boost::get<unsigned short>(*tok.value);
tok = lexer.next_token();
switch (tok.kind) {
@@ -1052,8 +1096,8 @@ void date_interval_t::stabilize(const optional<date_t>& date)
// want a date early enough that the range will be correct, but late
// enough that we don't spend hundreds of thousands of loops skipping
// through time.
- optional<date_t> initial_start = start ? start : begin(date->year());
- optional<date_t> initial_finish = finish ? finish : end(date->year());
+ optional<date_t> initial_start = start ? start : begin();
+ optional<date_t> initial_finish = finish ? finish : end();
#if defined(DEBUG_ON)
if (initial_start)
@@ -1116,13 +1160,8 @@ void date_interval_t::stabilize(const optional<date_t>& date)
#endif
}
else if (range) {
- if (date) {
- start = range->begin(date->year());
- finish = range->end(date->year());
- } else {
- start = range->begin();
- finish = range->end();
- }
+ start = range->begin();
+ finish = range->end();
}
aligned = true;
}
@@ -1228,7 +1267,7 @@ date_interval_t& date_interval_t::operator++()
return *this;
}
-void date_interval_t::dump(std::ostream& out, optional_year current_year)
+void date_interval_t::dump(std::ostream& out)
{
out << _("--- Before stabilization ---") << std::endl;
@@ -1242,7 +1281,7 @@ void date_interval_t::dump(std::ostream& out, optional_year current_year)
if (duration)
out << _("duration: ") << duration->to_string() << std::endl;
- stabilize(begin(current_year));
+ stabilize(begin());
out << std::endl
<< _("--- After stabilization ---") << std::endl;
@@ -1317,7 +1356,7 @@ date_parser_t::lexer_t::token_t date_parser_t::lexer_t::next_token()
try {
date_traits_t traits;
- date_t when = parse_date_mask(possible_date.c_str(), none, &traits);
+ date_t when = parse_date_mask(possible_date.c_str(), &traits);
if (! when.is_not_a_date()) {
begin = i;
return token_t(token_t::TOK_DATE,
diff --git a/src/times.h b/src/times.h
index 02b39ef7..ac96669d 100644
--- a/src/times.h
+++ b/src/times.h
@@ -77,27 +77,23 @@ extern optional<datetime_t> epoch;
#define CURRENT_DATE() \
(epoch ? epoch->date() : boost::gregorian::day_clock::universal_day())
-extern date_time::weekdays start_of_week;
+extern date_time::weekdays start_of_week;
optional<date_time::weekdays>
string_to_day_of_week(const std::string& str);
optional<date_time::months_of_year>
string_to_month_of_year(const std::string& str);
-typedef optional<date_t::year_type> optional_year;
+datetime_t parse_datetime(const char * str);
-datetime_t parse_datetime(const char * str, optional_year current_year = none);
-
-inline datetime_t parse_datetime(const std::string& str,
- optional_year current_year = none) {
- return parse_datetime(str.c_str(), current_year);
+inline datetime_t parse_datetime(const std::string& str) {
+ return parse_datetime(str.c_str());
}
-date_t parse_date(const char * str, optional_year current_year = none);
+date_t parse_date(const char * str);
-inline date_t parse_date(const std::string& str,
- optional_year current_year = none) {
- return parse_date(str.c_str(), current_year);
+inline date_t parse_date(const std::string& str) {
+ return parse_date(str.c_str());
}
enum format_type_t {
@@ -329,12 +325,11 @@ public:
TRACE_DTOR(date_specifier_t);
}
- date_t begin(const optional_year& current_year = none) const;
- date_t end(const optional_year& current_year = none) const;
+ date_t begin() const;
+ date_t end() const;
- bool is_within(const date_t& date,
- const optional_year& current_year = none) const {
- return date >= begin(current_year) && date < end(current_year);
+ bool is_within(const date_t& date) const {
+ return date >= begin() && date < end();
}
optional<date_duration_t> implied_duration() const {
@@ -404,27 +399,26 @@ public:
TRACE_DTOR(date_range_t);
}
- optional<date_t> begin(const optional_year& current_year = none) const {
+ optional<date_t> begin() const {
if (range_begin)
- return range_begin->begin(current_year);
+ return range_begin->begin();
else
return none;
}
- optional<date_t> end(const optional_year& current_year = none) const {
+ optional<date_t> end() const {
if (range_end) {
if (end_inclusive)
- return range_end->end(current_year);
+ return range_end->end();
else
- return range_end->begin(current_year);
+ return range_end->begin();
} else {
return none;
}
}
- bool is_within(const date_t& date,
- const optional_year& current_year = none) const {
- optional<date_t> b = begin(current_year);
- optional<date_t> e = end(current_year);
+ bool is_within(const date_t& date) const {
+ optional<date_t> b = begin();
+ optional<date_t> e = end();
bool after_begin = b ? date >= *b : true;
bool before_end = e ? date < *e : true;
return after_begin && before_end;
@@ -482,19 +476,19 @@ public:
TRACE_DTOR(date_specifier_or_range_t);
}
- optional<date_t> begin(const optional_year& current_year = none) const {
+ optional<date_t> begin() const {
if (specifier_or_range.type() == typeid(date_specifier_t))
- return boost::get<date_specifier_t>(specifier_or_range).begin(current_year);
+ return boost::get<date_specifier_t>(specifier_or_range).begin();
else if (specifier_or_range.type() == typeid(date_range_t))
- return boost::get<date_range_t>(specifier_or_range).begin(current_year);
+ return boost::get<date_range_t>(specifier_or_range).begin();
else
return none;
}
- optional<date_t> end(const optional_year& current_year = none) const {
+ optional<date_t> end() const {
if (specifier_or_range.type() == typeid(date_specifier_t))
- return boost::get<date_specifier_t>(specifier_or_range).end(current_year);
+ return boost::get<date_specifier_t>(specifier_or_range).end();
else if (specifier_or_range.type() == typeid(date_range_t))
- return boost::get<date_range_t>(specifier_or_range).end(current_year);
+ return boost::get<date_range_t>(specifier_or_range).end();
else
return none;
}
@@ -571,11 +565,11 @@ public:
return is_valid();
}
- optional<date_t> begin(const optional_year& current_year = none) const {
- return start ? start : (range ? range->begin(current_year) : none);
+ optional<date_t> begin() const {
+ return start ? start : (range ? range->begin() : none);
}
- optional<date_t> end(const optional_year& current_year = none) const {
- return finish ? finish : (range ? range->end(current_year) : none);
+ optional<date_t> end() const {
+ return finish ? finish : (range ? range->end() : none);
}
void parse(const string& str);
@@ -590,7 +584,7 @@ public:
/** Find the current or next period containing date. Returns true if the
date_interval_t object has been altered to reflect the interval
containing date, or false if no such period can be found. */
- bool find_period(const date_t& date);
+ bool find_period(const date_t& date = CURRENT_DATE());
optional<date_t> inclusive_end() const {
if (end_of_duration)
@@ -601,7 +595,7 @@ public:
date_interval_t& operator++();
- void dump(std::ostream& out, optional_year current_year = none);
+ void dump(std::ostream& out);
#if defined(HAVE_BOOST_SERIALIZATION)
private:
diff --git a/src/xact.cc b/src/xact.cc
index 1188fd0f..d8ed3f8b 100644
--- a/src/xact.cc
+++ b/src/xact.cc
@@ -509,7 +509,7 @@ namespace {
foreach (post_t * p, post.xact->posts) {
bind_scope_t bound_scope(args, *p);
- if (expr->calc(bound_scope).to_boolean())
+ if (expr->calc(bound_scope, args.locus, args.depth).to_boolean())
return true;
}
return false;
@@ -522,7 +522,7 @@ namespace {
foreach (post_t * p, post.xact->posts) {
bind_scope_t bound_scope(args, *p);
- if (! expr->calc(bound_scope).to_boolean())
+ if (! expr->calc(bound_scope, args.locus, args.depth).to_boolean())
return false;
}
return true;
@@ -629,8 +629,7 @@ namespace {
} // unnamed namespace
-void auto_xact_t::extend_xact(xact_base_t& xact,
- optional<date_t::year_type> current_year)
+void auto_xact_t::extend_xact(xact_base_t& xact)
{
posts_list initial_posts(xact.posts.begin(), xact.posts.end());
@@ -680,10 +679,8 @@ void auto_xact_t::extend_xact(xact_base_t& xact,
if (deferred_notes) {
foreach (deferred_tag_data_t& data, *deferred_notes) {
if (data.apply_to_post == NULL)
- initial_post->parse_tags(data.tag_data.c_str(),
- bound_scope,
- data.overwrite_existing,
- current_year);
+ initial_post->parse_tags(data.tag_data.c_str(), bound_scope,
+ data.overwrite_existing);
}
}
if (check_exprs) {
@@ -694,9 +691,9 @@ void auto_xact_t::extend_xact(xact_base_t& xact,
else if (! pair.first.calc(bound_scope).to_boolean()) {
if (pair.second == auto_xact_t::EXPR_ASSERTION) {
throw_(parse_error,
- _("Transaction assertion failed: %1" << pair.first));
+ _("Transaction assertion failed: %1") << pair.first);
} else {
- warning_(_("Transaction check failed: %1" << pair.first));
+ warning_(_("Transaction check failed: %1") << pair.first);
}
}
}
@@ -778,10 +775,8 @@ void auto_xact_t::extend_xact(xact_base_t& xact,
if (deferred_notes) {
foreach (deferred_tag_data_t& data, *deferred_notes) {
if (data.apply_to_post == post)
- new_post->parse_tags(data.tag_data.c_str(),
- bound_scope,
- data.overwrite_existing,
- current_year);
+ new_post->parse_tags(data.tag_data.c_str(), bound_scope,
+ data.overwrite_existing);
}
}
}
diff --git a/src/xact.h b/src/xact.h
index a3c639b9..41e58545 100644
--- a/src/xact.h
+++ b/src/xact.h
@@ -196,15 +196,13 @@ public:
virtual void parse_tags(const char * p,
scope_t&,
- bool overwrite_existing = true,
- optional<date_t::year_type> = none) {
+ bool overwrite_existing = true) {
if (! deferred_notes)
deferred_notes = deferred_notes_list();
deferred_notes->push_back(deferred_tag_data_t(p, overwrite_existing));
}
- virtual void extend_xact(xact_base_t& xact,
- optional<date_t::year_type> current_year);
+ virtual void extend_xact(xact_base_t& xact);
#if defined(HAVE_BOOST_SERIALIZATION)
private: