More infrastructure work toward getting journal objects to provide their own
information in an abstract manner.
This commit is contained in:
parent
9a9e06554e
commit
e52a6a9bd8
11 changed files with 162 additions and 76 deletions
31
entry.cc
31
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
|
||||
|
|
|
|||
2
error.h
2
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);
|
||||
}
|
||||
|
|
|
|||
17
expr.cc
17
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);
|
||||
|
|
|
|||
4
expr.h
4
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);
|
||||
|
|
|
|||
23
format.cc
23
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);
|
||||
|
|
|
|||
7
format.h
7
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
|
||||
|
|
|
|||
4
main.cc
4
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
|
||||
|
|
|
|||
74
scope.h
74
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(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
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
#include <typeinfo>
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include <streambuf>
|
||||
|
|
|
|||
36
textual.cc
36
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 << ": " <<
|
||||
|
|
|
|||
39
xact.cc
39
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)
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue