summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2010-06-12 15:42:02 -0400
committerJohn Wiegley <johnw@newartisans.com>2010-06-12 15:43:00 -0400
commitb1b4e2aadff5983d443d70c09ea86a41b015873f (patch)
tree2c40305c9f9841a4c3d453a4a5c49ec69056b4b2
parent0555e7f61ef14ec667f8ba611e60fd96133a9676 (diff)
downloadfork-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.cc30
-rw-r--r--src/item.h12
-rw-r--r--src/precmd.cc1
-rw-r--r--src/textual.cc14
-rw-r--r--src/timelog.cc9
-rw-r--r--src/timelog.h6
-rw-r--r--test/regress/F559EC12.test2
-rwxr-xr-xtools/proof2
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 {
diff --git a/src/item.h b/src/item.h
index 61438593..209b2dc2 100644
--- a/src/item.h
+++ b/src/item.h
@@ -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 | \