More infrastructure work toward getting journal objects to provide their own

information in an abstract manner.
This commit is contained in:
John Wiegley 2008-08-02 16:23:58 -04:00
parent 9a9e06554e
commit e52a6a9bd8
11 changed files with 162 additions and 76 deletions

View file

@ -357,17 +357,23 @@ void entry_t::add_xact(xact_t * xact)
} }
namespace { namespace {
value_t get_date(call_scope_t& scope) value_t get_date(entry_t& entry) {
{
entry_t& entry(downcast<entry_t>(*scope.parent));
return entry.date(); 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); 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) 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]) { switch (name[0]) {
case 'd': case 'd':
if (name[1] == '\0' || name == "date") if (name[1] == '\0' || name == "date")
return WRAP_FUNCTOR(bind(get_date, _1)); return WRAP_FUNCTOR(get_wrapper<&get_date>);
break; break;
case 'p': case 'p':
if (name[1] == '\0' || name == "payee") if (name[1] == '\0' || name == "payee")
return WRAP_FUNCTOR(bind(get_payee, _1)); return WRAP_FUNCTOR(get_wrapper<&get_payee>);
break; 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(); return expr_t::ptr_op_t();
#endif
} }
bool entry_t::valid() const 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) foreach (auto_entry_t * entry, journal->auto_entries)
entry->extend_entry(*entry, post); entry->extend_entry(base, post);
} }
} // namespace ledger } // namespace ledger

View file

