summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--entry.cc31
-rw-r--r--error.h2
-rw-r--r--expr.cc17
-rw-r--r--expr.h4
-rw-r--r--format.cc23
-rw-r--r--format.h7
-rw-r--r--main.cc4
-rw-r--r--scope.h72
-rw-r--r--system.hh1
-rw-r--r--textual.cc36
-rw-r--r--xact.cc39
11 files changed, 161 insertions, 75 deletions
diff --git a/entry.cc b/entry.cc
index 287f6555..e9b932fe 100644
--- a/entry.cc
+++ b/entry.cc
@@ -357,17 +357,23 @@ void entry_t::add_xact(xact_t * xact)
}
namespace {
- value_t get_date(call_scope_t& scope)
- {
- entry_t& entry(downcast<entry_t>(*scope.parent));
+ value_t get_date(entry_t& entry) {
return entry.date();
}
- value_t get_payee(call_scope_t& scope)
+ value_t get_payee(entry_t& entry)
{
- entry_t& entry(downcast<entry_t>(*scope.parent));
return string_value(entry.payee);
}
+
+ typedef value_t (*entry_func_t)(entry_t&);
+
+ template <entry_func_t Func>
+ value_t get_wrapper(call_scope_t& scope)
+ {
+ xact_t& xact(downcast<xact_t>(*scope.parent));
+ return (*Func)(*xact.entry);
+ }
}
expr_t::ptr_op_t entry_t::lookup(const string& name)
@@ -375,21 +381,14 @@ expr_t::ptr_op_t entry_t::lookup(const string& name)
switch (name[0]) {
case 'd':
if (name[1] == '\0' || name == "date")
- return WRAP_FUNCTOR(bind(get_date, _1));
+ return WRAP_FUNCTOR(get_wrapper<&get_date>);
break;
case 'p':
if (name[1] == '\0' || name == "payee")
- return WRAP_FUNCTOR(bind(get_payee, _1));
+ return WRAP_FUNCTOR(get_wrapper<&get_payee>);
break;
}
-
-#if 0
- // jww (2008-07-29): Should it go to the containing journal next, or to the
- // session?
- return entry->lookup(name);
-#else
return expr_t::ptr_op_t();
-#endif
}
bool entry_t::valid() const
@@ -465,10 +464,10 @@ void auto_entry_t::extend_entry(entry_base_t& entry, bool post)
}
}
-void extend_entry_base(journal_t * journal, entry_base_t& entry, bool post)
+void extend_entry_base(journal_t * journal, entry_base_t& base, bool post)
{
foreach (auto_entry_t * entry, journal->auto_entries)
- entry->extend_entry(*entry, post);
+ entry->extend_entry(base, post);
}
} // namespace ledger
diff --git a/error.h b/error.h
index 4eaf72a8..fafef08e 100644
--- a/error.h
+++ b/error.h
@@ -37,7 +37,7 @@ namespace ledger {
extern std::ostringstream _desc_buffer;
template <typename T>
-inline void throw_func(const std::string& message) {
+inline void throw_func(const string& message) {
_desc_buffer.str("");
throw T(message);
}
diff --git a/expr.cc b/expr.cc
index c326944f..37433179 100644
--- a/expr.cc
+++ b/expr.cc
@@ -44,7 +44,7 @@ expr_t::expr_t() : compiled(false)
}
expr_t::expr_t(const expr_t& other)
- : ptr(other.ptr), str(other.str), compiled(false)
+ : ptr(other.ptr), str(other.str), compiled(other.compiled)
{
TRACE_CTOR(expr_t, "copy");
}
@@ -109,7 +109,7 @@ void expr_t::parse(std::istream& in, const unsigned int flags)
void expr_t::compile(scope_t& scope)
{
- if (ptr.get()) {
+ if (ptr.get() && ! compiled) {
ptr = ptr->compile(scope);
compiled = true;
}
@@ -127,9 +127,16 @@ value_t expr_t::calc(scope_t& scope)
bool expr_t::is_constant() const
{
+ assert(compiled);
return ptr.get() && ptr->is_value();
}
+bool expr_t::is_function() const
+{
+ assert(compiled);
+ return ptr.get() && ptr->is_function();
+}
+
value_t& expr_t::constant_value()
{
assert(is_constant());
@@ -142,6 +149,12 @@ const value_t& expr_t::constant_value() const
return ptr->as_value();
}
+function_t& expr_t::get_function()
+{
+ assert(is_function());
+ return ptr->as_function_lval();
+}
+
value_t expr_t::eval(const string& _expr, scope_t& scope)
{
return expr_t(_expr).calc(scope);
diff --git a/expr.h b/expr.h
index 3cdc77a6..8e1ee19a 100644
--- a/expr.h
+++ b/expr.h
@@ -102,9 +102,13 @@ public:
value_t calc(scope_t& scope) const;
bool is_constant() const;
+ bool is_function() const;
+
value_t& constant_value();
const value_t& constant_value() const;
+ function_t& get_function();
+
void print(std::ostream& out, scope_t& scope) const;
void dump(std::ostream& out) const;
void read(const char *& data);
diff --git a/format.cc b/format.cc
index 1255d25b..772fa0bc 100644
--- a/format.cc
+++ b/format.cc
@@ -242,11 +242,24 @@ void format_t::format(std::ostream& out_str, scope_t& scope)
case element_t::EXPR:
try {
- if (elem->max_width == 0)
- elem->expr.calc(scope).dump(out, elem->min_width);
- else
- out << truncate(elem->expr.calc(scope).as_string(),
- elem->max_width);
+ elem->expr.compile(scope);
+
+ if (elem->expr.is_function()) {
+ call_scope_t args(scope);
+ args.push_back(long(elem->max_width));
+
+ if (elem->max_width == 0)
+ elem->expr.get_function()(args).dump(out, elem->min_width);
+ else
+ out << truncate(elem->expr.get_function()(args).as_string(),
+ elem->max_width);
+ } else {
+ if (elem->max_width == 0)
+ elem->expr.calc(scope).dump(out, elem->min_width);
+ else
+ out << truncate(elem->expr.calc(scope).as_string(),
+ elem->max_width);
+ }
}
catch (const calc_error&) {
out << (string("%") + elem->chars);
diff --git a/format.h b/format.h
index 840ff564..585216bf 100644
--- a/format.h
+++ b/format.h
@@ -74,6 +74,8 @@ class format_t : public noncopyable
static bool ansi_codes;
static bool ansi_invert;
+ static element_t * parse_elements(const string& fmt);
+
public:
format_t() {
TRACE_CTOR(format_t, "");
@@ -100,11 +102,8 @@ public:
elem->dump(out);
}
-private:
- static element_t * parse_elements(const string& fmt);
-
static string truncate(const string& str, unsigned int width,
- const bool is_account = false);
+ const bool is_account = false);
};
} // namespace ledger
diff --git a/main.cc b/main.cc
index f58578fd..78a9433b 100644
--- a/main.cc
+++ b/main.cc
@@ -48,8 +48,8 @@
namespace ledger {
value_t register_command(call_scope_t& args)
{
- var_t<report_t> report(args, 0);
- var_t<std::ostream> ostream(args, 1);
+ ptr_t<report_t> report(args, 0);
+ ptr_t<std::ostream> ostream(args, 1);
report->xacts_report
(xact_handler_ptr(new format_xacts
diff --git a/scope.h b/scope.h
index 1bf50a3e..f0badb54 100644
--- a/scope.h
+++ b/scope.h
@@ -56,8 +56,28 @@ public:
else
return NULL_VALUE;
}
+
+ virtual optional<scope_t&> find_scope(const std::type_info&, bool = true) {
+ return none;
+ }
};
+template <typename T>
+inline T& find_scope(scope_t& scope, bool skip_this = true) {
+ optional<scope_t&> found = scope.find_scope(typeid(T), skip_this);
+ assert(found);
+ return downcast<T>(*found);
+}
+
+template <typename T>
+inline optional<T&> maybe_find_scope(scope_t& scope, bool skip_this = true) {
+ optional<scope_t&> found = scope.find_scope(typeid(T), skip_this);
+ if (found)
+ return optional<T&>(downcast<T>(*found));
+ else
+ return none;
+}
+
class child_scope_t : public noncopyable, public scope_t
{
public:
@@ -79,6 +99,17 @@ public:
return parent->lookup(name);
return expr_t::ptr_op_t();
}
+
+ virtual optional<scope_t&> find_scope(const std::type_info& type,
+ bool skip_this = true) {
+ for (scope_t * ptr = (skip_this ? parent : this);
+ ptr;
+ ptr = polymorphic_downcast<child_scope_t *>(ptr)->parent)
+ if (typeid(ptr) == type)
+ return *ptr;
+
+ return none;
+ }
};
class symbol_scope_t : public child_scope_t
@@ -152,30 +183,55 @@ public:
};
template <typename T>
-class var_t : public noncopyable
+class ptr_t : public noncopyable
{
T * value;
- var_t();
+ ptr_t();
public:
- // jww (2008-07-21): Give a good exception here if we can't find "name"
- var_t(scope_t& scope, const string& name)
+ ptr_t(scope_t& scope, const string& name)
: value(scope.resolve(name).template as_pointer<T>()) {
- TRACE_CTOR(var_t, "scope_t&, const string&");
+ TRACE_CTOR(ptr_t, "scope_t&, const string&");
}
- var_t(call_scope_t& scope, const unsigned int idx)
+ ptr_t(call_scope_t& scope, const unsigned int idx)
: value(scope[idx].template as_pointer<T>()) {
+ TRACE_CTOR(ptr_t, "call_scope_t&, const unsigned int");
+ }
+ ~ptr_t() throw() {
+ TRACE_DTOR(ptr_t);
+ }
+
+ T& operator *() { return *value; }
+ T * operator->() { return value; }
+};
+
+template <typename T>
+class var_t : public noncopyable
+{
+ value_t value;
+
+ var_t();
+
+public:
+ var_t(scope_t& scope, const string& name) : value(scope.resolve(name)) {
+ TRACE_CTOR(var_t, "scope_t&, const string&");
+ }
+ var_t(call_scope_t& scope, const unsigned int idx) : value(scope[idx]) {
TRACE_CTOR(var_t, "call_scope_t&, const unsigned int");
}
~var_t() throw() {
TRACE_DTOR(var_t);
}
- T& operator *() { return *value; }
- T * operator->() { return value; }
+ operator T() { assert(false); }
};
+template <>
+inline var_t<long>::operator long() {
+ return value.to_long();
+}
+
} // namespace ledger
#endif // _SCOPE_H
diff --git a/system.hh b/system.hh
index ffefafb3..221b81ef 100644
--- a/system.hh
+++ b/system.hh
@@ -52,6 +52,7 @@
#include <algorithm>
#include <exception>
+#include <typeinfo>
#include <stdexcept>
#include <iostream>
#include <streambuf>
diff --git a/textual.cc b/textual.cc
index ed0e6509..f9499e6e 100644
--- a/textual.cc
+++ b/textual.cc
@@ -50,10 +50,10 @@ struct time_entry_t
#endif
namespace {
- optional<expr_t> parse_amount_expr(std::istream& in,
- amount_t& amount,
- xact_t * xact,
- unsigned short flags = 0)
+ optional<expr_t> parse_amount_expr(std::istream& in,
+ amount_t& amount,
+ xact_t * xact,
+ unsigned short flags = 0)
{
expr_t expr(in, flags | EXPR_PARSE_PARTIAL);
@@ -79,8 +79,7 @@ namespace {
}
}
-xact_t * parse_xact(char * line, account_t * account,
- entry_t * entry = NULL)
+xact_t * parse_xact(char * line, account_t * account, entry_t * entry = NULL)
{
std::istringstream in(line);
@@ -299,23 +298,25 @@ xact_t * parse_xact(char * line, account_t * account,
amount_t amt;
try {
-#if 0
- // jww (2008-08-02): This data must be saved so that it can be
- // restored on "print".
unsigned long beg = static_cast<unsigned long>(in.tellg());
-#endif
- if (parse_amount_expr(in, amt, xact.get(),
- EXPR_PARSE_NO_MIGRATE))
+ optional<expr_t> total_expr =
+ parse_amount_expr(in, amt, xact.get(), EXPR_PARSE_NO_MIGRATE);
+
+ if (amt.is_null())
throw parse_error
("An assigned balance must evaluate to a constant value");
DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
"XACT assign: parsed amt = " << amt);
-#if 0
- unsigned long end = static_cast<unsigned long>(in.tellg());
-#endif
+ if (total_expr) {
+ unsigned long end = static_cast<unsigned long>(in.tellg());
+ total_expr->set_text(string("=") +
+ string(line, beg, end - beg));
+ }
+
+ // jww (2008-08-02): Save total_expr somewhere!
amount_t diff;
if (xdata.value.is_amount()) {
@@ -339,11 +340,10 @@ xact_t * parse_xact(char * line, account_t * account,
"XACT assign: diff = " << diff);
if (! diff.is_realzero()) {
- if (xact->amount) {
+ if (! xact->amount.is_null()) {
xact_t * temp =
new xact_t(xact->account, diff,
- XACT_GENERATED |
- XACT_CALCULATED);
+ XACT_GENERATED | XACT_CALCULATED);
entry->add_xact(temp);
DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
diff --git a/xact.cc b/xact.cc
index 6fb0d636..8c9014f4 100644
--- a/xact.cc
+++ b/xact.cc
@@ -32,6 +32,7 @@
#include "xact.h"
#include "journal.h"
#include "account.h"
+#include "format.h"
namespace ledger {
@@ -57,32 +58,31 @@ date_t xact_t::effective_date() const
}
namespace {
- value_t get_amount(call_scope_t& scope)
+ value_t get_amount(xact_t& xact)
{
- xact_t& xact(downcast<xact_t>(*scope.parent));
return xact.amount;
}
- value_t get_date(call_scope_t& scope)
- {
- xact_t& xact(downcast<xact_t>(*scope.parent));
- return xact.entry->date();
- }
-
- value_t get_payee(call_scope_t& scope)
+ value_t get_date(xact_t& xact)
{
- xact_t& xact(downcast<xact_t>(*scope.parent));
- return string_value(xact.entry->payee);
+ return xact.date();
}
value_t get_account(call_scope_t& scope)
{
xact_t& xact(downcast<xact_t>(*scope.parent));
+ long width = 0;
+ if (scope.size() == 1)
+ width = var_t<long>(scope, 0);
+
// jww (2008-08-02): Accept a width here so that we can abbreviate the
// string.
string name = xact.account->fullname();
+ if (width > 2)
+ name = format_t::truncate(name, width - 2, true);
+
if (xact.has_flags(XACT_VIRTUAL)) {
if (xact.must_balance())
name = string("[") + name + "]";
@@ -92,11 +92,16 @@ namespace {
return string_value(name);
}
- value_t get_account_base(call_scope_t& scope)
+ value_t get_account_base(xact_t& xact)
{
assert(false);
return NULL_VALUE;
}
+
+ template <value_t (*Func)(xact_t&)>
+ value_t get_wrapper(call_scope_t& scope) {
+ return (*Func)(find_scope<xact_t>(scope));
+ }
}
expr_t::ptr_op_t xact_t::lookup(const string& name)
@@ -104,15 +109,15 @@ expr_t::ptr_op_t xact_t::lookup(const string& name)
switch (name[0]) {
case 'a':
if (name[1] == '\0' || name == "amount")
- return WRAP_FUNCTOR(get_amount);
+ return WRAP_FUNCTOR(get_wrapper<&get_amount>);
else if (name == "account")
return WRAP_FUNCTOR(get_account);
else if (name == "account_base")
- return WRAP_FUNCTOR(get_account_base);
+ return WRAP_FUNCTOR(get_wrapper<&get_account_base>);
break;
case 'd':
if (name[1] == '\0' || name == "date")
- return WRAP_FUNCTOR(get_date);
+ return WRAP_FUNCTOR(get_wrapper<&get_date>);
break;
case 'f':
if (name.find("fmt_") == 0) {
@@ -120,10 +125,6 @@ expr_t::ptr_op_t xact_t::lookup(const string& name)
return WRAP_FUNCTOR(get_account);
}
break;
- case 'p':
- if (name[1] == '\0' || name == "payee")
- return WRAP_FUNCTOR(get_payee);
- break;
}
return entry->lookup(name);
}