Now using xpath_t::path_t to select nodes.
This commit is contained in:
parent
74ecceb2ba
commit
7c7e5c5e36
8 changed files with 233 additions and 337 deletions
|
|
@ -153,7 +153,7 @@ bool entry_base_t::finalize()
|
|||
// account if one has been set.
|
||||
|
||||
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);
|
||||
// The amount doesn't need to be set because the code below will
|
||||
// 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
|
||||
// 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) {
|
||||
transactions_list::const_iterator x = transactions.begin();
|
||||
assert((*x)->amount);
|
||||
|
|
|
|||
14
src/main.cc
14
src/main.cc
|
|
@ -268,9 +268,17 @@ static int read_and_report(ledger::report_t * report, int argc, char * argv[],
|
|||
xpath.print(*out, xml_document);
|
||||
*out << std::endl;
|
||||
|
||||
foreach (xml::node_t * node, xpath.find_all(xml_document, report)) {
|
||||
node->print(std::cout);
|
||||
std::cout << std::endl;
|
||||
value_t result = xpath.calc(xml_document, report);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::cout << result << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ object python_interpreter_t::import(const string& str)
|
|||
PyErr_Print();
|
||||
throw_(std::logic_error, "Importing Python module " << str);
|
||||
}
|
||||
return object();
|
||||
}
|
||||
|
||||
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();
|
||||
throw_(std::logic_error, "Evaluating Python code");
|
||||
}
|
||||
return object();
|
||||
}
|
||||
|
||||
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();
|
||||
throw_(std::logic_error, "Evaluating Python code");
|
||||
}
|
||||
return object();
|
||||
}
|
||||
|
||||
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()) {
|
||||
PyErr_Print();
|
||||
throw_(xml::xpath_t::calc_error,
|
||||
"While calling Python function '" /*<< name() <<*/ "'");
|
||||
"While calling Python function '" /*<< name() <<*/ "': " << err);
|
||||
} else {
|
||||
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,
|
||||
"While calling Python function '" /*<< name() <<*/ "'");
|
||||
}
|
||||
return NULL_VALUE;
|
||||
}
|
||||
|
||||
value_t python_interpreter_t::lambda_t::operator()
|
||||
|
|
@ -216,7 +220,7 @@ value_t python_interpreter_t::lambda_t::operator()
|
|||
try {
|
||||
assert(locals->args.size() == 1);
|
||||
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());
|
||||
}
|
||||
catch (const error_already_set&) {
|
||||
|
|
@ -224,6 +228,7 @@ value_t python_interpreter_t::lambda_t::operator()
|
|||
throw_(xml::xpath_t::calc_error,
|
||||
"While evaluating Python lambda expression");
|
||||
}
|
||||
return NULL_VALUE;
|
||||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ extern "C" {
|
|||
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/any.hpp>
|
||||
#include <boost/cast.hpp>
|
||||
#include <boost/current_function.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
|
|
|||
177
src/value.cc
177
src/value.cc
|
|
@ -55,6 +55,9 @@ void value_t::storage_t::destroy()
|
|||
case SEQUENCE:
|
||||
((sequence_t *)data)->~sequence_t();
|
||||
break;
|
||||
case POINTER:
|
||||
((boost::any *)data)->~any();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
|
@ -84,79 +87,7 @@ value_t& value_t::operator=(const value_t& val)
|
|||
if (this == &val || storage == val.storage)
|
||||
return *this;
|
||||
|
||||
if (type() == val.type())
|
||||
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;
|
||||
}
|
||||
storage = val.storage;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -183,7 +114,7 @@ value_t::operator bool() const
|
|||
case XML_NODE:
|
||||
return as_xml_node()->to_value();
|
||||
case POINTER:
|
||||
return as_pointer() != NULL;
|
||||
return ! as_any_pointer().empty();
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
|
|
@ -291,19 +222,19 @@ void value_t::in_place_simplify()
|
|||
return;
|
||||
}
|
||||
|
||||
if (is_type(BALANCE_PAIR) &&
|
||||
if (is_balance_pair() &&
|
||||
(! as_balance_pair().cost || as_balance_pair().cost->is_realzero())) {
|
||||
DEBUG_("Reducing balance pair to 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");
|
||||
in_place_cast(AMOUNT);
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (is_type(AMOUNT) && ! as_amount().has_commodity() &&
|
||||
if (is_amount() && ! as_amount().has_commodity() &&
|
||||
as_amount().fits_in_long()) {
|
||||
DEBUG_("Reducing amount to integer");
|
||||
in_place_cast(INTEGER);
|
||||
|
|
@ -313,15 +244,15 @@ void value_t::in_place_simplify()
|
|||
|
||||
value_t& value_t::operator+=(const value_t& val)
|
||||
{
|
||||
if (is_type(STRING)) {
|
||||
if (val.is_type(STRING))
|
||||
if (is_string()) {
|
||||
if (val.is_string())
|
||||
as_string_lval() += val.as_string();
|
||||
else
|
||||
as_string_lval() += val.to_string();
|
||||
return *this;
|
||||
}
|
||||
else if (is_type(SEQUENCE)) {
|
||||
if (val.is_type(SEQUENCE)) {
|
||||
else if (is_sequence()) {
|
||||
if (val.is_sequence()) {
|
||||
sequence_t& seq(as_sequence_lval());
|
||||
seq.insert(seq.end(), val.as_sequence().begin(),
|
||||
val.as_sequence().end());
|
||||
|
|
@ -331,7 +262,7 @@ value_t& value_t::operator+=(const value_t& val)
|
|||
return *this;
|
||||
}
|
||||
|
||||
if (val.is_type(XML_NODE)) // recurse
|
||||
if (val.is_xml_node()) // recurse
|
||||
return *this += val.as_xml_node()->to_value();
|
||||
|
||||
switch (type()) {
|
||||
|
|
@ -456,10 +387,10 @@ 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());
|
||||
|
||||
if (val.is_type(SEQUENCE)) {
|
||||
if (val.is_sequence()) {
|
||||
for (sequence_t::const_iterator i = val.as_sequence().begin();
|
||||
i != val.as_sequence().end();
|
||||
i++) {
|
||||
|
|
@ -475,7 +406,7 @@ value_t& value_t::operator-=(const value_t& val)
|
|||
return *this;
|
||||
}
|
||||
|
||||
if (val.is_type(XML_NODE)) // recurse
|
||||
if (val.is_xml_node()) // recurse
|
||||
return *this -= val.as_xml_node()->to_value();
|
||||
|
||||
switch (type()) {
|
||||
|
|
@ -619,7 +550,7 @@ 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;
|
||||
long count = val.to_long();
|
||||
for (long i = 0; i < count; i++)
|
||||
|
|
@ -627,7 +558,7 @@ value_t& value_t::operator*=(const value_t& val)
|
|||
set_string(temp);
|
||||
return *this;
|
||||
}
|
||||
else if (is_type(SEQUENCE)) {
|
||||
else if (is_sequence()) {
|
||||
value_t temp;
|
||||
long count = val.to_long();
|
||||
for (long i = 0; i < count; i++)
|
||||
|
|
@ -635,7 +566,7 @@ value_t& value_t::operator*=(const value_t& val)
|
|||
return *this = temp;
|
||||
}
|
||||
|
||||
if (val.is_type(XML_NODE)) // recurse
|
||||
if (val.is_xml_node()) // recurse
|
||||
return *this *= val.as_xml_node()->to_value();
|
||||
|
||||
switch (type()) {
|
||||
|
|
@ -712,7 +643,7 @@ 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();
|
||||
|
||||
switch (type()) {
|
||||
|
|
@ -791,21 +722,21 @@ value_t& value_t::operator/=(const value_t& val)
|
|||
|
||||
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();
|
||||
else if (is_type(XML_NODE))
|
||||
else if (is_xml_node())
|
||||
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();
|
||||
|
||||
switch (type()) {
|
||||
case BOOLEAN:
|
||||
if (val.is_type(BOOLEAN))
|
||||
if (val.is_boolean())
|
||||
return as_boolean() == val.as_boolean();
|
||||
break;
|
||||
|
||||
case DATETIME:
|
||||
if (val.is_type(DATETIME))
|
||||
if (val.is_datetime())
|
||||
return as_datetime() == val.as_datetime();
|
||||
break;
|
||||
|
||||
|
|
@ -870,20 +801,15 @@ bool value_t::operator==(const value_t& val) const
|
|||
break;
|
||||
|
||||
case STRING:
|
||||
if (val.is_type(STRING))
|
||||
if (val.is_string())
|
||||
return as_string() == val.as_string();
|
||||
break;
|
||||
|
||||
case SEQUENCE:
|
||||
if (val.is_type(SEQUENCE))
|
||||
if (val.is_sequence())
|
||||
return as_sequence() == val.as_sequence();
|
||||
break;
|
||||
|
||||
case POINTER:
|
||||
if (val.is_type(POINTER))
|
||||
return as_pointer() == val.as_pointer();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -895,16 +821,16 @@ 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();
|
||||
else if (is_type(XML_NODE))
|
||||
else if (is_xml_node())
|
||||
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();
|
||||
|
||||
switch (type()) {
|
||||
case DATETIME:
|
||||
if (val.is_type(DATETIME))
|
||||
if (val.is_datetime())
|
||||
return as_datetime() < val.as_datetime();
|
||||
break;
|
||||
|
||||
|
|
@ -931,15 +857,10 @@ bool value_t::operator<(const value_t& val) const
|
|||
break;
|
||||
|
||||
case STRING:
|
||||
if (val.is_type(STRING))
|
||||
if (val.is_string())
|
||||
return as_string() < val.as_string();
|
||||
break;
|
||||
|
||||
case POINTER:
|
||||
if (val.is_type(POINTER))
|
||||
return as_pointer() < val.as_pointer();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -952,16 +873,16 @@ bool value_t::operator<(const value_t& val) const
|
|||
#if 0
|
||||
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();
|
||||
else if (is_type(XML_NODE))
|
||||
else if (is_xml_node())
|
||||
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();
|
||||
|
||||
switch (type()) {
|
||||
case DATETIME:
|
||||
if (val.is_type(DATETIME))
|
||||
if (val.is_datetime())
|
||||
return as_datetime() > val.as_datetime();
|
||||
break;
|
||||
|
||||
|
|
@ -988,15 +909,10 @@ bool value_t::operator>(const value_t& val) const
|
|||
break;
|
||||
|
||||
case STRING:
|
||||
if (val.is_type(STRING))
|
||||
if (val.is_string())
|
||||
return as_string() > val.as_string();
|
||||
break;
|
||||
|
||||
case POINTER:
|
||||
if (val.is_type(POINTER))
|
||||
return as_pointer() > val.as_pointer();
|
||||
break;
|
||||
|
||||
default:
|
||||
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
|
||||
// impossible to turn an XML node into a sequence containing that
|
||||
// same XML node.
|
||||
if (is_type(XML_NODE)) {
|
||||
if (is_xml_node()) {
|
||||
*this = as_xml_node()->to_value().cast(cast_type);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1214,7 +1130,7 @@ bool value_t::is_realzero() const
|
|||
case XML_NODE:
|
||||
return as_xml_node() == NULL;
|
||||
case POINTER:
|
||||
return as_pointer() == NULL;
|
||||
return as_any_pointer().empty();
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
|
|
@ -1310,18 +1226,23 @@ value_t value_t::unround() const
|
|||
throw_(value_error, "Cannot un-round a boolean");
|
||||
case DATETIME:
|
||||
throw_(value_error, "Cannot un-round a date/time");
|
||||
|
||||
case INTEGER:
|
||||
return *this;
|
||||
|
||||
case AMOUNT:
|
||||
return as_amount().unround();
|
||||
case BALANCE:
|
||||
return as_balance().unround();
|
||||
case BALANCE_PAIR:
|
||||
return as_balance_pair().unround();
|
||||
|
||||
case STRING:
|
||||
throw_(value_error, "Cannot un-round a string");
|
||||
|
||||
case XML_NODE:
|
||||
return as_xml_node()->to_value().unround();
|
||||
|
||||
case POINTER:
|
||||
throw_(value_error, "Cannot un-round a pointer");
|
||||
case SEQUENCE:
|
||||
|
|
@ -1496,10 +1417,12 @@ value_t value_t::cost() const
|
|||
switch (type()) {
|
||||
case BOOLEAN:
|
||||
throw_(value_error, "Cannot find the cost of a boolean");
|
||||
|
||||
case INTEGER:
|
||||
case AMOUNT:
|
||||
case BALANCE:
|
||||
return *this;
|
||||
|
||||
case DATETIME:
|
||||
throw_(value_error, "Cannot find the cost of a date/time");
|
||||
|
||||
|
|
@ -1512,8 +1435,10 @@ value_t value_t::cost() const
|
|||
|
||||
case STRING:
|
||||
throw_(value_error, "Cannot find the cost of a string");
|
||||
|
||||
case XML_NODE:
|
||||
return as_xml_node()->to_value().cost();
|
||||
|
||||
case POINTER:
|
||||
throw_(value_error, "Cannot find the cost of a pointer");
|
||||
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);
|
||||
return add(amount, tcost);
|
||||
}
|
||||
else if ((is_type(AMOUNT) &&
|
||||
else if ((is_amount() &&
|
||||
as_amount().commodity() != amount.commodity()) ||
|
||||
(! is_type(AMOUNT) && amount.commodity())) {
|
||||
(! is_amount() && amount.commodity())) {
|
||||
in_place_cast(BALANCE);
|
||||
return add(amount, tcost);
|
||||
}
|
||||
else if (! is_type(AMOUNT)) {
|
||||
else if (! is_amount()) {
|
||||
in_place_cast(AMOUNT);
|
||||
}
|
||||
*this += amount;
|
||||
|
|
|
|||
61
src/value.h
61
src/value.h
|
|
@ -72,6 +72,7 @@ public:
|
|||
STRING,
|
||||
SEQUENCE,
|
||||
XML_NODE,
|
||||
CONST_XML_NODE,
|
||||
POINTER
|
||||
};
|
||||
|
||||
|
|
@ -216,6 +217,10 @@ public:
|
|||
TRACE_CTOR(value_t, "xml::node_t *");
|
||||
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) {
|
||||
TRACE_CTOR(value_t, "void *");
|
||||
set_pointer(item);
|
||||
|
|
@ -248,14 +253,16 @@ public:
|
|||
operator bool() 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 {
|
||||
return storage ? storage->type : VOID;
|
||||
}
|
||||
private:
|
||||
bool is_type(type_t _type) const {
|
||||
assert(_type >= VOID && _type <= POINTER);
|
||||
return type() == _type;
|
||||
}
|
||||
void set_type(type_t new_type) {
|
||||
|
|
@ -265,6 +272,7 @@ public:
|
|||
assert(is_type(new_type));
|
||||
}
|
||||
|
||||
public:
|
||||
bool is_boolean() const {
|
||||
return is_type(BOOLEAN);
|
||||
}
|
||||
|
|
@ -402,37 +410,63 @@ public:
|
|||
}
|
||||
|
||||
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() {
|
||||
assert(is_xml_node());
|
||||
assert(! is_type(CONST_XML_NODE));
|
||||
_dup();
|
||||
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_type(CONST_XML_NODE));
|
||||
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) {
|
||||
set_type(XML_NODE);
|
||||
*(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 {
|
||||
return is_type(POINTER);
|
||||
}
|
||||
void *& as_pointer_lval() {
|
||||
boost::any& as_any_pointer_lval() {
|
||||
assert(is_pointer());
|
||||
_dup();
|
||||
return *(void **) storage->data;
|
||||
return *(boost::any *) storage->data;
|
||||
}
|
||||
void * as_pointer() const {
|
||||
template <typename T>
|
||||
T *& as_pointer_lval() {
|
||||
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);
|
||||
*(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;
|
||||
|
|
@ -498,6 +532,7 @@ public:
|
|||
case SEQUENCE:
|
||||
return "a sequence";
|
||||
case XML_NODE:
|
||||
case CONST_XML_NODE:
|
||||
return "an xml node";
|
||||
case POINTER:
|
||||
return "a pointer";
|
||||
|
|
|
|||
214
src/xpath.cc
214
src/xpath.cc
|
|
@ -1044,39 +1044,6 @@ xpath_t::op_t::copy(ptr_op_t tleft, ptr_op_t tright) const
|
|||
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)
|
||||
{
|
||||
// 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();
|
||||
}
|
||||
|
||||
if (! (*i).is_type(value_t::POINTER))
|
||||
if (! (*i).is_pointer())
|
||||
*opp = wrap_value(*i);
|
||||
else
|
||||
#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)
|
||||
{
|
||||
if (val.is_type(value_t::SEQUENCE))
|
||||
if (val.is_sequence())
|
||||
std::for_each(val.as_sequence().begin(), val.as_sequence().end(),
|
||||
bind(&value_t::sequence_t::push_back, ref(result_seq), _1));
|
||||
else
|
||||
|
|
@ -1134,57 +1101,6 @@ xpath_t::op_t::compile(const node_t& context, scope_t * scope, bool resolve)
|
|||
case VALUE:
|
||||
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:
|
||||
if (optional<const string&> value = context.get_attr(as_long()))
|
||||
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_RFIND:
|
||||
case O_PRED: {
|
||||
xpath_t lexpr(left()->compile(context, scope, resolve));
|
||||
xpath_t rexpr(resolve ? right() : right()->compile(context, scope, false));
|
||||
case NODE_ID:
|
||||
case NODE_NAME:
|
||||
return wrap_value(path_t(ptr_op_t(this)).find_all(context, scope));
|
||||
|
||||
if (! lexpr.ptr->is_value() || ! resolve) {
|
||||
if (left() == lexpr.ptr)
|
||||
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;
|
||||
}
|
||||
|
||||
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 O_PRED:
|
||||
assert(false); // this should never occur by itself
|
||||
break;
|
||||
|
||||
case LAST:
|
||||
default:
|
||||
|
|
@ -1763,6 +1628,7 @@ bool xpath_t::op_t::print(std::ostream& out,
|
|||
break;
|
||||
|
||||
case value_t::XML_NODE:
|
||||
case value_t::CONST_XML_NODE:
|
||||
out << '<' << value << '>';
|
||||
break;
|
||||
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,
|
||||
const ptr_op_t& element,
|
||||
scope_t * scope,
|
||||
std::size_t index,
|
||||
std::size_t size,
|
||||
const visitor_t& func)
|
||||
template <typename NodeType, typename FuncType>
|
||||
void xpath_t::path_t::check_element(NodeType& start,
|
||||
const ptr_op_t& element,
|
||||
scope_t * scope,
|
||||
std::size_t index,
|
||||
std::size_t size,
|
||||
const FuncType& func)
|
||||
{
|
||||
if (element->kind > op_t::TERMINALS &&
|
||||
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)
|
||||
func(start);
|
||||
else
|
||||
walk_elements(start, element->right(), element->kind == op_t::O_RFIND,
|
||||
scope, func);
|
||||
walk_elements<NodeType, FuncType>
|
||||
(start, element->right(), element->kind == op_t::O_RFIND, scope, func);
|
||||
}
|
||||
|
||||
void xpath_t::path_t::walk_elements(node_t& start,
|
||||
const ptr_op_t& element,
|
||||
const bool recurse,
|
||||
scope_t * scope,
|
||||
const visitor_t& func)
|
||||
template <typename NodeType, typename FuncType>
|
||||
void xpath_t::path_t::walk_elements(NodeType& start,
|
||||
const ptr_op_t& element,
|
||||
const bool recurse,
|
||||
scope_t * scope,
|
||||
const FuncType& func)
|
||||
{
|
||||
ptr_op_t name(element->kind < op_t::TERMINALS ? element : element->left());
|
||||
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 ledger
|
||||
|
|
|
|||
90
src/xpath.h
90
src/xpath.h
|
|
@ -216,8 +216,10 @@ private:
|
|||
public:
|
||||
class path_t
|
||||
{
|
||||
typedef function<void (node_t&)> visitor_t;
|
||||
typedef function<bool (node_t&, scope_t *)> predicate_t;
|
||||
typedef function<void (node_t&)> visitor_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 {
|
||||
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;
|
||||
|
||||
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:
|
||||
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 result = value_t::sequence_t();
|
||||
visit(start, scope, value_node_appender_t(result.as_sequence_lval()));
|
||||
return result;
|
||||
}
|
||||
|
||||
void visit(node_t& start, scope_t * scope,
|
||||
const function<void (node_t&)>& func) {
|
||||
if (path_expr)
|
||||
walk_elements(start, path_expr, false, scope, func);
|
||||
value_t find_all(const node_t& start, scope_t * scope) {
|
||||
value_t result = value_t::sequence_t();
|
||||
visit(start, scope,
|
||||
const_value_node_appender_t(result.as_sequence_lval()));
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
void walk_elements(node_t& start,
|
||||
const ptr_op_t& element,
|
||||
const bool recurse,
|
||||
scope_t * scope,
|
||||
const visitor_t& func);
|
||||
|
||||
void check_element(node_t& start,
|
||||
const ptr_op_t& element,
|
||||
scope_t * scope,
|
||||
std::size_t index,
|
||||
std::size_t size,
|
||||
const visitor_t& func);
|
||||
void visit(node_t& start, scope_t * scope, const visitor_t& func) {
|
||||
if (path_expr)
|
||||
walk_elements<node_t, visitor_t>
|
||||
(start, path_expr, false, scope, func);
|
||||
}
|
||||
void visit(const node_t& start, scope_t * scope,
|
||||
const const_visitor_t& func) {
|
||||
if (path_expr)
|
||||
walk_elements<const node_t, const_visitor_t>
|
||||
(start, path_expr, false, scope, func);
|
||||
}
|
||||
};
|
||||
|
||||
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 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);
|
||||
|
||||
static ptr_op_t defer_sequence(value_t::sequence_t& result_seq);
|
||||
|
|
@ -539,16 +560,22 @@ public:
|
|||
unsigned long * end_pos = NULL) 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
|
||||
{
|
||||
ptr_op_t op;
|
||||
|
||||
public:
|
||||
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));
|
||||
return result.ptr->as_value().to_boolean();
|
||||
}
|
||||
|
|
@ -746,19 +773,12 @@ public:
|
|||
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
|
||||
|
||||
template <typename T>
|
||||
inline T * get_ptr(xml::xpath_t::scope_t * locals, unsigned int 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);
|
||||
return ptr;
|
||||
}
|
||||
|
|
@ -766,7 +786,7 @@ inline T * get_ptr(xml::xpath_t::scope_t * locals, unsigned int idx) {
|
|||
template <typename T>
|
||||
inline T * get_node_ptr(xml::xpath_t::scope_t * locals, unsigned int 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);
|
||||
return ptr;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue