Now using xpath_t::path_t to select nodes.

This commit is contained in:
John Wiegley 2007-05-16 05:38:32 +00:00
parent 74ecceb2ba
commit 7c7e5c5e36
8 changed files with 233 additions and 337 deletions

View file

@ -153,7 +153,7 @@ bool entry_base_t::finalize()
// account if one has been set. // account if one has been set.
if (journal && journal->basket && transactions.size() == 1) { if (journal && journal->basket && transactions.size() == 1) {
assert(balance.is_type(value_t::AMOUNT)); assert(balance.is_amount());
transaction_t * nxact = new transaction_t(journal->basket); transaction_t * nxact = new transaction_t(journal->basket);
// The amount doesn't need to be set because the code below will // The amount doesn't need to be set because the code below will
// balance this transaction against the other. // balance this transaction against the other.
@ -166,7 +166,7 @@ bool entry_base_t::finalize()
// determine its price by dividing the unit count into the value of // determine its price by dividing the unit count into the value of
// the balance. This is done for the last eligible commodity. // the balance. This is done for the last eligible commodity.
if (! saw_null && balance && balance.is_type(value_t::BALANCE) && if (! saw_null && balance && balance.is_balance() &&
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);

View file

@ -268,10 +268,18 @@ static int read_and_report(ledger::report_t * report, int argc, char * argv[],
xpath.print(*out, xml_document); xpath.print(*out, xml_document);
*out << std::endl; *out << std::endl;
foreach (xml::node_t * node, xpath.find_all(xml_document, report)) { value_t result = xpath.calc(xml_document, report);
node->print(std::cout);
if (result.is_sequence()) {
foreach (const value_t& value, result.as_sequence()) {
if (value.is_xml_node()) {
value.as_xml_node()->print(std::cout);
std::cout << std::endl; std::cout << std::endl;
} }
}
} else {
std::cout << result << std::endl;
}
return 0; return 0;
} }

View file

@ -119,6 +119,7 @@ object python_interpreter_t::import(const string& str)
PyErr_Print(); PyErr_Print();
throw_(std::logic_error, "Importing Python module " << str); throw_(std::logic_error, "Importing Python module " << str);
} }
return object();
} }
object python_interpreter_t::eval(std::istream& in, py_eval_mode_t mode) object python_interpreter_t::eval(std::istream& in, py_eval_mode_t mode)
@ -153,6 +154,7 @@ object python_interpreter_t::eval(std::istream& in, py_eval_mode_t mode)
PyErr_Print(); PyErr_Print();
throw_(std::logic_error, "Evaluating Python code"); throw_(std::logic_error, "Evaluating Python code");
} }
return object();
} }
object python_interpreter_t::eval(const string& str, py_eval_mode_t mode) object python_interpreter_t::eval(const string& str, py_eval_mode_t mode)
@ -171,6 +173,7 @@ object python_interpreter_t::eval(const string& str, py_eval_mode_t mode)
PyErr_Print(); PyErr_Print();
throw_(std::logic_error, "Evaluating Python code"); throw_(std::logic_error, "Evaluating Python code");
} }
return object();
} }
value_t python_interpreter_t::functor_t::operator()(xml::xpath_t::scope_t * locals) value_t python_interpreter_t::functor_t::operator()(xml::xpath_t::scope_t * locals)
@ -194,7 +197,7 @@ value_t python_interpreter_t::functor_t::operator()(xml::xpath_t::scope_t * loca
else if (PyObject * err = PyErr_Occurred()) { else if (PyObject * err = PyErr_Occurred()) {
PyErr_Print(); PyErr_Print();
throw_(xml::xpath_t::calc_error, throw_(xml::xpath_t::calc_error,
"While calling Python function '" /*<< name() <<*/ "'"); "While calling Python function '" /*<< name() <<*/ "': " << err);
} else { } else {
assert(false); assert(false);
} }
@ -208,6 +211,7 @@ value_t python_interpreter_t::functor_t::operator()(xml::xpath_t::scope_t * loca
throw_(xml::xpath_t::calc_error, throw_(xml::xpath_t::calc_error,
"While calling Python function '" /*<< name() <<*/ "'"); "While calling Python function '" /*<< name() <<*/ "'");
} }
return NULL_VALUE;
} }
value_t python_interpreter_t::lambda_t::operator() value_t python_interpreter_t::lambda_t::operator()
@ -216,7 +220,7 @@ value_t python_interpreter_t::lambda_t::operator()
try { try {
assert(locals->args.size() == 1); assert(locals->args.size() == 1);
value_t item = locals->args[0]; value_t item = locals->args[0];
assert(item.is_type(value_t::XML_NODE)); assert(item.is_xml_node());
return call<value_t>(func.ptr(), item.as_xml_node()); return call<value_t>(func.ptr(), item.as_xml_node());
} }
catch (const error_already_set&) { catch (const error_already_set&) {
@ -224,6 +228,7 @@ value_t python_interpreter_t::lambda_t::operator()
throw_(xml::xpath_t::calc_error, throw_(xml::xpath_t::calc_error,
"While evaluating Python lambda expression"); "While evaluating Python lambda expression");
} }
return NULL_VALUE;
} }
} // namespace ledger } // namespace ledger

View file

@ -130,6 +130,7 @@ extern "C" {
#include <boost/algorithm/string/classification.hpp> #include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#include <boost/any.hpp>
#include <boost/cast.hpp> #include <boost/cast.hpp>
#include <boost/current_function.hpp> #include <boost/current_function.hpp>
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>

View file

@ -55,6 +55,9 @@ void value_t::storage_t::destroy()
case SEQUENCE: case SEQUENCE:
((sequence_t *)data)->~sequence_t(); ((sequence_t *)data)->~sequence_t();
break; break;
case POINTER:
((boost::any *)data)->~any();
break;
default: default:
break; break;
@ -84,79 +87,7 @@ value_t& value_t::operator=(const value_t& val)
if (this == &val || storage == val.storage) if (this == &val || storage == val.storage)
return *this; return *this;
if (type() == val.type()) storage = val.storage;
switch (type()) {
case VOID:
assert(false);
return *this;
case BOOLEAN:
as_boolean_lval() = val.as_boolean();
return *this;
case INTEGER:
as_long_lval() = val.as_long();
return *this;
case DATETIME:
as_datetime_lval() = val.as_datetime();
return *this;
case AMOUNT:
as_amount_lval() = val.as_amount();
return *this;
case BALANCE:
as_balance_lval() = val.as_balance();
return *this;
case BALANCE_PAIR:
as_balance_pair_lval() = val.as_balance_pair();
return *this;
case STRING:
as_string_lval() = val.as_string();
return *this;
case SEQUENCE:
as_sequence_lval() = val.as_sequence();
return *this;
default:
break;
}
switch (val.type()) {
case VOID:
set_type(VOID);
break;
case BOOLEAN:
set_boolean(val.as_boolean());
break;
case INTEGER:
set_long(val.as_long());
break;
case DATETIME:
set_datetime(val.as_datetime());
break;
case AMOUNT:
set_amount(val.as_amount());
break;
case BALANCE:
set_balance(val.as_balance());
break;
case BALANCE_PAIR:
set_balance_pair(val.as_balance_pair());
break;
case STRING:
set_string(val.as_string());
break;
case SEQUENCE:
set_sequence(val.as_sequence());
break;
case XML_NODE:
set_xml_node(val.as_xml_node());
break;
case POINTER:
set_pointer(val.as_pointer());
break;
default:
assert(false);
break;
}
return *this; return *this;
} }
@ -183,7 +114,7 @@ value_t::operator bool() const
case XML_NODE: case XML_NODE:
return as_xml_node()->to_value(); return as_xml_node()->to_value();
case POINTER: case POINTER:
return as_pointer() != NULL; return ! as_any_pointer().empty();
default: default:
assert(false); assert(false);
break; break;
@ -291,19 +222,19 @@ void value_t::in_place_simplify()
return; return;
} }
if (is_type(BALANCE_PAIR) && if (is_balance_pair() &&
(! as_balance_pair().cost || as_balance_pair().cost->is_realzero())) { (! as_balance_pair().cost || as_balance_pair().cost->is_realzero())) {
DEBUG_("Reducing balance pair to balance"); DEBUG_("Reducing balance pair to balance");
in_place_cast(BALANCE); in_place_cast(BALANCE);
} }
if (is_type(BALANCE) && as_balance().amounts.size() == 1) { if (is_balance() && as_balance().amounts.size() == 1) {
DEBUG_("Reducing balance to amount"); DEBUG_("Reducing balance to amount");
in_place_cast(AMOUNT); in_place_cast(AMOUNT);
} }
#if 0 #if 0
if (is_type(AMOUNT) && ! as_amount().has_commodity() && if (is_amount() && ! as_amount().has_commodity() &&
as_amount().fits_in_long()) { as_amount().fits_in_long()) {
DEBUG_("Reducing amount to integer"); DEBUG_("Reducing amount to integer");
in_place_cast(INTEGER); in_place_cast(INTEGER);
@ -313,15 +244,15 @@ void value_t::in_place_simplify()
value_t& value_t::operator+=(const value_t& val) value_t& value_t::operator+=(const value_t& val)
{ {
if (is_type(STRING)) { if (is_string()) {
if (val.is_type(STRING)) if (val.is_string())
as_string_lval() += val.as_string(); as_string_lval() += val.as_string();
else else
as_string_lval() += val.to_string(); as_string_lval() += val.to_string();
return *this; return *this;
} }
else if (is_type(SEQUENCE)) { else if (is_sequence()) {
if (val.is_type(SEQUENCE)) { if (val.is_sequence()) {
sequence_t& seq(as_sequence_lval()); sequence_t& seq(as_sequence_lval());
seq.insert(seq.end(), val.as_sequence().begin(), seq.insert(seq.end(), val.as_sequence().begin(),
val.as_sequence().end()); val.as_sequence().end());
@ -331,7 +262,7 @@ value_t& value_t::operator+=(const value_t& val)
return *this; return *this;
} }
if (val.is_type(XML_NODE)) // recurse if (val.is_xml_node()) // recurse
return *this += val.as_xml_node()->to_value(); return *this += val.as_xml_node()->to_value();
switch (type()) { switch (type()) {
@ -456,10 +387,10 @@ value_t& value_t::operator+=(const value_t& val)
value_t& value_t::operator-=(const value_t& val) value_t& value_t::operator-=(const value_t& val)
{ {
if (is_type(SEQUENCE)) { if (is_sequence()) {
sequence_t& seq(as_sequence_lval()); sequence_t& seq(as_sequence_lval());
if (val.is_type(SEQUENCE)) { if (val.is_sequence()) {
for (sequence_t::const_iterator i = val.as_sequence().begin(); for (sequence_t::const_iterator i = val.as_sequence().begin();
i != val.as_sequence().end(); i != val.as_sequence().end();
i++) { i++) {
@ -475,7 +406,7 @@ value_t& value_t::operator-=(const value_t& val)
return *this; return *this;
} }
if (val.is_type(XML_NODE)) // recurse if (val.is_xml_node()) // recurse
return *this -= val.as_xml_node()->to_value(); return *this -= val.as_xml_node()->to_value();
switch (type()) { switch (type()) {
@ -619,7 +550,7 @@ value_t& value_t::operator-=(const value_t& val)
value_t& value_t::operator*=(const value_t& val) value_t& value_t::operator*=(const value_t& val)
{ {
if (is_type(STRING)) { if (is_string()) {
string temp; string temp;
long count = val.to_long(); long count = val.to_long();
for (long i = 0; i < count; i++) for (long i = 0; i < count; i++)
@ -627,7 +558,7 @@ value_t& value_t::operator*=(const value_t& val)
set_string(temp); set_string(temp);
return *this; return *this;
} }
else if (is_type(SEQUENCE)) { else if (is_sequence()) {
value_t temp; value_t temp;
long count = val.to_long(); long count = val.to_long();
for (long i = 0; i < count; i++) for (long i = 0; i < count; i++)
@ -635,7 +566,7 @@ value_t& value_t::operator*=(const value_t& val)
return *this = temp; return *this = temp;
} }
if (val.is_type(XML_NODE)) // recurse if (val.is_xml_node()) // recurse
return *this *= val.as_xml_node()->to_value(); return *this *= val.as_xml_node()->to_value();
switch (type()) { switch (type()) {
@ -712,7 +643,7 @@ value_t& value_t::operator*=(const value_t& val)
value_t& value_t::operator/=(const value_t& val) value_t& value_t::operator/=(const value_t& val)
{ {
if (val.is_type(XML_NODE)) // recurse if (val.is_xml_node()) // recurse
return *this /= val.as_xml_node()->to_value(); return *this /= val.as_xml_node()->to_value();
switch (type()) { switch (type()) {
@ -791,21 +722,21 @@ value_t& value_t::operator/=(const value_t& val)
bool value_t::operator==(const value_t& val) const bool value_t::operator==(const value_t& val) const
{ {
if (is_type(XML_NODE) && val.is_type(XML_NODE)) if (is_xml_node() && val.is_xml_node())
return as_xml_node() == val.as_xml_node(); return as_xml_node() == val.as_xml_node();
else if (is_type(XML_NODE)) else if (is_xml_node())
return as_xml_node()->to_value() == val; return as_xml_node()->to_value() == val;
else if (val.is_type(XML_NODE)) else if (val.is_xml_node())
return *this == val.as_xml_node()->to_value(); return *this == val.as_xml_node()->to_value();
switch (type()) { switch (type()) {
case BOOLEAN: case BOOLEAN:
if (val.is_type(BOOLEAN)) if (val.is_boolean())
return as_boolean() == val.as_boolean(); return as_boolean() == val.as_boolean();
break; break;
case DATETIME: case DATETIME:
if (val.is_type(DATETIME)) if (val.is_datetime())
return as_datetime() == val.as_datetime(); return as_datetime() == val.as_datetime();
break; break;
@ -870,20 +801,15 @@ bool value_t::operator==(const value_t& val) const
break; break;
case STRING: case STRING:
if (val.is_type(STRING)) if (val.is_string())
return as_string() == val.as_string(); return as_string() == val.as_string();
break; break;
case SEQUENCE: case SEQUENCE:
if (val.is_type(SEQUENCE)) if (val.is_sequence())
return as_sequence() == val.as_sequence(); return as_sequence() == val.as_sequence();
break; break;
case POINTER:
if (val.is_type(POINTER))
return as_pointer() == val.as_pointer();
break;
default: default:
break; break;
} }
@ -895,16 +821,16 @@ bool value_t::operator==(const value_t& val) const
bool value_t::operator<(const value_t& val) const bool value_t::operator<(const value_t& val) const
{ {
if (is_type(XML_NODE) && val.is_type(XML_NODE)) if (is_xml_node() && val.is_xml_node())
return as_xml_node() < val.as_xml_node(); return as_xml_node() < val.as_xml_node();
else if (is_type(XML_NODE)) else if (is_xml_node())
return as_xml_node()->to_value() < val; return as_xml_node()->to_value() < val;
else if (val.is_type(XML_NODE)) else if (val.is_xml_node())
return *this < val.as_xml_node()->to_value(); return *this < val.as_xml_node()->to_value();
switch (type()) { switch (type()) {
case DATETIME: case DATETIME:
if (val.is_type(DATETIME)) if (val.is_datetime())
return as_datetime() < val.as_datetime(); return as_datetime() < val.as_datetime();
break; break;
@ -931,15 +857,10 @@ bool value_t::operator<(const value_t& val) const
break; break;
case STRING: case STRING:
if (val.is_type(STRING)) if (val.is_string())
return as_string() < val.as_string(); return as_string() < val.as_string();
break; break;
case POINTER:
if (val.is_type(POINTER))
return as_pointer() < val.as_pointer();
break;
default: default:
break; break;
} }
@ -952,16 +873,16 @@ bool value_t::operator<(const value_t& val) const
#if 0 #if 0
bool value_t::operator>(const value_t& val) const bool value_t::operator>(const value_t& val) const
{ {
if (is_type(XML_NODE) && val.is_type(XML_NODE)) if (is_xml_node() && val.is_xml_node())
return as_xml_node() > val.as_xml_node(); return as_xml_node() > val.as_xml_node();
else if (is_type(XML_NODE)) else if (is_xml_node())
return as_xml_node()->to_value() > val; return as_xml_node()->to_value() > val;
else if (val.is_type(XML_NODE)) else if (val.is_xml_node())
return *this > val.as_xml_node()->to_value(); return *this > val.as_xml_node()->to_value();
switch (type()) { switch (type()) {
case DATETIME: case DATETIME:
if (val.is_type(DATETIME)) if (val.is_datetime())
return as_datetime() > val.as_datetime(); return as_datetime() > val.as_datetime();
break; break;
@ -988,15 +909,10 @@ bool value_t::operator>(const value_t& val) const
break; break;
case STRING: case STRING:
if (val.is_type(STRING)) if (val.is_string())
return as_string() > val.as_string(); return as_string() > val.as_string();
break; break;
case POINTER:
if (val.is_type(POINTER))
return as_pointer() > val.as_pointer();
break;
default: default:
break; break;
} }
@ -1028,7 +944,7 @@ void value_t::in_place_cast(type_t cast_type)
// This must came after the if's above, otherwise it would be // This must came after the if's above, otherwise it would be
// impossible to turn an XML node into a sequence containing that // impossible to turn an XML node into a sequence containing that
// same XML node. // same XML node.
if (is_type(XML_NODE)) { if (is_xml_node()) {
*this = as_xml_node()->to_value().cast(cast_type); *this = as_xml_node()->to_value().cast(cast_type);
return; return;
} }
@ -1214,7 +1130,7 @@ bool value_t::is_realzero() const
case XML_NODE: case XML_NODE:
return as_xml_node() == NULL; return as_xml_node() == NULL;
case POINTER: case POINTER:
return as_pointer() == NULL; return as_any_pointer().empty();
default: default:
assert(false); assert(false);
@ -1310,18 +1226,23 @@ value_t value_t::unround() const
throw_(value_error, "Cannot un-round a boolean"); throw_(value_error, "Cannot un-round a boolean");
case DATETIME: case DATETIME:
throw_(value_error, "Cannot un-round a date/time"); throw_(value_error, "Cannot un-round a date/time");
case INTEGER: case INTEGER:
return *this; return *this;
case AMOUNT: case AMOUNT:
return as_amount().unround(); return as_amount().unround();
case BALANCE: case BALANCE:
return as_balance().unround(); return as_balance().unround();
case BALANCE_PAIR: case BALANCE_PAIR:
return as_balance_pair().unround(); return as_balance_pair().unround();
case STRING: case STRING:
throw_(value_error, "Cannot un-round a string"); throw_(value_error, "Cannot un-round a string");
case XML_NODE: case XML_NODE:
return as_xml_node()->to_value().unround(); return as_xml_node()->to_value().unround();
case POINTER: case POINTER:
throw_(value_error, "Cannot un-round a pointer"); throw_(value_error, "Cannot un-round a pointer");
case SEQUENCE: case SEQUENCE:
@ -1496,10 +1417,12 @@ value_t value_t::cost() const
switch (type()) { switch (type()) {
case BOOLEAN: case BOOLEAN:
throw_(value_error, "Cannot find the cost of a boolean"); throw_(value_error, "Cannot find the cost of a boolean");
case INTEGER: case INTEGER:
case AMOUNT: case AMOUNT:
case BALANCE: case BALANCE:
return *this; return *this;
case DATETIME: case DATETIME:
throw_(value_error, "Cannot find the cost of a date/time"); throw_(value_error, "Cannot find the cost of a date/time");
@ -1512,8 +1435,10 @@ value_t value_t::cost() const
case STRING: case STRING:
throw_(value_error, "Cannot find the cost of a string"); throw_(value_error, "Cannot find the cost of a string");
case XML_NODE: case XML_NODE:
return as_xml_node()->to_value().cost(); return as_xml_node()->to_value().cost();
case POINTER: case POINTER:
throw_(value_error, "Cannot find the cost of a pointer"); throw_(value_error, "Cannot find the cost of a pointer");
case SEQUENCE: case SEQUENCE:
@ -1541,13 +1466,13 @@ value_t& value_t::add(const amount_t& amount, const optional<amount_t>& tcost)
in_place_cast(BALANCE_PAIR); in_place_cast(BALANCE_PAIR);
return add(amount, tcost); return add(amount, tcost);
} }
else if ((is_type(AMOUNT) && else if ((is_amount() &&
as_amount().commodity() != amount.commodity()) || as_amount().commodity() != amount.commodity()) ||
(! is_type(AMOUNT) && amount.commodity())) { (! is_amount() && amount.commodity())) {
in_place_cast(BALANCE); in_place_cast(BALANCE);
return add(amount, tcost); return add(amount, tcost);
} }
else if (! is_type(AMOUNT)) { else if (! is_amount()) {
in_place_cast(AMOUNT); in_place_cast(AMOUNT);
} }
*this += amount; *this += amount;

View file

@ -72,6 +72,7 @@ public:
STRING, STRING,
SEQUENCE, SEQUENCE,
XML_NODE, XML_NODE,
CONST_XML_NODE,
POINTER POINTER
}; };
@ -216,6 +217,10 @@ public:
TRACE_CTOR(value_t, "xml::node_t *"); TRACE_CTOR(value_t, "xml::node_t *");
set_xml_node(xml_node); set_xml_node(xml_node);
} }
value_t(const xml::node_t * xml_node) {
TRACE_CTOR(value_t, "const xml::node_t *");
set_xml_node(xml_node);
}
value_t(void * item) { value_t(void * item) {
TRACE_CTOR(value_t, "void *"); TRACE_CTOR(value_t, "void *");
set_pointer(item); set_pointer(item);
@ -248,14 +253,16 @@ public:
operator bool() const; operator bool() const;
bool is_null() const { bool is_null() const {
return ! storage || storage->type == VOID; return ! storage || is_type(VOID);
}
type_t type() const {
type_t result = storage ? storage->type : VOID;
assert(result >= VOID && result <= POINTER);
return result;
} }
type_t type() const { private:
return storage ? storage->type : VOID;
}
bool is_type(type_t _type) const { bool is_type(type_t _type) const {
assert(_type >= VOID && _type <= POINTER);
return type() == _type; return type() == _type;
} }
void set_type(type_t new_type) { void set_type(type_t new_type) {
@ -265,6 +272,7 @@ public:
assert(is_type(new_type)); assert(is_type(new_type));
} }
public:
bool is_boolean() const { bool is_boolean() const {
return is_type(BOOLEAN); return is_type(BOOLEAN);
} }
@ -402,37 +410,63 @@ public:
} }
bool is_xml_node() const { bool is_xml_node() const {
return is_type(XML_NODE); return is_type(XML_NODE) || is_type(CONST_XML_NODE);
} }
xml::node_t *& as_xml_node_lval() { xml::node_t *& as_xml_node_lval() {
assert(is_xml_node()); assert(is_xml_node());
assert(! is_type(CONST_XML_NODE));
_dup(); _dup();
return *(xml::node_t **) storage->data; return *(xml::node_t **) storage->data;
} }
xml::node_t * as_xml_node() const { xml::node_t * as_xml_node_mutable() {
assert(is_xml_node()); assert(is_xml_node());
assert(! is_type(CONST_XML_NODE));
return *(xml::node_t **) storage->data; return *(xml::node_t **) storage->data;
} }
const xml::node_t * as_xml_node() const {
assert(is_xml_node());
return *(const xml::node_t **) storage->data;
}
void set_xml_node(xml::node_t * val) { void set_xml_node(xml::node_t * val) {
set_type(XML_NODE); set_type(XML_NODE);
*(xml::node_t **) storage->data = val; *(xml::node_t **) storage->data = val;
} }
void set_xml_node(const xml::node_t * val) {
set_type(CONST_XML_NODE);
*(const xml::node_t **) storage->data = val;
}
bool is_pointer() const { bool is_pointer() const {
return is_type(POINTER); return is_type(POINTER);
} }
void *& as_pointer_lval() { boost::any& as_any_pointer_lval() {
assert(is_pointer()); assert(is_pointer());
_dup(); _dup();
return *(void **) storage->data; return *(boost::any *) storage->data;
} }
void * as_pointer() const { template <typename T>
T *& as_pointer_lval() {
assert(is_pointer()); assert(is_pointer());
return *(void **) storage->data; _dup();
return any_cast<T *>(*(boost::any *) storage->data);
} }
void set_pointer(void * val) { boost::any as_any_pointer() const {
assert(is_pointer());
return *(boost::any *) storage->data;
}
template <typename T>
T * as_pointer() const {
assert(is_pointer());
return any_cast<T *>(*(boost::any *) storage->data);
}
void set_any_pointer(const boost::any& val) {
set_type(POINTER); set_type(POINTER);
*(void **) storage->data = val; new((boost::any *) storage->data) boost::any(val);
}
template <typename T>
void set_pointer(T * val) {
set_type(POINTER);
new((boost::any *) storage->data) boost::any(val);
} }
bool to_boolean() const; bool to_boolean() const;
@ -498,6 +532,7 @@ public:
case SEQUENCE: case SEQUENCE:
return "a sequence"; return "a sequence";
case XML_NODE: case XML_NODE:
case CONST_XML_NODE:
return "an xml node"; return "an xml node";
case POINTER: case POINTER:
return "a pointer"; return "a pointer";

View file

@ -1044,39 +1044,6 @@ xpath_t::op_t::copy(ptr_op_t tleft, ptr_op_t tright) const
return node; return node;
} }
void xpath_t::op_t::find_values(const node_t& context, scope_t * scope,
value_t::sequence_t& result_seq,
bool recursive)
{
xpath_t expr(compile(context, scope, true));
if (expr.ptr->is_value() &&
(expr.ptr->as_value().is_xml_node() ||
expr.ptr->as_value().is_sequence()))
append_value(result_seq, expr.ptr->as_value());
if (recursive && context.is_parent_node())
foreach (node_t * node, context.as_parent_node())
find_values(*node, scope, result_seq, recursive);
}
bool xpath_t::op_t::test_value(const node_t& context, scope_t * scope, int index)
{
xpath_t expr(compile(context, scope, true));
if (expr.ptr->kind != VALUE)
throw_(calc_error, "Predicate expression does not yield a constant value");
switch (expr.ptr->as_value().type()) {
case value_t::INTEGER:
case value_t::AMOUNT:
return expr.ptr->as_value() == value_t((long)index + 1);
default:
return expr.ptr->as_value().as_boolean();
}
}
xpath_t::ptr_op_t xpath_t::op_t::defer_sequence(value_t::sequence_t& result_seq) xpath_t::ptr_op_t xpath_t::op_t::defer_sequence(value_t::sequence_t& result_seq)
{ {
// If not all of the elements were constants, transform the result // If not all of the elements were constants, transform the result
@ -1102,7 +1069,7 @@ xpath_t::ptr_op_t xpath_t::op_t::defer_sequence(value_t::sequence_t& result_seq)
opp = &(*opp)->right(); opp = &(*opp)->right();
} }
if (! (*i).is_type(value_t::POINTER)) if (! (*i).is_pointer())
*opp = wrap_value(*i); *opp = wrap_value(*i);
else else
#if 1 #if 1
@ -1117,7 +1084,7 @@ xpath_t::ptr_op_t xpath_t::op_t::defer_sequence(value_t::sequence_t& result_seq)
void xpath_t::op_t::append_value(value_t::sequence_t& result_seq, value_t& val) void xpath_t::op_t::append_value(value_t::sequence_t& result_seq, value_t& val)
{ {
if (val.is_type(value_t::SEQUENCE)) if (val.is_sequence())
std::for_each(val.as_sequence().begin(), val.as_sequence().end(), std::for_each(val.as_sequence().begin(), val.as_sequence().end(),
bind(&value_t::sequence_t::push_back, ref(result_seq), _1)); bind(&value_t::sequence_t::push_back, ref(result_seq), _1));
else else
@ -1134,57 +1101,6 @@ xpath_t::op_t::compile(const node_t& context, scope_t * scope, bool resolve)
case VALUE: case VALUE:
return this; return this;
case NODE_ID:
switch (as_name()) {
case document_t::CURRENT:
return wrap_value(&context);
case document_t::PARENT:
if (context.parent())
return wrap_value(&*context.parent());
else
throw_(compile_error, "Referencing parent node from the root node");
case document_t::ROOT:
return wrap_value(&context.document());
case document_t::ALL: {
value_t::sequence_t nodes;
foreach (node_t * node, context.as_parent_node())
nodes.push_back(node);
return wrap_value(nodes);
}
default:
break; // pass down to the NODE_NAME case
}
// fall through...
case NODE_NAME:
if (resolve) {
// First, look up the symbol as a node name within the current
// context. If any exist, then return the set of names.
if (context.is_parent_node()) {
value_t::sequence_t nodes;
foreach (node_t * node, context.as_parent_node()) {
if ((kind == NODE_NAME &&
std::strcmp(as_string().c_str(), node->name()) == 0) ||
(kind == NODE_ID && as_name() == node->name_id()))
nodes.push_back(node);
}
return wrap_value(nodes);
}
}
else if (optional<node_t::nameid_t> id =
context.document().lookup_name_id(as_string())) {
ptr_op_t node = new_node(NODE_ID);
node->set_name(*id);
return node;
}
return this;
case ATTR_ID: case ATTR_ID:
if (optional<const string&> value = context.get_attr(as_long())) if (optional<const string&> value = context.get_attr(as_long()))
return wrap_value(*value); return wrap_value(*value);
@ -1566,64 +1482,13 @@ xpath_t::op_t::compile(const node_t& context, scope_t * scope, bool resolve)
case O_FIND: case O_FIND:
case O_RFIND: case O_RFIND:
case O_PRED: { case NODE_ID:
xpath_t lexpr(left()->compile(context, scope, resolve)); case NODE_NAME:
xpath_t rexpr(resolve ? right() : right()->compile(context, scope, false)); return wrap_value(path_t(ptr_op_t(this)).find_all(context, scope));
if (! lexpr.ptr->is_value() || ! resolve) { case O_PRED:
if (left() == lexpr.ptr) assert(false); // this should never occur by itself
return this;
else
return copy(lexpr.ptr, rexpr.ptr);
}
value_t::sequence_t result_seq;
// jww (2006-09-24): What about when nothing is found?
switch (lexpr.ptr->as_value().type()) {
case value_t::XML_NODE: {
value_t& value(lexpr.ptr->as_value());
function_scope_t xpath_fscope(*value.as_xml_node(), 0, 1, scope);
if (kind == O_PRED) {
if (rexpr.ptr->test_value(*value.as_xml_node(), &xpath_fscope))
result_seq.push_back(value);
} else {
rexpr.ptr->find_values(*value.as_xml_node(), &xpath_fscope,
result_seq, kind == O_RFIND);
}
break; break;
}
case value_t::SEQUENCE: {
const value_t::sequence_t& seq(lexpr.ptr->as_value().as_sequence());
int index = 0;
for (value_t::sequence_t::const_iterator i = seq.begin();
i != seq.end();
i++, index++) {
assert(! (*i).is_type(value_t::SEQUENCE));
if (! (*i).is_type(value_t::XML_NODE))
throw_(compile_error, "Attempting to apply path selection "
"to non-node(s)");
function_scope_t xpath_fscope(seq, *(*i).as_xml_node(), index, scope);
if (kind == O_PRED) {
if (rexpr.ptr->test_value(*(*i).as_xml_node(), &xpath_fscope, index))
result_seq.push_back(*i);
} else {
rexpr.ptr->find_values(*(*i).as_xml_node(), &xpath_fscope, result_seq,
kind == O_RFIND);
}
}
break;
}
default:
throw_(compile_error, "Attempting to apply path selection "
"to non-node(s)");
}
return wrap_value(result_seq);
}
case LAST: case LAST:
default: default:
@ -1763,6 +1628,7 @@ bool xpath_t::op_t::print(std::ostream& out,
break; break;
case value_t::XML_NODE: case value_t::XML_NODE:
case value_t::CONST_XML_NODE:
out << '<' << value << '>'; out << '<' << value << '>';
break; break;
case value_t::POINTER: case value_t::POINTER:
@ -2115,12 +1981,13 @@ void xpath_t::op_t::dump(std::ostream& out, const int depth) const
} }
} }
void xpath_t::path_t::check_element(node_t& start, template <typename NodeType, typename FuncType>
void xpath_t::path_t::check_element(NodeType& start,
const ptr_op_t& element, const ptr_op_t& element,
scope_t * scope, scope_t * scope,
std::size_t index, std::size_t index,
std::size_t size, std::size_t size,
const visitor_t& func) const FuncType& func)
{ {
if (element->kind > op_t::TERMINALS && if (element->kind > op_t::TERMINALS &&
element->left()->kind == op_t::O_PRED) { element->left()->kind == op_t::O_PRED) {
@ -2132,15 +1999,16 @@ void xpath_t::path_t::check_element(node_t& start,
if (element->kind < op_t::TERMINALS) if (element->kind < op_t::TERMINALS)
func(start); func(start);
else else
walk_elements(start, element->right(), element->kind == op_t::O_RFIND, walk_elements<NodeType, FuncType>
scope, func); (start, element->right(), element->kind == op_t::O_RFIND, scope, func);
} }
void xpath_t::path_t::walk_elements(node_t& start, template <typename NodeType, typename FuncType>
void xpath_t::path_t::walk_elements(NodeType& start,
const ptr_op_t& element, const ptr_op_t& element,
const bool recurse, const bool recurse,
scope_t * scope, scope_t * scope,
const visitor_t& func) const FuncType& func)
{ {
ptr_op_t name(element->kind < op_t::TERMINALS ? element : element->left()); ptr_op_t name(element->kind < op_t::TERMINALS ? element : element->left());
if (name->kind == op_t::O_PRED) if (name->kind == op_t::O_PRED)
@ -2205,5 +2073,39 @@ void xpath_t::path_t::walk_elements(node_t& start,
} }
} }
template
void xpath_t::path_t::walk_elements<node_t, xpath_t::path_t::visitor_t>
(node_t& start,
const ptr_op_t& element,
const bool recurse,
scope_t * scope,
const visitor_t& func);
template
void xpath_t::path_t::walk_elements<const node_t, xpath_t::path_t::const_visitor_t>
(const node_t& start,
const ptr_op_t& element,
const bool recurse,
scope_t * scope,
const const_visitor_t& func);
template
void xpath_t::path_t::check_element<node_t, xpath_t::path_t::visitor_t>
(node_t& start,
const ptr_op_t& element,
scope_t * scope,
std::size_t index,
std::size_t size,
const visitor_t& func);
template
void xpath_t::path_t::check_element<const node_t, xpath_t::path_t::const_visitor_t>
(const node_t& start,
const ptr_op_t& element,
scope_t * scope,
std::size_t index,
std::size_t size,
const const_visitor_t& func);
} // namespace xml } // namespace xml
} // namespace ledger } // namespace ledger

View file

@ -217,7 +217,9 @@ public:
class path_t class path_t
{ {
typedef function<void (node_t&)> visitor_t; typedef function<void (node_t&)> visitor_t;
typedef function<bool (node_t&, scope_t *)> predicate_t; typedef function<void (const node_t&)> const_visitor_t;
typedef function<bool (const node_t&, scope_t *)> predicate_t;
struct value_node_appender_t { struct value_node_appender_t {
value_t::sequence_t& sequence; value_t::sequence_t& sequence;
@ -228,36 +230,59 @@ public:
} }
}; };
struct const_value_node_appender_t {
value_t::sequence_t& sequence;
const_value_node_appender_t(value_t::sequence_t& _sequence)
: sequence(_sequence) {}
void operator()(const node_t& node) {
sequence.push_back(&node);
}
};
ptr_op_t path_expr; ptr_op_t path_expr;
template <typename NodeType, typename FuncType>
void walk_elements(NodeType& start,
const ptr_op_t& element,
const bool recurse,
scope_t * scope,
const FuncType& func);
template <typename NodeType, typename FuncType>
void check_element(NodeType& start,
const ptr_op_t& element,
scope_t * scope,
std::size_t index,
std::size_t size,
const FuncType& func);
public: public:
path_t(const xpath_t& xpath) : path_expr(xpath.ptr) {} path_t(const xpath_t& xpath) : path_expr(xpath.ptr) {}
path_t(const ptr_op_t& _path_expr) : path_expr(_path_expr) {}
value_t find_all(node_t& start, scope_t * scope) { value_t find_all(node_t& start, scope_t * scope) {
value_t result = value_t::sequence_t(); value_t result = value_t::sequence_t();
visit(start, scope, value_node_appender_t(result.as_sequence_lval())); visit(start, scope, value_node_appender_t(result.as_sequence_lval()));
return result; return result;
} }
value_t find_all(const node_t& start, scope_t * scope) {
void visit(node_t& start, scope_t * scope, value_t result = value_t::sequence_t();
const function<void (node_t&)>& func) { visit(start, scope,
if (path_expr) const_value_node_appender_t(result.as_sequence_lval()));
walk_elements(start, path_expr, false, scope, func); return result;
} }
private: void visit(node_t& start, scope_t * scope, const visitor_t& func) {
void walk_elements(node_t& start, if (path_expr)
const ptr_op_t& element, walk_elements<node_t, visitor_t>
const bool recurse, (start, path_expr, false, scope, func);
scope_t * scope, }
const visitor_t& func); void visit(const node_t& start, scope_t * scope,
const const_visitor_t& func) {
void check_element(node_t& start, if (path_expr)
const ptr_op_t& element, walk_elements<const node_t, const_visitor_t>
scope_t * scope, (start, path_expr, false, scope, func);
std::size_t index, }
std::size_t size,
const visitor_t& func);
}; };
class path_iterator_t class path_iterator_t
@ -523,10 +548,6 @@ public:
ptr_op_t copy(ptr_op_t left = NULL, ptr_op_t right = NULL) const; ptr_op_t copy(ptr_op_t left = NULL, ptr_op_t right = NULL) const;
ptr_op_t compile(const node_t& context, scope_t * scope, bool resolve = false); ptr_op_t compile(const node_t& context, scope_t * scope, bool resolve = false);
void find_values(const node_t& context, scope_t * scope,
value_t::sequence_t& result_seq, bool recursive);
bool test_value(const node_t& context, scope_t * scope, int index = 0);
void append_value(value_t::sequence_t& result_seq, value_t& value); void append_value(value_t::sequence_t& result_seq, value_t& value);
static ptr_op_t defer_sequence(value_t::sequence_t& result_seq); static ptr_op_t defer_sequence(value_t::sequence_t& result_seq);
@ -539,16 +560,22 @@ public:
unsigned long * end_pos = NULL) const; unsigned long * end_pos = NULL) const;
void dump(std::ostream& out, const int depth) const; void dump(std::ostream& out, const int depth) const;
friend inline void intrusive_ptr_add_ref(xpath_t::op_t * op) {
op->acquire();
}
friend inline void intrusive_ptr_release(xpath_t::op_t * op) {
op->release();
}
}; };
class op_predicate class op_predicate
{ {
ptr_op_t op; ptr_op_t op;
public: public:
op_predicate(ptr_op_t _op) : op(_op) {} op_predicate(ptr_op_t _op) : op(_op) {}
bool operator()(node_t& node, scope_t * scope) { bool operator()(const node_t& node, scope_t * scope) {
xpath_t result(op->compile(node, scope, true)); xpath_t result(op->compile(node, scope, true));
return result.ptr->as_value().to_boolean(); return result.ptr->as_value().to_boolean();
} }
@ -746,19 +773,12 @@ public:
friend class scope_t; friend class scope_t;
}; };
inline void intrusive_ptr_add_ref(xpath_t::op_t * op) {
op->acquire();
}
inline void intrusive_ptr_release(xpath_t::op_t * op) {
op->release();
}
} // namespace xml } // namespace xml
template <typename T> template <typename T>
inline T * get_ptr(xml::xpath_t::scope_t * locals, unsigned int idx) { inline T * get_ptr(xml::xpath_t::scope_t * locals, unsigned int idx) {
assert(locals->args.size() > idx); assert(locals->args.size() > idx);
T * ptr = static_cast<T *>(locals->args[idx].as_pointer()); T * ptr = locals->args[idx].as_pointer<T>();
assert(ptr); assert(ptr);
return ptr; return ptr;
} }
@ -766,7 +786,7 @@ inline T * get_ptr(xml::xpath_t::scope_t * locals, unsigned int idx) {
template <typename T> template <typename T>
inline T * get_node_ptr(xml::xpath_t::scope_t * locals, unsigned int idx) { inline T * get_node_ptr(xml::xpath_t::scope_t * locals, unsigned int idx) {
assert(locals->args.size() > idx); assert(locals->args.size() > idx);
T * ptr = polymorphic_downcast<T *>(locals->args[idx].as_xml_node()); T * ptr = polymorphic_downcast<T *>(locals->args[idx].as_xml_node_mutable());
assert(ptr); assert(ptr);
return ptr; return ptr;
} }