diff options
-rw-r--r-- | src/journal.cc | 4 | ||||
-rw-r--r-- | src/main.cc | 14 | ||||
-rw-r--r-- | src/pyinterp.cc | 9 | ||||
-rw-r--r-- | src/system.hh | 1 | ||||
-rw-r--r-- | src/value.cc | 177 | ||||
-rw-r--r-- | src/value.h | 59 | ||||
-rw-r--r-- | src/xpath.cc | 214 | ||||
-rw-r--r-- | src/xpath.h | 90 |
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; } |