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 {
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

View file

@ -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);
}

17
expr.cc
View file

@ -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);

4
expr.h
View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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

74
scope.h
View file

@ -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(var_t, "call_scope_t&, const unsigned int");
TRACE_CTOR(ptr_t, "call_scope_t&, const unsigned int");
}
~var_t() throw() {
TRACE_DTOR(var_t);
~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);
}
operator T() { assert(false); }
};
template <>
inline var_t<long>::operator long() {
return value.to_long();
}
} // namespace ledger
#endif // _SCOPE_H

View file

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

View file

@ -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 << ": " <<

39
xact.cc
View file

@ -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)
value_t get_date(xact_t& xact)
{
xact_t& xact(downcast<xact_t>(*scope.parent));
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);
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);
}