summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2007-05-16 05:38:32 +0000
committerJohn Wiegley <johnw@newartisans.com>2008-04-13 03:38:52 -0400
commit7c7e5c5e367778c6d54a1bb2be2db5c73db0492b (patch)
tree16ed5bde7719aa10b4d7cde25eaaf2ea64fa7f80
parent74ecceb2ba0cb1592f570bcb52619f882c15bd27 (diff)
downloadfork-ledger-7c7e5c5e367778c6d54a1bb2be2db5c73db0492b.tar.gz
fork-ledger-7c7e5c5e367778c6d54a1bb2be2db5c73db0492b.tar.bz2
fork-ledger-7c7e5c5e367778c6d54a1bb2be2db5c73db0492b.zip
Now using xpath_t::path_t to select nodes.
-rw-r--r--src/journal.cc4
-rw-r--r--src/main.cc14
-rw-r--r--src/pyinterp.cc9
-rw-r--r--src/system.hh1
-rw-r--r--src/value.cc177
-rw-r--r--src/value.h59
-rw-r--r--src/xpath.cc214
-rw-r--r--src/xpath.h90
8 files changed, 232 insertions, 336 deletions
diff --git a/src/journal.cc b/src/journal.cc
index 2f501aff..295db452 100644
--- a/src/journal.cc
+++ b/src/journal.cc
@@ -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);
diff --git a/src/main.cc b/src/main.cc
index 4fe41be2..db34f183 100644
--- a/src/main.cc
+++ b/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;
}
diff --git a/src/pyinterp.cc b/src/pyinterp.cc
index cd0576bf..e96646dc 100644
--- a/src/pyinterp.cc
+++ b/src/pyinterp.cc
@@ -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
diff --git a/src/system.hh b/src/system.hh
index a345bc9d..96c6575c 100644
--- a/src/system.hh
+++ b/src/system.hh
@@ -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>
diff --git a/src/value.cc b/src/value.cc
index ecd95705..dd2b3a11 100644
--- a/src/value.cc
+++ b/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;
diff --git a/src/value.h b/src/value.h
index fbe62dbf..f8674864 100644
--- a/src/value.h
+++ b/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 {
- return storage ? storage->type : VOID;
+ type_t result = storage ? storage->type : VOID;
+ assert(result >= VOID && result <= POINTER);
+ return result;
}
+
+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 *(boost::any *) storage->data;
+ }
+ template <typename T>
+ T *& as_pointer_lval() {
assert(is_pointer());
_dup();
- return *(void **) storage->data;
+ return any_cast<T *>(*(boost::any *) storage->data);
}
- void * as_pointer() const {
+ boost::any as_any_pointer() const {
assert(is_pointer());
- return *(void **) storage->data;
+ 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);
+ new((boost::any *) storage->data) boost::any(val);
}
- void set_pointer(void * val) {
+ template <typename T>
+ void set_pointer(T * val) {
set_type(POINTER);
- *(void **) storage->data = val;
+ 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";
diff --git a/src/xpath.cc b/src/xpath.cc
index b96df49d..3799e260 100644
--- a/src/xpath.cc
+++ b/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));
-
- 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;
- }
+ case NODE_ID:
+ case NODE_NAME:
+ return wrap_value(path_t(ptr_op_t(this)).find_all(context, scope));
- 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
diff --git a/src/xpath.h b/src/xpath.h
index 1838a6e2..7b358976 100644
--- a/src/xpath.h
+++ b/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;
}
+ 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;
+ }
- void visit(node_t& start, scope_t * scope,
- const function<void (node_t&)>& func) {
+ void visit(node_t& start, scope_t * scope, const visitor_t& func) {
if (path_expr)
- walk_elements(start, path_expr, false, scope, func);
- }
-
- 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);
+ 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;
}