@ -37,7 +37,7 @@ namespace ledger {
extern std::ostringstream _desc_buffer; extern std::ostringstream _desc_buffer;
template <typename T> template <typename T>
inline void throw_func(const std::string& message) { inline void throw_func(const string& message) {
_desc_buffer.str(""); _desc_buffer.str("");
throw T(message); throw T(message);
} }

17
expr.cc
View file

@ -44,7 +44,7 @@ expr_t::expr_t() : compiled(false)
} }
expr_t::expr_t(const expr_t& other) 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"); 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) void expr_t::compile(scope_t& scope)
{ {
if (ptr.get()) { if (ptr.get() && ! compiled) {
ptr = ptr->compile(scope); ptr = ptr->compile(scope);
compiled = true; compiled = true;
} }
@ -127,9 +127,16 @@ value_t expr_t::calc(scope_t& scope)
bool expr_t::is_constant() const bool expr_t::is_constant() const
{ {
assert(compiled);
return ptr.get() && ptr->is_value(); 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() value_t& expr_t::constant_value()
{ {
assert(is_constant()); assert(is_constant());
@ -142,6 +149,12 @@ const value_t& expr_t::constant_value() const
return ptr->as_value(); 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) value_t expr_t::eval(const string& _expr, scope_t& scope)
{ {
return expr_t(_expr).calc(scope); return expr_t(_expr).calc(scope);

4
expr.h
View file

@ -102,9 +102,13 @@ public:
value_t calc(scope_t& scope) const; value_t calc(scope_t& scope) const;
bool is_constant() const; bool is_constant() const;
bool is_function() const;
value_t& constant_value(); value_t& constant_value();
const value_t& constant_value() const; const value_t& constant_value() const;
function_t& get_function();
void print(std::ostream& out, scope_t& scope) const; void print(std::ostream& out, scope_t& scope) const;
void dump(std::ostream& out) const; void dump(std::ostream& out) const;
void read(const char *& data); void read(const char *& data);

View file

@ -242,11 +242,24 @@ void format_t::format(std::ostream& out_str, scope_t& scope)
case element_t::EXPR: case element_t::EXPR:
try { try {
if (elem->max_width == 0) elem->expr.compile(scope);
elem->expr.calc(scope).dump(out, elem->min_width);
else if (elem->expr.is_function()) {
out << truncate(elem->expr.calc(scope).as_string(), call_scope_t args(scope);
elem->max_width); 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&) { catch (const calc_error&) {
out << (string("%") + elem->chars); out << (string("%") + elem->chars);

View file

@ -74,6 +74,8 @@ class format_t : public noncopyable
static bool ansi_codes; static bool ansi_codes;
static bool ansi_invert; static bool ansi_invert;
static element_t * parse_elements(const string& fmt);
public: public:
format_t() { format_t() {
TRACE_CTOR(format_t, ""); TRACE_CTOR(format_t, "");
@ -100,11 +102,8 @@ public:
elem->dump(out); elem->dump(out);
} }
private:
static element_t * parse_elements(const string& fmt);
static string truncate(const string& str, unsigned int width, static string truncate(const string& str, unsigned int width,
const bool is_account = false); const bool is_account = false);
}; };
} // namespace ledger } // namespace ledger

View file

@ -48,8 +48,8 @@
namespace ledger { namespace ledger {
value_t register_command(call_scope_t& args) value_t register_command(call_scope_t& args)
{ {
var_t<report_t> report(args, 0); ptr_t<report_t> report(args, 0);
var_t<std::ostream> ostream(args, 1); ptr_t<std::ostream> ostream(args, 1);
report->xacts_report report->xacts_report
(xact_handler_ptr(new format_xacts (xact_handler_ptr(new format_xacts

74
scope.h
View file

@ -56,8 +56,28 @@ public:
else else
return NULL_VALUE; 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 class child_scope_t : public noncopyable, public scope_t
{ {
public: public:
@ -79,6 +99,17 @@ public:
return parent->lookup(name); return parent->lookup(name);
return expr_t::ptr_op_t(); 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 class symbol_scope_t : public child_scope_t
@ -152,30 +183,55 @@ public:
}; };
template <typename T> template <typename T>
class var_t : public noncopyable class ptr_t : public noncopyable
{ {
T * value; T * value;
var_t(); ptr_t();
public: public:
// jww (2008-07-21): Give a good exception here if we can't find "name" ptr_t(scope_t& scope, const string& name)
var_t(scope_t& scope, const string& name)
: value(scope.resolve(name).template as_pointer<T>()) { : 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>()) { : value(scope[idx].template as_pointer<T>()) {
TRACE_CTOR(var_t, "call_scope_t&, const unsigned int"); TRACE_CTOR(ptr_t, "call_scope_t&, const unsigned int");
} }
~var_t() throw() { ~ptr_t() throw() {
TRACE_DTOR(var_t); TRACE_DTOR(ptr_t);
} }
T& operator *() { return *value; } T& operator *() { return *value; }
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);
}
operator T() { assert(false); }
};
template <>
inline var_t<long>::operator long() {
return value.to_long();
}
} // namespace ledger } // namespace ledger
#endif // _SCOPE_H #endif // _SCOPE_H

View file

@ -52,6 +52,7 @@
#include <algorithm> #include <algorithm>
#include <exception> #include <exception>
#include <typeinfo>
#include <stdexcept> #include <stdexcept>
#include <iostream> #include <iostream>
#include <streambuf> #include <streambuf>

View file

@ -50,10 +50,10 @@ struct time_entry_t
#endif #endif
namespace { namespace {
optional<expr_t> parse_amount_expr(std::istream& in, optional<expr_t> parse_amount_expr(std::istream& in,
amount_t& amount, amount_t& amount,
xact_t * xact, xact_t * xact,
unsigned short flags = 0) unsigned short flags = 0)
{ {
expr_t expr(in, flags | EXPR_PARSE_PARTIAL); expr_t expr(in, flags | EXPR_PARSE_PARTIAL);
@ -79,8 +79,7 @@ namespace {
} }
} }
xact_t * parse_xact(char * line, account_t * account, xact_t * parse_xact(char * line, account_t * account, entry_t * entry = NULL)
entry_t * entry = NULL)
{ {
std::istringstream in(line); std::istringstream in(line);
@ -299,23 +298,25 @@ xact_t * parse_xact(char * line, account_t * account,
amount_t amt; amount_t amt;
try { 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()); unsigned long beg = static_cast<unsigned long>(in.tellg());
#endif
if (parse_amount_expr(in, amt, xact.get(), optional<expr_t> total_expr =
EXPR_PARSE_NO_MIGRATE)) parse_amount_expr(in, amt, xact.get(), EXPR_PARSE_NO_MIGRATE);
if (amt.is_null())
throw parse_error throw parse_error
("An assigned balance must evaluate to a constant value"); ("An assigned balance must evaluate to a constant value");
DEBUG("ledger.textual.parse", "line " << linenum << ": " << DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
"XACT assign: parsed amt = " << amt); "XACT assign: parsed amt = " << amt);
#if 0 if (total_expr) {
unsigned long end = static_cast<unsigned long>(in.tellg()); unsigned long end = static_cast<unsigned long>(in.tellg());
#endif total_expr->set_text(string("=") +
string(line, beg, end - beg));
}
// jww (2008-08-02): Save total_expr somewhere!
amount_t diff; amount_t diff;
if (xdata.value.is_amount()) { if (xdata.value.is_amount()) {
@ -339,11 +340,10 @@ xact_t * parse_xact(char * line, account_t * account,
"XACT assign: diff = " << diff); "XACT assign: diff = " << diff);
if (! diff.is_realzero()) { if (! diff.is_realzero()) {
if (xact->amount) { if (! xact->amount.is_null()) {
xact_t * temp = xact_t * temp =
new xact_t(xact->account, diff, new xact_t(xact->account, diff,
XACT_GENERATED | XACT_GENERATED | XACT_CALCULATED);
XACT_CALCULATED);
entry->add_xact(temp); entry->add_xact(temp);
DEBUG("ledger.textual.parse", "line " << linenum << ": " << DEBUG("ledger.textual.parse", "line " << linenum << ": " <<

39
xact.cc
View file

@ -32,6 +32,7 @@
#include "xact.h" #include "xact.h"
#include "journal.h" #include "journal.h"
#include "account.h" #include "account.h"
#include "format.h"
namespace ledger { namespace ledger {
@ -57,32 +58,31 @@ date_t xact_t::effective_date() const
} }
namespace { 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; return xact.amount;
} }
value_t get_date(call_scope_t& scope) value_t get_date(xact_t& xact)
{ {
xact_t& xact(downcast<xact_t>(*scope.parent)); return xact.date();
return xact.entry->date();
}
value_t get_payee(call_scope_t& scope)
{
xact_t& xact(downcast<xact_t>(*scope.parent));
return string_value(xact.entry->payee);
} }
value_t get_account(call_scope_t& scope) value_t get_account(call_scope_t& scope)
{ {
xact_t& xact(downcast<xact_t>(*scope.parent)); 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 // jww (2008-08-02): Accept a width here so that we can abbreviate the
// string. // string.
string name = xact.account->fullname(); string name = xact.account->fullname();
if (width > 2)
name = format_t::truncate(name, width - 2, true);
if (xact.has_flags(XACT_VIRTUAL)) { if (xact.has_flags(XACT_VIRTUAL)) {
if (xact.must_balance()) if (xact.must_balance())
name = string("[") + name + "]"; name = string("[") + name + "]";
@ -92,11 +92,16 @@ namespace {
return string_value(name); return string_value(name);
} }
value_t get_account_base(call_scope_t& scope) value_t get_account_base(xact_t& xact)
{ {
assert(false); assert(false);
return NULL_VALUE; 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) 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]) { switch (name[0]) {
case 'a': case 'a':
if (name[1] == '\0' || name == "amount") if (name[1] == '\0' || name == "amount")
return WRAP_FUNCTOR(get_amount); return WRAP_FUNCTOR(get_wrapper<&get_amount>);
else if (name == "account") else if (name == "account")
return WRAP_FUNCTOR(get_account); return WRAP_FUNCTOR(get_account);
else if (name == "account_base") else if (name == "account_base")
return WRAP_FUNCTOR(get_account_base); return WRAP_FUNCTOR(get_wrapper<&get_account_base>);
break; break;
case 'd': case 'd':
if (name[1] == '\0' || name == "date") if (name[1] == '\0' || name == "date")
return WRAP_FUNCTOR(get_date); return WRAP_FUNCTOR(get_wrapper<&get_date>);
break; break;
case 'f': case 'f':
if (name.find("fmt_") == 0) { 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); return WRAP_FUNCTOR(get_account);
} }
break; break;
case 'p':
if (name[1] == '\0' || name == "payee")
return WRAP_FUNCTOR(get_payee);
break;
} }
return entry->lookup(name); return entry->lookup(name);
} }