From ac885a907525589aa56266d9a2527cdc7127c9cb Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Tue, 10 Nov 2009 18:44:08 -0500 Subject: All strings passed to Python are now Unicode objects --- test/convert.py | 1 + 1 file changed, 1 insertion(+) (limited to 'test') diff --git a/test/convert.py b/test/convert.py index d61da790..0c64fde4 100755 --- a/test/convert.py +++ b/test/convert.py @@ -150,6 +150,7 @@ for line in fd.readlines(): line = re.sub('set_session_context\(\)', 'set_session_context()\n self.testSession = None', line) line = re.sub('([a-z_]+?)_t\b', '\\1', line) + line = re.sub('("[^"]+")', 'u\\1', line) line = re.sub('std::string\(([^)]+?)\)', '\\1', line) line = re.sub('string\(([^)]+?)\)', '\\1', line) line = re.sub('\.print\(([^)]+?)\)', '.print_(\\1)', line) -- cgit v1.2.3 From e8ea2d4938fcbb0988fd1e2021d97a519c67ffd8 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Wed, 11 Nov 2009 03:41:59 -0500 Subject: Automated postings defer amount expression calculation This allows for value expressions to be used which reference the incoming posting, for example: = Income:Clients: (Liabilities:Taxes:VAT1) (floor(amount) * 1) (Liabilities:Taxes:VAT2) 0.19 2009/07/27 * Invoice Assets:Bank:Checking $1,190.45 Income:Clients:ACME_Inc The automated posting for VAT1 will use the floored amount multiplied by a factor, while the posting for VAT2 multiples the whole amount as before. --- src/archive.cc | 2 +- src/hooks.h | 4 +-- src/journal.cc | 4 +-- src/post.h | 2 ++ src/py_journal.cc | 8 ++--- src/textual.cc | 75 +++++++++++++++++++++++++++------------------- src/xact.cc | 47 ++++++++++++++++++----------- src/xact.h | 18 +++++------ test/regress/25A099C9.test | 12 ++++---- 9 files changed, 99 insertions(+), 73 deletions(-) (limited to 'test') diff --git a/src/archive.cc b/src/archive.cc index f76b7543..5ea6cd8e 100644 --- a/src/archive.cc +++ b/src/archive.cc @@ -43,7 +43,7 @@ #include "xact.h" #define LEDGER_MAGIC 0x4c454447 -#define ARCHIVE_VERSION 0x03000004 +#define ARCHIVE_VERSION 0x03000005 //BOOST_IS_ABSTRACT(ledger::scope_t) BOOST_CLASS_EXPORT(ledger::scope_t) diff --git a/src/hooks.h b/src/hooks.h index da6fcf84..20c7750c 100644 --- a/src/hooks.h +++ b/src/hooks.h @@ -70,9 +70,9 @@ public: list.remove(func); } - bool run_hooks(Data& item, bool post) { + bool run_hooks(Data& item) { foreach (T * func, list) - if (! (*func)(item, post)) + if (! (*func)(item)) return false; return true; } diff --git a/src/journal.cc b/src/journal.cc index 550b4f4c..b7ad9a23 100644 --- a/src/journal.cc +++ b/src/journal.cc @@ -126,9 +126,7 @@ bool journal_t::add_xact(xact_t * xact) { xact->journal = this; - if (! xact_finalize_hooks.run_hooks(*xact, false) || - ! xact->finalize() || - ! xact_finalize_hooks.run_hooks(*xact, true)) { + if (! xact->finalize() || ! xact_finalize_hooks.run_hooks(*xact)) { xact->journal = NULL; return false; } diff --git a/src/post.h b/src/post.h index addf0629..d9e50580 100644 --- a/src/post.h +++ b/src/post.h @@ -61,6 +61,7 @@ public: account_t * account; amount_t amount; // can be null until finalization + optional amount_expr; optional cost; optional assigned_amount; @@ -212,6 +213,7 @@ private: ar & xact; ar & account; ar & amount; + ar & amount_expr; ar & cost; ar & assigned_amount; } diff --git a/src/py_journal.cc b/src/py_journal.cc index 17c42c21..88447b92 100644 --- a/src/py_journal.cc +++ b/src/py_journal.cc @@ -136,8 +136,8 @@ namespace { py_xact_finalizer_t(object obj) : pyobj(obj) {} py_xact_finalizer_t(const py_xact_finalizer_t& other) : pyobj(other.pyobj) {} - virtual bool operator()(xact_t& xact, bool post) { - return call(pyobj.ptr(), xact, post); + virtual bool operator()(xact_t& xact) { + return call(pyobj.ptr(), xact); } }; @@ -161,9 +161,9 @@ namespace { } } - void py_run_xact_finalizers(journal_t& journal, xact_t& xact, bool post) + void py_run_xact_finalizers(journal_t& journal, xact_t& xact) { - journal.xact_finalize_hooks.run_hooks(xact, post); + journal.xact_finalize_hooks.run_hooks(xact); } std::size_t py_read(journal_t& journal, const string& pathname) diff --git a/src/textual.cc b/src/textual.cc index f5d0635c..8f0dd89c 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -132,10 +132,12 @@ namespace { std::streamsize len, account_t * account, xact_t * xact, - bool honor_strict = true); + bool honor_strict = true, + bool defer_expr = false); - bool parse_posts(account_t * account, - xact_base_t& xact); + bool parse_posts(account_t * account, + xact_base_t& xact, + const bool defer_expr = false); xact_t * parse_xact(char * line, std::streamsize len, @@ -145,11 +147,13 @@ namespace { const string& name); }; - void parse_amount_expr(scope_t& scope, - std::istream& in, - amount_t& amount, - post_t * post, - const parse_flags_t& flags = PARSE_DEFAULT) + void parse_amount_expr(scope_t& scope, + std::istream& in, + amount_t& amount, + optional * amount_expr, + post_t * post, + const parse_flags_t& flags = PARSE_DEFAULT, + const bool defer_expr = false) { expr_t expr(in, flags.plus_flags(PARSE_PARTIAL)); @@ -166,17 +170,22 @@ namespace { if (expr) { bind_scope_t bound_scope(scope, *post); - - value_t result(expr.calc(bound_scope)); - if (result.is_long()) { - amount = result.to_amount(); + if (defer_expr) { + assert(amount_expr); + *amount_expr = expr; + (*amount_expr)->compile(bound_scope); } else { - if (! result.is_amount()) - throw_(parse_error, _("Postings may only specify simple amounts")); - - amount = result.as_amount(); + 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); } - DEBUG("textual.parse", "The posting amount is " << amount); } } } @@ -548,7 +557,7 @@ void instance_t::automated_xact_directive(char * line) reveal_context = false; - if (parse_posts(account_stack.front(), *ae.get())) { + if (parse_posts(account_stack.front(), *ae.get(), true)) { reveal_context = true; journal.auto_xacts.push_back(ae.get()); @@ -592,7 +601,7 @@ void instance_t::period_xact_directive(char * line) pe->journal = &journal; if (pe->finalize()) { - extend_xact_base(&journal, *pe.get(), true); + extend_xact_base(&journal, *pe.get()); journal.period_xacts.push_back(pe.get()); @@ -817,7 +826,8 @@ post_t * instance_t::parse_post(char * line, std::streamsize len, account_t * account, xact_t * xact, - bool honor_strict) + bool honor_strict, + bool defer_expr) { TRACE_START(post_details, 1, "Time spent parsing postings:"); @@ -919,8 +929,9 @@ 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.get(), - PARSE_NO_REDUCE | PARSE_SINGLE | PARSE_NO_ASSIGN); + parse_amount_expr(scope, stream, post->amount, &post->amount_expr, + post.get(), PARSE_NO_REDUCE | PARSE_SINGLE | + PARSE_NO_ASSIGN, defer_expr); if (! post->amount.is_null() && honor_strict && strict && post->amount.has_commodity() && @@ -965,9 +976,9 @@ 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, post.get(), - PARSE_NO_MIGRATE | PARSE_SINGLE | - PARSE_NO_ASSIGN); + parse_amount_expr(scope, cstream, *post->cost, NULL, post.get(), + PARSE_NO_MIGRATE | PARSE_SINGLE | PARSE_NO_ASSIGN, + defer_expr); if (post->cost->sign() < 0) throw parse_error(_("A posting's cost may not be negative")); @@ -1017,8 +1028,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, post.get(), - PARSE_SINGLE | PARSE_NO_MIGRATE); + parse_amount_expr(scope, stream, *post->assigned_amount, NULL, + post.get(), PARSE_SINGLE | PARSE_NO_MIGRATE, + defer_expr); if (post->assigned_amount->is_null()) { if (post->amount.is_null()) @@ -1118,8 +1130,9 @@ post_t * instance_t::parse_post(char * line, } } -bool instance_t::parse_posts(account_t * account, - xact_base_t& xact) +bool instance_t::parse_posts(account_t * account, + xact_base_t& xact, + const bool defer_expr) { TRACE_START(xact_posts, 1, "Time spent parsing postings:"); @@ -1130,7 +1143,9 @@ 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, false)) { + if (post_t * post = + parse_post(line, len, account, NULL, /* honor_strict= */ false, + defer_expr)) { xact.add_post(post); added = true; } diff --git a/src/xact.cc b/src/xact.cc index d94464a6..8ac5280a 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -480,7 +480,7 @@ bool xact_t::valid() const return true; } -void auto_xact_t::extend_xact(xact_base_t& xact, bool post_handler) +void auto_xact_t::extend_xact(xact_base_t& xact) { posts_list initial_posts(xact.posts.begin(), xact.posts.end()); @@ -490,20 +490,32 @@ void auto_xact_t::extend_xact(xact_base_t& xact, bool post_handler) if (! initial_post->has_flags(ITEM_GENERATED) && predicate(*initial_post)) { foreach (post_t * post, posts) { - amount_t amt; - assert(post->amount); - if (! post->amount.commodity()) { - if ((post_handler && - ! initial_post->has_flags(POST_CALCULATED)) || - initial_post->amount.is_null()) - continue; - amt = initial_post->amount * post->amount; + amount_t post_amount; + if (post->amount.is_null()) { + if (! post->amount_expr) + throw_(amount_error, + _("Automated transaction's posting has no amount")); + + bind_scope_t bound_scope(*scope_t::default_scope, *initial_post); + value_t result(post->amount_expr->calc(bound_scope)); + if (result.is_long()) { + post_amount = result.to_amount(); + } else { + if (! result.is_amount()) + throw_(amount_error, + _("Amount expressions must result in a simple amount")); + post_amount = result.as_amount(); + } } else { - if (post_handler) - continue; - amt = post->amount; + post_amount = post->amount; } + amount_t amt; + if (! post_amount.commodity()) + amt = initial_post->amount * post_amount; + else + amt = post_amount; + IF_DEBUG("xact.extend") { DEBUG("xact.extend", "Initial post on line " << initial_post->pos->beg_line << ": " @@ -517,12 +529,12 @@ void auto_xact_t::extend_xact(xact_base_t& xact, bool post_handler) DEBUG("xact.extend", "Posting on line " << post->pos->beg_line << ": " - << "amount " << post->amount << ", amt " << amt - << " (precision " << post->amount.precision() + << "amount " << post_amount << ", amt " << amt + << " (precision " << post_amount.precision() << " != " << amt.precision() << ")"); #if defined(DEBUG_ON) - if (post->amount.keep_precision()) + if (post_amount.keep_precision()) DEBUG("xact.extend", " precision is kept"); if (amt.keep_precision()) DEBUG("xact.extend", " amt precision is kept"); @@ -556,11 +568,10 @@ void auto_xact_t::extend_xact(xact_base_t& xact, bool post_handler) } void extend_xact_base(journal_t * journal, - xact_base_t& base, - bool post_handler) + xact_base_t& base) { foreach (auto_xact_t * xact, journal->auto_xacts) - xact->extend_xact(base, post_handler); + xact->extend_xact(base); } void to_xml(std::ostream& out, const xact_t& xact) diff --git a/src/xact.h b/src/xact.h index 9a52fafe..ff1f65fa 100644 --- a/src/xact.h +++ b/src/xact.h @@ -142,7 +142,7 @@ private: struct xact_finalizer_t { virtual ~xact_finalizer_t() {} - virtual bool operator()(xact_t& xact, bool post) = 0; + virtual bool operator()(xact_t& xact) = 0; }; class auto_xact_t : public xact_base_t @@ -167,7 +167,7 @@ public: TRACE_DTOR(auto_xact_t); } - virtual void extend_xact(xact_base_t& xact, bool post); + virtual void extend_xact(xact_base_t& xact); #if defined(HAVE_BOOST_SERIALIZATION) private: @@ -201,7 +201,7 @@ struct auto_xact_finalizer_t : public xact_finalizer_t TRACE_DTOR(auto_xact_finalizer_t); } - virtual bool operator()(xact_t& xact, bool post); + virtual bool operator()(xact_t& xact); #if defined(HAVE_BOOST_SERIALIZATION) private: @@ -258,7 +258,7 @@ class func_finalizer_t : public xact_finalizer_t func_finalizer_t(); public: - typedef function func_t; + typedef function func_t; func_t func; @@ -273,15 +273,15 @@ public: TRACE_DTOR(func_finalizer_t); } - virtual bool operator()(xact_t& xact, bool post) { - return func(xact, post); + virtual bool operator()(xact_t& xact) { + return func(xact); } }; -void extend_xact_base(journal_t * journal, xact_base_t& xact, bool post); +void extend_xact_base(journal_t * journal, xact_base_t& xact); -inline bool auto_xact_finalizer_t::operator()(xact_t& xact, bool post) { - extend_xact_base(journal, xact, post); +inline bool auto_xact_finalizer_t::operator()(xact_t& xact) { + extend_xact_base(journal, xact); return true; } diff --git a/test/regress/25A099C9.test b/test/regress/25A099C9.test index 8aa8954f..604939d8 100644 --- a/test/regress/25A099C9.test +++ b/test/regress/25A099C9.test @@ -4,16 +4,16 @@ >>>2 While parsing file "$sourcepath/src/amount.h", line 67: Error: No quantity specified for amount -While parsing file "$sourcepath/src/amount.h", line 712: +While parsing file "$sourcepath/src/amount.h", line 721: Error: Invalid date/time: line amount_t amoun -While parsing file "$sourcepath/src/amount.h", line 718: +While parsing file "$sourcepath/src/amount.h", line 727: Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/src/amount.h", line 724: +While parsing file "$sourcepath/src/amount.h", line 733: Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/src/amount.h", line 730: +While parsing file "$sourcepath/src/amount.h", line 739: Error: Invalid date/time: line string amount_ -While parsing file "$sourcepath/src/amount.h", line 736: +While parsing file "$sourcepath/src/amount.h", line 745: Error: Invalid date/time: line std::ostream& -While parsing file "$sourcepath/src/amount.h", line 743: +While parsing file "$sourcepath/src/amount.h", line 752: Error: Invalid date/time: line std::istream& === 7 -- cgit v1.2.3