More work on the compilation of nodes.
This commit is contained in:
parent
5a72d17d02
commit
3e0f510b29
12 changed files with 360 additions and 132 deletions
216
src/compile.cc
216
src/compile.cc
|
|
@ -30,31 +30,213 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "compile.h"
|
#include "compile.h"
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
namespace xml {
|
namespace xml {
|
||||||
|
|
||||||
void entry_node_t::compile()
|
void compile_node(node_t& node, xpath_t::scope_t& scope)
|
||||||
{
|
{
|
||||||
typedef std::list<attributes_t::iterator> iterator_list;
|
switch (node.name_id()) {
|
||||||
|
case JOURNAL_NODE:
|
||||||
iterator_list to_update;
|
downcast<journal_node_t>(node).compile(scope);
|
||||||
|
break;
|
||||||
|
case ENTRY_NODE:
|
||||||
|
downcast<entry_node_t>(node).compile(scope);
|
||||||
|
break;
|
||||||
|
case TRANSACTION_NODE:
|
||||||
|
downcast<transaction_node_t>(node).compile(scope);
|
||||||
|
break;
|
||||||
|
|
||||||
for (attributes_t::iterator i = attributes->begin();
|
default:
|
||||||
i != attributes->end();
|
break;
|
||||||
i++)
|
}
|
||||||
if (i->first == DATE_ATTR && i->second.is_string())
|
|
||||||
//i->second = parse_datetime(i->second.as_string().c_str());
|
|
||||||
to_update.push_back(i);
|
|
||||||
|
|
||||||
for (iterator_list::iterator i = to_update.begin();
|
node.compiled = true;
|
||||||
i != to_update.end();
|
|
||||||
i++) {
|
|
||||||
attr_pair attr_def = **i;
|
|
||||||
attributes->erase(*i);
|
|
||||||
|
|
||||||
attr_def.second = parse_datetime(attr_def.second.as_string().c_str());
|
if (node.is_parent_node())
|
||||||
attributes->push_back(attr_def);
|
foreach (node_t * child, node.as_parent_node())
|
||||||
|
compile_node(*child, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
void journal_node_t::compile(xpath_t::scope_t& scope)
|
||||||
|
{
|
||||||
|
if (! journal.get())
|
||||||
|
journal.reset(new journal_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void entry_node_t::compile(xpath_t::scope_t& scope)
|
||||||
|
{
|
||||||
|
parent_node_t& parent_node(*parent());
|
||||||
|
|
||||||
|
assert(parent_node.name_id() == JOURNAL_NODE);
|
||||||
|
assert(parent_node.is_compiled());
|
||||||
|
|
||||||
|
journal_t * journal = downcast<journal_node_t>(parent_node).journal.get();
|
||||||
|
|
||||||
|
if (! entry.get()) {
|
||||||
|
entry.reset(new entry_t);
|
||||||
|
#if 0
|
||||||
|
journal->add_entry(entry.get());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
entry->journal = journal;
|
||||||
|
|
||||||
|
foreach (attr_pair& attr, *attributes) {
|
||||||
|
if (attr.first == DATE_ATTR && attr.second.is_string())
|
||||||
|
entry->_date = parse_datetime(attr.second.as_string().c_str());
|
||||||
|
else if (attr.first == EFF_DATE_ATTR && attr.second.is_string())
|
||||||
|
entry->_date_eff = parse_datetime(attr.second.as_string().c_str());
|
||||||
|
else if (attr.first == CODE_ATTR)
|
||||||
|
entry->code = attr.second.as_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void transaction_node_t::parse_amount_expr(xpath_t::scope_t& scope,
|
||||||
|
const char * amount_expr)
|
||||||
|
{
|
||||||
|
value_t * amount;
|
||||||
|
|
||||||
|
std::istringstream in(amount_expr);
|
||||||
|
|
||||||
|
PUSH_CONTEXT();
|
||||||
|
|
||||||
|
// jww (2006-09-15): Make sure it doesn't gobble up the upcoming @ symbol
|
||||||
|
|
||||||
|
unsigned long beg = (long)in.tellg();
|
||||||
|
|
||||||
|
amount_t temp;
|
||||||
|
temp.parse(in, AMOUNT_PARSE_NO_REDUCE);
|
||||||
|
|
||||||
|
char c;
|
||||||
|
if (! in.eof() && (c = peek_next_nonws(in)) != '@' &&
|
||||||
|
c != ';' && ! in.eof()) {
|
||||||
|
in.seekg(beg, std::ios::beg);
|
||||||
|
|
||||||
|
xpath_t xpath(in, (XPATH_PARSE_NO_REDUCE | XPATH_PARSE_RELAXED |
|
||||||
|
XPATH_PARSE_PARTIAL));
|
||||||
|
|
||||||
|
xpath_t::context_scope_t node_scope(scope, this);
|
||||||
|
amount = &set_attr(AMOUNT_ATTR, xpath.calc(node_scope));
|
||||||
|
|
||||||
|
//unsigned long end = (long)in.tellg();
|
||||||
|
} else {
|
||||||
|
amount = &set_attr(AMOUNT_ATTR, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// jww (2007-04-30): This should be a string context, or perhaps a
|
||||||
|
// file context
|
||||||
|
POP_CONTEXT(context("While parsing transaction amount"));
|
||||||
|
|
||||||
|
// Parse the optional cost (@ PER-UNIT-COST, @@ TOTAL-COST)
|
||||||
|
|
||||||
|
unsigned int linenum = -1;
|
||||||
|
|
||||||
|
if (in.good() && ! in.eof()) {
|
||||||
|
char c = peek_next_nonws(in);
|
||||||
|
if (c == '@') {
|
||||||
|
DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
|
||||||
|
"Found a price indicator");
|
||||||
|
bool per_unit = true;
|
||||||
|
in.get(c);
|
||||||
|
if (in.peek() == '@') {
|
||||||
|
in.get(c);
|
||||||
|
per_unit = false;
|
||||||
|
DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
|
||||||
|
"And it's for a total price");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in.good() && ! in.eof()) {
|
||||||
|
amount_t temp;
|
||||||
|
|
||||||
|
PUSH_CONTEXT();
|
||||||
|
|
||||||
|
//unsigned long beg = (long)in.tellg();
|
||||||
|
|
||||||
|
temp.parse(in);
|
||||||
|
|
||||||
|
if (temp.sign() < 0)
|
||||||
|
throw_(parse_error, "A transaction's cost may not be negative");
|
||||||
|
|
||||||
|
//unsigned long end = (long)in.tellg();
|
||||||
|
|
||||||
|
POP_CONTEXT(context("While parsing transaction cost"));
|
||||||
|
|
||||||
|
amount_t per_unit_cost(temp);
|
||||||
|
amount_t& base_amount(amount->as_amount_lval());
|
||||||
|
if (per_unit)
|
||||||
|
temp *= base_amount.number();
|
||||||
|
else
|
||||||
|
per_unit_cost /= base_amount.number();
|
||||||
|
|
||||||
|
value_t& cost = set_attr(COST_ATTR, temp);
|
||||||
|
|
||||||
|
if (base_amount.commodity() && ! base_amount.commodity().annotated) {
|
||||||
|
assert(transaction);
|
||||||
|
assert(transaction->entry);
|
||||||
|
base_amount.annotate_commodity
|
||||||
|
(annotation_t(per_unit_cost, transaction->entry->actual_date(),
|
||||||
|
transaction->entry->code));
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
|
||||||
|
"Total cost is " << cost);
|
||||||
|
DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
|
||||||
|
"Per-unit cost is " << per_unit_cost);
|
||||||
|
DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
|
||||||
|
"Annotated amount is " << base_amount);
|
||||||
|
DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
|
||||||
|
"Bare amount is " << base_amount.number());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
amount->in_place_reduce();
|
||||||
|
|
||||||
|
DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
|
||||||
|
"Reduced amount is " << *amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void transaction_node_t::compile(xpath_t::scope_t& scope)
|
||||||
|
{
|
||||||
|
parent_node_t& parent_node(*parent());
|
||||||
|
|
||||||
|
assert(parent_node.name_id() == ENTRY_NODE);
|
||||||
|
assert(parent_node.is_compiled());
|
||||||
|
|
||||||
|
entry_t * entry = downcast<entry_node_t>(parent_node).entry.get();
|
||||||
|
|
||||||
|
if (! transaction.get()) {
|
||||||
|
transaction.reset(new transaction_t);
|
||||||
|
#if 0
|
||||||
|
entry->add_transaction(transaction.get());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
transaction->entry = entry;
|
||||||
|
|
||||||
|
foreach (node_t * child, *this) {
|
||||||
|
switch (child->name_id()) {
|
||||||
|
case AMOUNT_EXPR_NODE:
|
||||||
|
parse_amount_expr(scope, child->as_terminal_node().text());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ACCOUNT_PATH_NODE: {
|
||||||
|
assert(entry);
|
||||||
|
|
||||||
|
journal_t * journal = entry->journal;
|
||||||
|
assert(journal);
|
||||||
|
|
||||||
|
transaction->account =
|
||||||
|
journal->find_account(child->as_terminal_node().text());
|
||||||
|
|
||||||
|
// jww (2007-05-18): Need to set an attribute that refers to the
|
||||||
|
// unique id of the account
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,8 @@
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
namespace xml {
|
namespace xml {
|
||||||
|
|
||||||
|
void compile_node(node_t& node, xml::xpath_t::scope_t& scope);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
class commodity_node_t : public parent_node_t
|
class commodity_node_t : public parent_node_t
|
||||||
{
|
{
|
||||||
|
|
@ -82,6 +84,25 @@ public:
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class journal_node_t : public parent_node_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
shared_ptr<journal_t> journal;
|
||||||
|
|
||||||
|
journal_node_t(nameid_t _name_id,
|
||||||
|
document_t& _document,
|
||||||
|
const optional<parent_node_t&>& _parent = none,
|
||||||
|
journal_t * _journal = NULL)
|
||||||
|
: parent_node_t(_name_id, _document, _parent), journal(_journal) {
|
||||||
|
TRACE_CTOR(journal_node_t, "document_t *, journal_t *, parent_node_t *");
|
||||||
|
}
|
||||||
|
virtual ~journal_node_t() {
|
||||||
|
TRACE_DTOR(journal_node_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void compile(xpath_t::scope_t& scope);
|
||||||
|
};
|
||||||
|
|
||||||
class entry_node_t : public parent_node_t
|
class entry_node_t : public parent_node_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -99,7 +120,7 @@ public:
|
||||||
TRACE_DTOR(entry_node_t);
|
TRACE_DTOR(entry_node_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void compile();
|
void compile(xpath_t::scope_t& scope);
|
||||||
};
|
};
|
||||||
|
|
||||||
class transaction_node_t : public parent_node_t
|
class transaction_node_t : public parent_node_t
|
||||||
|
|
@ -120,30 +141,15 @@ public:
|
||||||
virtual ~transaction_node_t() {
|
virtual ~transaction_node_t() {
|
||||||
TRACE_DTOR(transaction_node_t);
|
TRACE_DTOR(transaction_node_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void compile(xpath_t::scope_t& scope);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void parse_amount_expr(xpath_t::scope_t& scope,
|
||||||
|
const char * amount_expr);
|
||||||
};
|
};
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
class entry_node_t : public parent_node_t
|
|
||||||
{
|
|
||||||
entry_t * entry;
|
|
||||||
|
|
||||||
public:
|
|
||||||
entry_node_t(document_t * _document, entry_t * _entry,
|
|
||||||
parent_node_t * _parent = NULL)
|
|
||||||
: parent_node_t(_document, _parent), entry(_entry) {
|
|
||||||
TRACE_CTOR(entry_node_t, "document_t *, entry_t *, parent_node_t *");
|
|
||||||
set_name(document_t::ENTRY);
|
|
||||||
}
|
|
||||||
virtual ~entry_node_t() {
|
|
||||||
TRACE_DTOR(entry_node_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual node_t * children() const;
|
|
||||||
virtual node_t * lookup_child(int _name_id) const;
|
|
||||||
|
|
||||||
friend class transaction_node_t;
|
|
||||||
};
|
|
||||||
|
|
||||||
class account_node_t : public parent_node_t
|
class account_node_t : public parent_node_t
|
||||||
{
|
{
|
||||||
account_t * account;
|
account_t * account;
|
||||||
|
|
@ -162,26 +168,6 @@ public:
|
||||||
virtual node_t * children() const;
|
virtual node_t * children() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class journal_node_t : public parent_node_t
|
|
||||||
{
|
|
||||||
journal_t * journal;
|
|
||||||
|
|
||||||
public:
|
|
||||||
journal_node_t(document_t * _document, journal_t * _journal,
|
|
||||||
parent_node_t * _parent = NULL)
|
|
||||||
: parent_node_t(_document, _parent), journal(_journal) {
|
|
||||||
TRACE_CTOR(journal_node_t, "document_t *, journal_t *, parent_node_t *");
|
|
||||||
set_name(document_t::JOURNAL);
|
|
||||||
}
|
|
||||||
virtual ~journal_node_t() {
|
|
||||||
TRACE_DTOR(journal_node_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual node_t * children() const;
|
|
||||||
|
|
||||||
friend class transaction_node_t;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline typename T::node_type *
|
inline typename T::node_type *
|
||||||
wrap_node(document_t * doc, T * item, void * parent_node = NULL) {
|
wrap_node(document_t * doc, T * item, void * parent_node = NULL) {
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ namespace {
|
||||||
"account",
|
"account",
|
||||||
"account-path",
|
"account-path",
|
||||||
"amount",
|
"amount",
|
||||||
|
"amount",
|
||||||
"amount-expr",
|
"amount-expr",
|
||||||
"arg",
|
"arg",
|
||||||
"auto-entry",
|
"auto-entry",
|
||||||
|
|
@ -51,6 +52,7 @@ namespace {
|
||||||
"commodity-conversion",
|
"commodity-conversion",
|
||||||
"commodity-nomarket",
|
"commodity-nomarket",
|
||||||
"commodity-template",
|
"commodity-template",
|
||||||
|
"cost",
|
||||||
"current-year",
|
"current-year",
|
||||||
"date",
|
"date",
|
||||||
"default-account",
|
"default-account",
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ namespace xml {
|
||||||
enum ledger_builtins_t {
|
enum ledger_builtins_t {
|
||||||
ACCOUNT_ATTR = 10,
|
ACCOUNT_ATTR = 10,
|
||||||
ACCOUNT_PATH_NODE,
|
ACCOUNT_PATH_NODE,
|
||||||
|
AMOUNT_ATTR,
|
||||||
AMOUNT_NODE,
|
AMOUNT_NODE,
|
||||||
AMOUNT_EXPR_NODE,
|
AMOUNT_EXPR_NODE,
|
||||||
ARG_ATTR,
|
ARG_ATTR,
|
||||||
|
|
@ -53,6 +54,7 @@ enum ledger_builtins_t {
|
||||||
COMMODITY_CONVERSION_NODE,
|
COMMODITY_CONVERSION_NODE,
|
||||||
COMMODITY_NOMARKET_NODE,
|
COMMODITY_NOMARKET_NODE,
|
||||||
COMMODITY_TEMPLATE_NODE,
|
COMMODITY_TEMPLATE_NODE,
|
||||||
|
COST_ATTR,
|
||||||
CURRENT_YEAR_NODE,
|
CURRENT_YEAR_NODE,
|
||||||
DATE_ATTR,
|
DATE_ATTR,
|
||||||
DEFAULT_ACCOUNT_NODE,
|
DEFAULT_ACCOUNT_NODE,
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ bool transaction_t::valid() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (amount && ! amount->valid()) {
|
if (! amount.valid()) {
|
||||||
DEBUG("ledger.validate", "transaction_t: ! amount.valid()");
|
DEBUG("ledger.validate", "transaction_t: ! amount.valid()");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -122,22 +122,22 @@ bool entry_base_t::finalize()
|
||||||
x++)
|
x++)
|
||||||
if (! (*x)->has_flags(TRANSACTION_VIRTUAL) ||
|
if (! (*x)->has_flags(TRANSACTION_VIRTUAL) ||
|
||||||
(*x)->has_flags(TRANSACTION_BALANCE)) {
|
(*x)->has_flags(TRANSACTION_BALANCE)) {
|
||||||
optional<amount_t>& p((*x)->cost ? (*x)->cost : (*x)->amount);
|
amount_t& p((*x)->cost ? *(*x)->cost : (*x)->amount);
|
||||||
if (p) {
|
if (p) {
|
||||||
if (no_amounts) {
|
if (no_amounts) {
|
||||||
balance = *p;
|
balance = p;
|
||||||
no_amounts = false;
|
no_amounts = false;
|
||||||
} else {
|
} else {
|
||||||
balance += *p;
|
balance += p;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert((*x)->amount);
|
assert((*x)->amount);
|
||||||
if ((*x)->cost && (*x)->amount->commodity().annotated) {
|
if ((*x)->cost && (*x)->amount.commodity().annotated) {
|
||||||
annotated_commodity_t&
|
annotated_commodity_t&
|
||||||
ann_comm(static_cast<annotated_commodity_t&>
|
ann_comm(static_cast<annotated_commodity_t&>
|
||||||
((*x)->amount->commodity()));
|
((*x)->amount.commodity()));
|
||||||
if (ann_comm.details.price)
|
if (ann_comm.details.price)
|
||||||
balance += (*ann_comm.details.price * (*x)->amount->number() -
|
balance += (*ann_comm.details.price * (*x)->amount.number() -
|
||||||
*((*x)->cost));
|
*((*x)->cost));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -170,7 +170,7 @@ bool entry_base_t::finalize()
|
||||||
balance.as_balance().amounts.size() == 2) {
|
balance.as_balance().amounts.size() == 2) {
|
||||||
transactions_list::const_iterator x = transactions.begin();
|
transactions_list::const_iterator x = transactions.begin();
|
||||||
assert((*x)->amount);
|
assert((*x)->amount);
|
||||||
commodity_t& this_comm = (*x)->amount->commodity();
|
commodity_t& this_comm = (*x)->amount.commodity();
|
||||||
|
|
||||||
balance_t::amounts_map::const_iterator this_bal =
|
balance_t::amounts_map::const_iterator this_bal =
|
||||||
balance.as_balance().amounts.find(&this_comm);
|
balance.as_balance().amounts.find(&this_comm);
|
||||||
|
|
@ -184,22 +184,21 @@ bool entry_base_t::finalize()
|
||||||
|
|
||||||
for (; x != transactions.end(); x++) {
|
for (; x != transactions.end(); x++) {
|
||||||
if ((*x)->cost || (*x)->has_flags(TRANSACTION_VIRTUAL) ||
|
if ((*x)->cost || (*x)->has_flags(TRANSACTION_VIRTUAL) ||
|
||||||
! (*x)->amount || (*x)->amount->commodity() != this_comm)
|
(*x)->amount.commodity() != this_comm)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
assert((*x)->amount);
|
balance -= (*x)->amount;
|
||||||
balance -= *(*x)->amount;
|
|
||||||
|
|
||||||
entry_t * entry = dynamic_cast<entry_t *>(this);
|
entry_t * entry = dynamic_cast<entry_t *>(this);
|
||||||
|
|
||||||
if ((*x)->amount->commodity() &&
|
if ((*x)->amount.commodity() &&
|
||||||
! (*x)->amount->commodity().annotated)
|
! (*x)->amount.commodity().annotated)
|
||||||
(*x)->amount->annotate_commodity
|
(*x)->amount.annotate_commodity
|
||||||
(annotation_t(per_unit_cost.abs(),
|
(annotation_t(per_unit_cost.abs(),
|
||||||
entry ? entry->actual_date() : optional<moment_t>(),
|
entry ? entry->actual_date() : optional<moment_t>(),
|
||||||
entry ? entry->code : optional<string>()));
|
entry ? entry->code : optional<string>()));
|
||||||
|
|
||||||
(*x)->cost = - (per_unit_cost * (*x)->amount->number());
|
(*x)->cost = - (per_unit_cost * (*x)->amount.number());
|
||||||
balance += *(*x)->cost;
|
balance += *(*x)->cost;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -267,7 +266,7 @@ bool entry_base_t::finalize()
|
||||||
(*x)->amount = balance.as_amount().negate();
|
(*x)->amount = balance.as_amount().negate();
|
||||||
(*x)->add_flags(TRANSACTION_CALCULATED);
|
(*x)->add_flags(TRANSACTION_CALCULATED);
|
||||||
|
|
||||||
balance += *(*x)->amount;
|
balance += (*x)->amount;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -378,7 +377,7 @@ void auto_entry_t::extend_entry(entry_base_t& entry, bool post)
|
||||||
t++) {
|
t++) {
|
||||||
amount_t amt;
|
amount_t amt;
|
||||||
assert((*t)->amount);
|
assert((*t)->amount);
|
||||||
if (! (*t)->amount->commodity()) {
|
if (! (*t)->amount.commodity()) {
|
||||||
if (! post)
|
if (! post)
|
||||||
continue;
|
continue;
|
||||||
assert((*i)->amount);
|
assert((*i)->amount);
|
||||||
|
|
@ -590,9 +589,8 @@ bool journal_t::add_entry(entry_t * entry)
|
||||||
i++)
|
i++)
|
||||||
if ((*i)->cost) {
|
if ((*i)->cost) {
|
||||||
assert((*i)->amount);
|
assert((*i)->amount);
|
||||||
assert(*(*i)->amount);
|
(*i)->amount.commodity().add_price(entry->date(),
|
||||||
(*i)->amount->commodity().add_price(entry->date(),
|
*(*i)->cost / (*i)->amount.number());
|
||||||
*(*i)->cost / (*i)->amount->number());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -58,10 +58,8 @@ class transaction_t : public supports_flags<>
|
||||||
account_t * account;
|
account_t * account;
|
||||||
optional<moment_t> _date;
|
optional<moment_t> _date;
|
||||||
optional<moment_t> _date_eff;
|
optional<moment_t> _date_eff;
|
||||||
optional<amount_t> amount;
|
amount_t amount;
|
||||||
optional<string> amount_expr;
|
|
||||||
optional<amount_t> cost;
|
optional<amount_t> cost;
|
||||||
optional<string> cost_expr;
|
|
||||||
optional<string> note;
|
optional<string> note;
|
||||||
|
|
||||||
static bool use_effective_date;
|
static bool use_effective_date;
|
||||||
|
|
@ -88,9 +86,7 @@ class transaction_t : public supports_flags<>
|
||||||
_date(xact._date),
|
_date(xact._date),
|
||||||
_date_eff(xact._date_eff),
|
_date_eff(xact._date_eff),
|
||||||
amount(xact.amount),
|
amount(xact.amount),
|
||||||
amount_expr(xact.amount_expr),
|
|
||||||
cost(xact.cost),
|
cost(xact.cost),
|
||||||
cost_expr(xact.cost_expr),
|
|
||||||
note(xact.note) {
|
note(xact.note) {
|
||||||
TRACE_CTOR(transaction_t, "copy");
|
TRACE_CTOR(transaction_t, "copy");
|
||||||
}
|
}
|
||||||
|
|
@ -368,12 +364,9 @@ typedef std::list<period_entry_t *> period_entries_list;
|
||||||
typedef std::list<path> path_list;
|
typedef std::list<path> path_list;
|
||||||
typedef std::list<string> strings_list;
|
typedef std::list<string> strings_list;
|
||||||
|
|
||||||
class session_t;
|
|
||||||
|
|
||||||
class journal_t
|
class journal_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
session_t * session;
|
|
||||||
account_t * master;
|
account_t * master;
|
||||||
account_t * basket;
|
account_t * basket;
|
||||||
entries_list entries;
|
entries_list entries;
|
||||||
|
|
@ -388,9 +381,7 @@ class journal_t
|
||||||
|
|
||||||
std::list<entry_finalizer_t *> entry_finalize_hooks;
|
std::list<entry_finalizer_t *> entry_finalize_hooks;
|
||||||
|
|
||||||
journal_t(session_t * _session)
|
journal_t() : basket(NULL), item_pool(NULL), item_pool_end(NULL) {
|
||||||
: session(_session), basket(NULL),
|
|
||||||
item_pool(NULL), item_pool_end(NULL) {
|
|
||||||
TRACE_CTOR(journal_t, "");
|
TRACE_CTOR(journal_t, "");
|
||||||
master = new account_t(NULL, "");
|
master = new account_t(NULL, "");
|
||||||
master->journal = this;
|
master->journal = this;
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@
|
||||||
//#include "qif.h"
|
//#include "qif.h"
|
||||||
//#include "ofx.h"
|
//#include "ofx.h"
|
||||||
#include "jbuilder.h"
|
#include "jbuilder.h"
|
||||||
|
#include "compile.h"
|
||||||
|
|
||||||
#include <ledger.h>
|
#include <ledger.h>
|
||||||
|
|
||||||
|
|
@ -300,7 +301,7 @@ static int read_and_report(ledger::report_t& report, int argc, char * argv[],
|
||||||
*out << "Compiled results:" << std::endl;
|
*out << "Compiled results:" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
xml_document.compile();
|
xml::compile_node(xml_document, report);
|
||||||
|
|
||||||
foreach (const value_t& value, xpath.find_all(doc_scope)) {
|
foreach (const value_t& value, xpath.find_all(doc_scope)) {
|
||||||
if (value.is_xml_node())
|
if (value.is_xml_node())
|
||||||
|
|
|
||||||
23
src/node.cc
23
src/node.cc
|
|
@ -40,7 +40,19 @@ const char * node_t::name() const
|
||||||
return *document().lookup_name(name_id());
|
return *document().lookup_name(name_id());
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<value_t> node_t::get_attr(const string& _name) const
|
value_t& node_t::set_attr(const string& _name, const char * value)
|
||||||
|
{
|
||||||
|
nameid_t name_id = document().register_name(_name);
|
||||||
|
return set_attr(name_id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
value_t& node_t::set_attr(const string& _name, const value_t& value)
|
||||||
|
{
|
||||||
|
nameid_t name_id = document().register_name(_name);
|
||||||
|
return set_attr(name_id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<value_t&> node_t::get_attr(const string& _name)
|
||||||
{
|
{
|
||||||
optional<nameid_t> name_id = document().lookup_name_id(_name);
|
optional<nameid_t> name_id = document().lookup_name_id(_name);
|
||||||
if (name_id)
|
if (name_id)
|
||||||
|
|
@ -71,10 +83,17 @@ void output_xml_string(std::ostream& out, const string& str)
|
||||||
|
|
||||||
void node_t::print_attributes(std::ostream& out) const
|
void node_t::print_attributes(std::ostream& out) const
|
||||||
{
|
{
|
||||||
if (attributes)
|
if (attributes) {
|
||||||
|
#if 1
|
||||||
|
foreach (const attr_pair& attr, *attributes)
|
||||||
|
out << ' ' << *document().lookup_name(attr.first)
|
||||||
|
<< "=\"" << attr.second << "\"";
|
||||||
|
#else
|
||||||
foreach (const attr_pair& attr, attributes->get<0>())
|
foreach (const attr_pair& attr, attributes->get<0>())
|
||||||
out << ' ' << *document().lookup_name(attr.first)
|
out << ' ' << *document().lookup_name(attr.first)
|
||||||
<< "=\"" << attr.second << "\"";
|
<< "=\"" << attr.second << "\"";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
IF_VERIFY()
|
IF_VERIFY()
|
||||||
out << " type=\"parent_node_t\"";
|
out << " type=\"parent_node_t\"";
|
||||||
|
|
|
||||||
104
src/node.h
104
src/node.h
|
|
@ -33,7 +33,6 @@
|
||||||
#define _NODE_H
|
#define _NODE_H
|
||||||
|
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
//#include "parser.h"
|
|
||||||
|
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
namespace xml {
|
namespace xml {
|
||||||
|
|
@ -42,8 +41,9 @@ namespace xml {
|
||||||
|
|
||||||
DECLARE_EXCEPTION(conversion_error);
|
DECLARE_EXCEPTION(conversion_error);
|
||||||
|
|
||||||
class parent_node_t;
|
|
||||||
class document_t;
|
class document_t;
|
||||||
|
class parent_node_t;
|
||||||
|
class terminal_node_t;
|
||||||
|
|
||||||
class node_t : public supports_flags<>, public noncopyable
|
class node_t : public supports_flags<>, public noncopyable
|
||||||
{
|
{
|
||||||
|
|
@ -58,6 +58,10 @@ protected:
|
||||||
document_t& document_;
|
document_t& document_;
|
||||||
optional<parent_node_t&> parent_;
|
optional<parent_node_t&> parent_;
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
typedef std::map<const nameid_t, value_t> attributes_t;
|
||||||
|
typedef std::pair<const nameid_t, value_t> attr_pair;
|
||||||
|
#else
|
||||||
typedef std::pair<nameid_t, value_t> attr_pair;
|
typedef std::pair<nameid_t, value_t> attr_pair;
|
||||||
|
|
||||||
typedef multi_index_container<
|
typedef multi_index_container<
|
||||||
|
|
@ -69,14 +73,15 @@ protected:
|
||||||
>
|
>
|
||||||
> attributes_t;
|
> attributes_t;
|
||||||
|
|
||||||
optional<attributes_t> attributes;
|
|
||||||
|
|
||||||
typedef attributes_t::nth_index<0>::type attributes_by_order;
|
typedef attributes_t::nth_index<0>::type attributes_by_order;
|
||||||
typedef attributes_t::nth_index<1>::type attributes_hashed;
|
typedef attributes_t::nth_index<1>::type attributes_hashed;
|
||||||
|
#endif
|
||||||
|
|
||||||
bool compiled;
|
optional<attributes_t> attributes;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
bool compiled; // so that compile_node() can access it
|
||||||
|
|
||||||
node_t(nameid_t _name_id, document_t& _document,
|
node_t(nameid_t _name_id, document_t& _document,
|
||||||
const optional<parent_node_t&>& _parent = none, flags_t _flags = 0)
|
const optional<parent_node_t&>& _parent = none, flags_t _flags = 0)
|
||||||
: supports_flags<>(_flags), name_id_(_name_id),
|
: supports_flags<>(_flags), name_id_(_name_id),
|
||||||
|
|
@ -88,10 +93,11 @@ public:
|
||||||
TRACE_DTOR(node_t);
|
TRACE_DTOR(node_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void extract();
|
||||||
|
|
||||||
bool is_compiled() const {
|
bool is_compiled() const {
|
||||||
return compiled;
|
return compiled;
|
||||||
}
|
}
|
||||||
virtual void compile() {}
|
|
||||||
|
|
||||||
bool is_parent_node() const {
|
bool is_parent_node() const {
|
||||||
return has_flags(XML_NODE_IS_PARENT);
|
return has_flags(XML_NODE_IS_PARENT);
|
||||||
|
|
@ -102,9 +108,19 @@ public:
|
||||||
return downcast<parent_node_t>(*this);
|
return downcast<parent_node_t>(*this);
|
||||||
}
|
}
|
||||||
const parent_node_t& as_parent_node() const {
|
const parent_node_t& as_parent_node() const {
|
||||||
if (! is_parent_node())
|
return const_cast<node_t *>(this)->as_parent_node();
|
||||||
throw_(std::logic_error, "Request to cast leaf node to a parent node");
|
}
|
||||||
return downcast<const parent_node_t>(*this);
|
|
||||||
|
bool is_terminal_node() const {
|
||||||
|
return ! has_flags(XML_NODE_IS_PARENT);
|
||||||
|
}
|
||||||
|
terminal_node_t& as_terminal_node() {
|
||||||
|
if (! is_terminal_node())
|
||||||
|
throw_(std::logic_error, "Request to cast parent node to a leaf node");
|
||||||
|
return downcast<terminal_node_t>(*this);
|
||||||
|
}
|
||||||
|
const terminal_node_t& as_terminal_node() const {
|
||||||
|
return const_cast<node_t *>(this)->as_terminal_node();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual value_t to_value() const = 0;
|
virtual value_t to_value() const = 0;
|
||||||
|
|
@ -123,29 +139,61 @@ public:
|
||||||
return parent_;
|
return parent_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_attr(const nameid_t _name_id, const char * value) {
|
value_t& set_attr(const string& _name, const char * value);
|
||||||
if (! attributes)
|
value_t& set_attr(const string& _name, const value_t& value);
|
||||||
attributes = attributes_t();
|
|
||||||
attributes->push_back(attr_pair(_name_id, string_value(value)));
|
value_t& set_attr(const nameid_t _name_id, const char * value) {
|
||||||
|
return set_attr(_name_id, string_value(value));
|
||||||
}
|
}
|
||||||
void set_attr(const nameid_t _name_id, const value_t& value) {
|
value_t& set_attr(const nameid_t _name_id, const value_t& value) {
|
||||||
if (! attributes)
|
if (! attributes)
|
||||||
attributes = attributes_t();
|
attributes = attributes_t();
|
||||||
attributes->push_back(attr_pair(_name_id, value));
|
|
||||||
|
attributes_t::iterator i = attributes->find(_name_id);
|
||||||
|
if (i == attributes->end()) {
|
||||||
|
std::pair<attributes_t::iterator, bool> result =
|
||||||
|
attributes->insert(attr_pair(_name_id, value));
|
||||||
|
assert(result.second);
|
||||||
|
return (*result.first).second;
|
||||||
|
} else {
|
||||||
|
i->second = value;
|
||||||
|
return i->second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<value_t> get_attr(const string& _name) const;
|
optional<value_t&> get_attr(const string& _name);
|
||||||
optional<value_t> get_attr(const nameid_t _name_id) const {
|
optional<value_t&> get_attr(const nameid_t _name_id) {
|
||||||
if (attributes) {
|
if (attributes) {
|
||||||
|
#if 1
|
||||||
|
attributes_t::iterator i = attributes->find(_name_id);
|
||||||
|
if (i != attributes->end())
|
||||||
|
return (*i).second;
|
||||||
|
#else
|
||||||
typedef attributes_t::nth_index<1>::type attributes_by_name;
|
typedef attributes_t::nth_index<1>::type attributes_by_name;
|
||||||
|
|
||||||
const attributes_by_name& name_index = attributes->get<1>();
|
const attributes_by_name& name_index = attributes->get<1>();
|
||||||
attributes_by_name::const_iterator i = name_index.find(_name_id);
|
attributes_by_name::iterator i = name_index.find(_name_id);
|
||||||
if (i != name_index.end())
|
if (i != name_index.end())
|
||||||
return (*i).second;
|
return (*i).second;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return none;
|
return none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
optional<const value_t&> get_attr(const string& _name) const {
|
||||||
|
if (optional<value_t&> value =
|
||||||
|
const_cast<node_t *>(this)->get_attr(_name))
|
||||||
|
return *value;
|
||||||
|
else
|
||||||
|
return none;
|
||||||
|
}
|
||||||
|
optional<const value_t&> get_attr(const nameid_t _name_id) const {
|
||||||
|
if (optional<value_t&> value =
|
||||||
|
const_cast<node_t *>(this)->get_attr(_name_id))
|
||||||
|
return *value;
|
||||||
|
else
|
||||||
|
return none;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class parent_node_t : public node_t
|
class parent_node_t : public node_t
|
||||||
|
|
@ -177,11 +225,6 @@ public:
|
||||||
clear_children();
|
clear_children();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void compile() {
|
|
||||||
foreach (node_t * child, *this)
|
|
||||||
child->compile();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T * create_child(nameid_t _name_id) {
|
T * create_child(nameid_t _name_id) {
|
||||||
T * child = new T(_name_id, document(), *this);
|
T * child = new T(_name_id, document(), *this);
|
||||||
|
|
@ -189,14 +232,17 @@ public:
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
void delete_child(node_t * child) {
|
void remove_child(node_t * child) {
|
||||||
children_by_ptr& ptr_index = children.get<2>();
|
children_by_ptr& ptr_index = children.get<2>();
|
||||||
children_by_ptr::iterator i = ptr_index.find(child);
|
children_by_ptr::iterator i = ptr_index.find(child);
|
||||||
if (i == ptr_index.end())
|
if (i == ptr_index.end())
|
||||||
throw_(std::logic_error, "Request to delete node which is not a child");
|
throw_(std::logic_error, "Request to delete node which is not a child");
|
||||||
node_t * ptr = *i;
|
|
||||||
ptr_index.erase(i);
|
ptr_index.erase(i);
|
||||||
checked_delete(ptr);
|
}
|
||||||
|
|
||||||
|
void delete_child(node_t * child) {
|
||||||
|
remove_child(child);
|
||||||
|
checked_delete(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct match_nameid {
|
struct match_nameid {
|
||||||
|
|
@ -262,6 +308,12 @@ public:
|
||||||
void print(std::ostream& out) const;
|
void print(std::ostream& out) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline void node_t::extract()
|
||||||
|
{
|
||||||
|
if (parent_)
|
||||||
|
parent_->remove_child(this);
|
||||||
|
}
|
||||||
|
|
||||||
class terminal_node_t : public node_t
|
class terminal_node_t : public node_t
|
||||||
{
|
{
|
||||||
string data;
|
string data;
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ class session_t : public xml::xpath_t::symbol_scope_t
|
||||||
}
|
}
|
||||||
|
|
||||||
journal_t * create_journal() {
|
journal_t * create_journal() {
|
||||||
journal_t * journal = new journal_t(this);
|
journal_t * journal = new journal_t;
|
||||||
journals.push_back(journal);
|
journals.push_back(journal);
|
||||||
return journal;
|
return journal;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
src/value.cc
10
src/value.cc
|
|
@ -1203,20 +1203,20 @@ void value_t::in_place_reduce()
|
||||||
{
|
{
|
||||||
switch (type()) {
|
switch (type()) {
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
break;
|
return;
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
as_amount_lval().in_place_reduce();
|
as_amount_lval().in_place_reduce();
|
||||||
break;
|
return;
|
||||||
case BALANCE:
|
case BALANCE:
|
||||||
as_balance_lval().in_place_reduce();
|
as_balance_lval().in_place_reduce();
|
||||||
break;
|
return;
|
||||||
case BALANCE_PAIR:
|
case BALANCE_PAIR:
|
||||||
as_balance_pair_lval().in_place_reduce();
|
as_balance_pair_lval().in_place_reduce();
|
||||||
break;
|
return;
|
||||||
case XML_NODE:
|
case XML_NODE:
|
||||||
*this = as_xml_node()->to_value();
|
*this = as_xml_node()->to_value();
|
||||||
in_place_reduce(); // recurse
|
in_place_reduce(); // recurse
|
||||||
break;
|
return;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1208,16 +1208,11 @@ value_t xpath_t::op_t::calc(scope_t& scope)
|
||||||
|
|
||||||
case ATTR_ID:
|
case ATTR_ID:
|
||||||
case ATTR_NAME:
|
case ATTR_NAME:
|
||||||
if (optional<value_t> value =
|
if (optional<value_t&> value =
|
||||||
kind == ATTR_ID ? current_xml_node(scope).get_attr(as_name()) :
|
kind == ATTR_ID ? current_xml_node(scope).get_attr(as_name()) :
|
||||||
current_xml_node(scope).get_attr(as_string()))
|
current_xml_node(scope).get_attr(as_string()))
|
||||||
return *value;
|
return *value;
|
||||||
else
|
|
||||||
throw_(calc_error, "Attribute '"
|
|
||||||
<< (kind == ATTR_ID ?
|
|
||||||
*current_xml_node(scope).document().lookup_name(as_long()) :
|
|
||||||
as_string().c_str())
|
|
||||||
<< "' was not found");
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case O_NEQ:
|
case O_NEQ:
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue