summaryrefslogtreecommitdiff
path: root/src/xact.cc
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2009-11-14 20:43:28 -0500
committerJohn Wiegley <johnw@newartisans.com>2009-11-14 20:43:28 -0500
commitbadbeb545b9e700e6656dfbc348bfe1387cb2ffa (patch)
tree26237a150367e13a24917d994602f5f94f979ec8 /src/xact.cc
parent73baf9cd727407f6e47b410bbde3b4bcad482ae3 (diff)
parent8d698e5ccb471d546eee8a5bea6d6c56ec4b08c3 (diff)
downloadfork-ledger-badbeb545b9e700e6656dfbc348bfe1387cb2ffa.tar.gz
fork-ledger-badbeb545b9e700e6656dfbc348bfe1387cb2ffa.tar.bz2
fork-ledger-badbeb545b9e700e6656dfbc348bfe1387cb2ffa.zip
Merge branch 'next'
Diffstat (limited to 'src/xact.cc')
-rw-r--r--src/xact.cc84
1 files changed, 81 insertions, 3 deletions
diff --git a/src/xact.cc b/src/xact.cc
index 1cece187..f2694976 100644
--- a/src/xact.cc
+++ b/src/xact.cc
@@ -412,7 +412,7 @@ bool xact_base_t::verify()
continue;
if (post->amount.commodity() == post->cost->commodity())
- throw_(balance_error,
+ throw_(amount_error,
_("A posting's cost must be of a different commodity than its amount"));
}
@@ -538,6 +538,50 @@ bool xact_t::valid() const
return true;
}
+namespace {
+
+ bool post_pred(expr_t::ptr_op_t op, post_t& post)
+ {
+ switch (op->kind) {
+ case expr_t::op_t::VALUE:
+ return op->as_value().to_boolean();
+ break;
+
+ case expr_t::op_t::O_MATCH:
+ if (op->left()->kind == expr_t::op_t::IDENT &&
+ op->left()->as_ident() == "account" &&
+ op->right()->kind == expr_t::op_t::VALUE &&
+ op->right()->as_value().is_mask())
+ return op->right()->as_value().as_mask()
+ .match(post.reported_account()->fullname());
+ else
+ break;
+
+ case expr_t::op_t::O_NOT:
+ return ! post_pred(op->left(), post);
+
+ case expr_t::op_t::O_AND:
+ return post_pred(op->left(), post) && post_pred(op->right(), post);
+
+ case expr_t::op_t::O_OR:
+ return post_pred(op->left(), post) || post_pred(op->right(), post);
+
+ case expr_t::op_t::O_QUERY:
+ if (post_pred(op->left(), post))
+ return post_pred(op->right()->left(), post);
+ else
+ return post_pred(op->right()->right(), post);
+
+ default:
+ break;
+ }
+
+ throw_(calc_error, _("Unhandled operator"));
+ return false;
+ }
+
+} // unnamed namespace
+
void auto_xact_t::extend_xact(xact_base_t& xact)
{
posts_list initial_posts(xact.posts.begin(), xact.posts.end());
@@ -547,8 +591,42 @@ void auto_xact_t::extend_xact(xact_base_t& xact)
bool needs_further_verification = false;
foreach (post_t * initial_post, initial_posts) {
- if (! initial_post->has_flags(ITEM_GENERATED) &&
- predicate(*initial_post)) {
+ if (initial_post->has_flags(ITEM_GENERATED))
+ continue;
+
+ bool matches_predicate = false;
+ if (try_quick_match) {
+ try {
+ bool found_memoized_result = false;
+ if (! memoized_results.empty()) {
+ std::map<string, bool>::iterator i =
+ memoized_results.find(initial_post->account->fullname());
+ if (i != memoized_results.end()) {
+ found_memoized_result = true;
+ matches_predicate = (*i).second;
+ }
+ }
+
+ // Since the majority of people who use automated transactions simply
+ // match against account names, try using a *much* faster version of
+ // the predicate evaluator.
+ if (! found_memoized_result) {
+ matches_predicate = post_pred(predicate.get_op(), *initial_post);
+ memoized_results.insert
+ (std::pair<string, bool>(initial_post->account->fullname(),
+ matches_predicate));
+ }
+ }
+ catch (...) {
+ DEBUG("xact.extend.fail",
+ "The quick matcher failed, going back to regular eval");
+ try_quick_match = false;
+ matches_predicate = predicate(*initial_post);
+ }
+ } else {
+ matches_predicate = predicate(*initial_post);
+ }
+ if (matches_predicate) {
foreach (post_t * post, posts) {
amount_t post_amount;
if (post->amount.is_null()) {