diff options
-rw-r--r-- | entry.cc | 31 | ||||
-rw-r--r-- | error.h | 2 | ||||
-rw-r--r-- | expr.cc | 17 | ||||
-rw-r--r-- | expr.h | 4 | ||||
-rw-r--r-- | format.cc | 23 | ||||
-rw-r--r-- | format.h | 7 | ||||
-rw-r--r-- | main.cc | 4 | ||||
-rw-r--r-- | scope.h | 72 | ||||
-rw-r--r-- | system.hh | 1 | ||||
-rw-r--r-- | textual.cc | 36 | ||||
-rw-r--r-- | xact.cc | 39 |
11 files changed, 161 insertions, 75 deletions
@@ -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 @@ -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); } @@ -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); @@ -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); @@ -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); @@ -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 @@ -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 @@ -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 @@ -52,6 +52,7 @@ #include <algorithm> #include <exception> +#include <typeinfo> #include <stdexcept> #include <iostream> #include <streambuf> @@ -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 << ": " << @@ -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); } |