diff options
author | John Wiegley <johnw@newartisans.com> | 2010-06-12 15:42:02 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2010-06-12 15:43:00 -0400 |
commit | b1b4e2aadff5983d443d70c09ea86a41b015873f (patch) | |
tree | 2c40305c9f9841a4c3d453a4a5c49ec69056b4b2 | |
parent | 0555e7f61ef14ec667f8ba611e60fd96133a9676 (diff) | |
download | fork-ledger-b1b4e2aadff5983d443d70c09ea86a41b015873f.tar.gz fork-ledger-b1b4e2aadff5983d443d70c09ea86a41b015873f.tar.bz2 fork-ledger-b1b4e2aadff5983d443d70c09ea86a41b015873f.zip |
Add support for typed metadata
The metadata construct 'Key: Value' is now just a special case for
'Key:: "Value"'. Another after a :: in metadata setting is parsed as a
full value expression and typed as such. For example:
; Key:: $400 + $500
ledger -l 'tag("Key") < $1000'
-rw-r--r-- | src/item.cc | 30 | ||||
-rw-r--r-- | src/item.h | 12 | ||||
-rw-r--r-- | src/precmd.cc | 1 | ||||
-rw-r--r-- | src/textual.cc | 14 | ||||
-rw-r--r-- | src/timelog.cc | 9 | ||||
-rw-r--r-- | src/timelog.h | 6 | ||||
-rw-r--r-- | test/regress/F559EC12.test | 2 | ||||
-rwxr-xr-x | tools/proof | 2 |
8 files changed, 52 insertions, 24 deletions
diff --git a/src/item.cc b/src/item.cc index 1f42510c..f59c9e29 100644 --- a/src/item.cc +++ b/src/item.cc @@ -135,7 +135,9 @@ item_t::set_tag(const string& tag, } } -void item_t::parse_tags(const char * p, bool overwrite_existing, +void item_t::parse_tags(const char * p, + scope_t& scope, + bool overwrite_existing, optional<date_t::year_type> current_year) { if (const char * b = std::strchr(p, '[')) { @@ -164,14 +166,21 @@ void item_t::parse_tags(const char * p, bool overwrite_existing, std::strcpy(buf.get(), p); string tag; + bool by_value = false; for (char * q = std::strtok(buf.get(), " \t"); q; q = std::strtok(NULL, " \t")) { const string::size_type len = std::strlen(q); + if (len < 2) continue; if (! tag.empty()) { - string_map::iterator i = - set_tag(tag, string_value(string(p + (q - buf.get()))), - overwrite_existing); + string_map::iterator i; + string field(p + (q - buf.get())); + if (by_value) { + bind_scope_t bound_scope(scope, *this); + i = set_tag(tag, expr_t(field).calc(bound_scope), overwrite_existing); + } else { + i = set_tag(tag, string_value(field), overwrite_existing); + } (*i).second.second = true; break; } @@ -184,12 +193,19 @@ void item_t::parse_tags(const char * p, bool overwrite_existing, } } else if (q[len - 1] == ':') { // a metadata setting - tag = string(q, len - 1); + int index = 1; + if (q[len - 2] == ':') { + by_value = true; + index = 2; + } + tag = string(q, len - index); } } } -void item_t::append_note(const char * p, bool overwrite_existing, +void item_t::append_note(const char * p, + scope_t& scope, + bool overwrite_existing, optional<date_t::year_type> current_year) { if (note) { @@ -199,7 +215,7 @@ void item_t::append_note(const char * p, bool overwrite_existing, note = p; } - parse_tags(p, overwrite_existing, current_year); + parse_tags(p, scope, overwrite_existing, current_year); } namespace { @@ -162,10 +162,14 @@ public: const optional<value_t>& value = none, const bool overwrite_existing = true); - virtual void parse_tags(const char * p, bool overwrite_existing = true, - optional<date_t::year_type> current_year = none); - virtual void append_note(const char * p, 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, + 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); static bool use_effective_date; diff --git a/src/precmd.cc b/src/precmd.cc index 43a9835c..f78d766e 100644 --- a/src/precmd.cc +++ b/src/precmd.cc @@ -54,6 +54,7 @@ namespace { << " ; This note applies to all postings. :SecondTag:\n" << " Expenses:Books 20 BOOK @ $10\n" << " ; Metadata: Some Value\n" + << " ; Typed:: $100 + $200\n" << " ; :ExampleTag:\n" << " ; Here follows a note describing the posting.\n" << " Liabilities:MasterCard $-200.00\n"; diff --git a/src/textual.cc b/src/textual.cc index 5308fa18..9a4fee8e 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -67,7 +67,7 @@ namespace { std::size_t sequence; parse_context_t(journal_t& _journal, scope_t& _scope) - : journal(_journal), scope(_scope), timelog(journal), + : journal(_journal), scope(_scope), timelog(journal, scope), strict(false), count(0), errors(0), sequence(1) {} bool front_is_account() { @@ -1236,7 +1236,7 @@ post_t * instance_t::parse_post(char * line, // Parse the optional note if (next && *next == ';') { - post->append_note(++next, true, current_year); + post->append_note(++next, context.scope, true, current_year); next = line + len; DEBUG("textual.parse", "line " << linenum << ": " << "Parsed a posting note"); @@ -1255,7 +1255,8 @@ 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(), true); + post->parse_tags(boost::get<string>(state).c_str(), context.scope, + true); } TRACE_STOP(post_details, 1); @@ -1367,7 +1368,7 @@ xact_t * instance_t::parse_xact(char * line, // Parse the xact note if (next && *next == ';') - xact->append_note(++next, current_year); + xact->append_note(++next, context.scope, false, current_year); TRACE_STOP(xact_text, 1); @@ -1392,7 +1393,7 @@ xact_t * instance_t::parse_xact(char * line, item = xact.get(); // This is a trailing note, and possibly a metadata info tag - item->append_note(p + 1, true, current_year); + item->append_note(p + 1, context.scope, true, current_year); item->pos->end_pos = curr_pos; item->pos->end_line++; } else { @@ -1426,7 +1427,8 @@ xact_t * instance_t::parse_xact(char * line, 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(), false); + xact->parse_tags(boost::get<string>(state).c_str(), context.scope, + false); } TRACE_STOP(xact_details, 1); diff --git a/src/timelog.cc b/src/timelog.cc index 241824cd..698e2420 100644 --- a/src/timelog.cc +++ b/src/timelog.cc @@ -42,7 +42,8 @@ namespace ledger { namespace { void clock_out_from_timelog(std::list<time_xact_t>& time_xacts, time_xact_t out_event, - journal_t& journal) + journal_t& journal, + scope_t& scope) { time_xact_t event; @@ -94,7 +95,7 @@ namespace { curr->pos = event.position; if (! event.note.empty()) - curr->append_note(event.note.c_str()); + curr->append_note(event.note.c_str(), scope); char buf[32]; std::sprintf(buf, "%lds", long((out_event.checkin - event.checkin) @@ -129,7 +130,7 @@ time_log_t::~time_log_t() foreach (account_t * account, accounts) clock_out_from_timelog(time_xacts, time_xact_t(none, CURRENT_TIME(), account), - journal); + journal, scope); assert(time_xacts.empty()); } @@ -152,7 +153,7 @@ void time_log_t::clock_out(time_xact_t event) if (time_xacts.empty()) throw std::logic_error(_("Timelog check-out event without a check-in")); - clock_out_from_timelog(time_xacts, event, journal); + clock_out_from_timelog(time_xacts, event, journal, scope); } } // namespace ledger diff --git a/src/timelog.h b/src/timelog.h index 79629408..92b80edc 100644 --- a/src/timelog.h +++ b/src/timelog.h @@ -87,10 +87,12 @@ class time_log_t { std::list<time_xact_t> time_xacts; journal_t& journal; + scope_t& scope; public: - time_log_t(journal_t& _journal) : journal(_journal) { - TRACE_CTOR(time_log_t, "journal_t&"); + time_log_t(journal_t& _journal, scope_t& _scope) + : journal(_journal), scope(_scope) { + TRACE_CTOR(time_log_t, "journal_t&, scope_t&"); } ~time_log_t(); diff --git a/test/regress/F559EC12.test b/test/regress/F559EC12.test index c8b686db..d6b2521e 100644 --- a/test/regress/F559EC12.test +++ b/test/regress/F559EC12.test @@ -6,6 +6,7 @@ format "%-12(scrub(amount))" ; This note applies to all postings. :SecondTag: Expenses:Books 20 BOOK @ $10 ; Metadata: Some Value + ; Typed:: $100 + $200 ; :ExampleTag: ; Here follows a note describing the posting. Liabilities:MasterCard $-200.00 @@ -27,6 +28,7 @@ format "%12(scrub(amount))" ; This note applies to all postings. :SecondTag: Expenses:Books 20 BOOK @ $10 ; Metadata: Some Value + ; Typed:: $100 + $200 ; :ExampleTag: ; Here follows a note describing the posting. Liabilities:MasterCard $-200.00 diff --git a/tools/proof b/tools/proof index daebc68c..755c3fe7 100755 --- a/tools/proof +++ b/tools/proof @@ -12,7 +12,7 @@ if [[ -f ~/Products/last-proofed && \ exit 0 fi -rm -fr ~/Products/ledger* +rm -fr ~/Products/ledger-proof time ./acprep --enable-cache --enable-doxygen \ --universal -j16 --warn proof 2>&1 | \ |