Completely revised the way XPath expressions are calculated.

This commit is contained in:
John Wiegley 2007-05-19 02:58:38 +00:00
parent 2d8512af88
commit b6ab7deb63
16 changed files with 1033 additions and 1340 deletions

View file

@ -126,13 +126,13 @@ commodity_t::operator bool() const
annotated_commodity_t& commodity_t::as_annotated()
{
assert(annotated);
return *polymorphic_downcast<annotated_commodity_t *>(this);
return downcast<annotated_commodity_t>(*this);
}
const annotated_commodity_t& commodity_t::as_annotated() const
{
assert(annotated);
return *polymorphic_downcast<const annotated_commodity_t *>(this);
return downcast<const annotated_commodity_t>(*this);
}
bool commodity_t::symbol_needs_quotes(const string& symbol)

View file

@ -136,7 +136,7 @@ static int read_and_report(ledger::report_t& report, int argc, char * argv[],
else
#endif
if (verb == "xml")
command = xml_command();
command = bind(xml_command, _1);
else if (verb == "expr")
;
else if (verb == "xpath")
@ -145,17 +145,19 @@ static int read_and_report(ledger::report_t& report, int argc, char * argv[],
xml::xpath_t expr(*arg);
xml::document_t temp(xml::LEDGER_NODE);
xml::xpath_t::document_scope_t doc_scope(report, temp);
IF_INFO() {
std::cout << "Value expression tree:" << std::endl;
expr.dump(std::cout);
std::cout << std::endl;
std::cout << "Value expression parsed was:" << std::endl;
expr.print(std::cout, temp);
expr.print(std::cout, doc_scope);
std::cout << std::endl << std::endl;
std::cout << "Result of calculation: ";
}
std::cout << expr.calc(temp, report).strip_annotations() << std::endl;
std::cout << expr.calc(doc_scope).strip_annotations() << std::endl;
return 0;
}
@ -242,8 +244,12 @@ static int read_and_report(ledger::report_t& report, int argc, char * argv[],
}
#endif
report.define("ostream", value_t(out));
// Are we handling the expr commands? Do so now.
xml::xpath_t::document_scope_t doc_scope(report, xml_document);
if (verb == "expr") {
xml::xpath_t expr(*arg);
@ -252,12 +258,12 @@ static int read_and_report(ledger::report_t& report, int argc, char * argv[],
expr.dump(*out);
*out << std::endl;
*out << "Value expression parsed was:" << std::endl;
expr.print(*out, xml_document);
expr.print(*out, doc_scope);
*out << std::endl << std::endl;
*out << "Result of calculation: ";
}
*out << expr.calc(xml_document, report).strip_annotations() << std::endl;
*out << expr.calc(doc_scope).strip_annotations() << std::endl;
return 0;
}
@ -265,9 +271,10 @@ static int read_and_report(ledger::report_t& report, int argc, char * argv[],
std::cout << "XPath parsed:" << std::endl;
xml::xpath_t xpath(*arg);
xpath.print(*out, xml_document);
xpath.print(*out, doc_scope);
*out << std::endl;
#if 0
foreach (const value_t& value, xpath.find_all(xml_document, report)) {
if (value.is_xml_node()) {
value.as_xml_node()->print(std::cout);
@ -276,31 +283,27 @@ static int read_and_report(ledger::report_t& report, int argc, char * argv[],
}
std::cout << std::endl;
}
#endif
return 0;
}
// Apply transforms to the hierarchical document structure
INFO_START(transforms, "Applied transforms");
report.apply_transforms(xml_document);
report.apply_transforms(doc_scope);
INFO_FINISH(transforms);
// Create an argument scope containing the report command's
// arguments, and then invoke the command.
xml::xpath_t::scope_t locals(report, xml::xpath_t::scope_t::ARGUMENT);
xml::xpath_t::call_scope_t command_args(doc_scope);
locals.args.push_back(out);
locals.args.push_back(&xml_document);
value_t::sequence_t args_list;
foreach (string& i, args)
args_list.push_back(value_t(i, true));
locals.args.push_back(args_list);
for (strings_list::iterator i = arg; i != args.end(); i++)
command_args.push_back(value_t(*i, true));
INFO_START(command, "Did user command '" << verb << "'");
command(locals);
command(command_args);
INFO_FINISH(command);

View file

@ -40,6 +40,15 @@ const char * node_t::name() const
return *document().lookup_name(name_id());
}
optional<const string&> node_t::get_attr(const string& _name) const
{
optional<nameid_t> name_id = document().lookup_name_id(_name);
if (name_id)
return get_attr(*name_id);
else
return none;
}
void output_xml_string(std::ostream& out, const string& str)
{
for (const char * s = str.c_str(); *s; s++) {

View file

@ -87,12 +87,12 @@ public:
parent_node_t& as_parent_node() {
if (! is_parent_node())
throw_(std::logic_error, "Request to cast leaf node to a parent node");
return *polymorphic_downcast<parent_node_t *>(this);
return downcast<parent_node_t>(*this);
}
const parent_node_t& as_parent_node() const {
if (! is_parent_node())
throw_(std::logic_error, "Request to cast leaf node to a parent node");
return *polymorphic_downcast<const parent_node_t *>(this);
return downcast<const parent_node_t>(*this);
}
virtual value_t to_value() const = 0;
@ -116,6 +116,7 @@ public:
attributes = attributes_t();
attributes->push_back(attr_pair(_name_id, value));
}
optional<const string&> get_attr(const string& _name) const;
optional<const string&> get_attr(const nameid_t _name_id) const {
if (attributes) {
typedef attributes_t::nth_index<1>::type attributes_by_name;

View file

@ -82,11 +82,11 @@ namespace {
#if 0
try {
#endif
xml::xpath_t::scope_t arguments(scope, xml::xpath_t::scope_t::ARGUMENT);
xml::xpath_t::call_scope_t args(scope);
if (arg)
arguments.args.push_back(value_t(arg, true));
args.push_back(value_t(arg, true));
opt(arguments);
opt(args);
#if 0
}
catch (error * err) {

View file

@ -87,7 +87,7 @@ struct python_run
};
python_interpreter_t::python_interpreter_t(xml::xpath_t::scope_t& parent)
: xml::xpath_t::scope_t(parent),
: xml::xpath_t::symbol_scope_t(parent),
mmodule(borrowed(PyImport_AddModule("__main__"))),
nspace(handle<>(borrowed(PyModule_GetDict(mmodule.get()))))
{
@ -176,16 +176,20 @@ object python_interpreter_t::eval(const string& str, py_eval_mode_t mode)
return object();
}
value_t python_interpreter_t::functor_t::operator()(xml::xpath_t::scope_t& locals)
value_t python_interpreter_t::functor_t::operator()
(xml::xpath_t::call_scope_t& args)
{
try {
if (! PyCallable_Check(func.ptr())) {
return extract<value_t>(func.ptr());
} else {
if (locals.args.size() > 0) {
if (args.size() > 0) {
list arglist;
foreach (const value_t& value, locals.args)
arglist.append(value);
if (args.value().is_sequence())
foreach (const value_t& value, args.value().as_sequence())
arglist.append(value);
else
arglist.append(args.value());
if (PyObject * val =
PyObject_CallObject(func.ptr(),
@ -215,11 +219,11 @@ value_t python_interpreter_t::functor_t::operator()(xml::xpath_t::scope_t& local
}
value_t python_interpreter_t::lambda_t::operator()
(xml::xpath_t::scope_t& locals)
(xml::xpath_t::call_scope_t& args)
{
try {
assert(locals.args.size() == 1);
value_t item = locals.args[0];
assert(args.size() == 1);
value_t item = args[0];
assert(item.is_xml_node());
return call<value_t>(func.ptr(), item.as_xml_node());
}

View file

@ -29,8 +29,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _PY_EVAL_H
#define _PY_EVAL_H
#ifndef _PYINTERP_H
#define _PYINTERP_H
#include "xpath.h"
@ -39,7 +39,7 @@
namespace ledger {
class python_interpreter_t : public xml::xpath_t::scope_t
class python_interpreter_t : public xml::xpath_t::symbol_scope_t
{
boost::python::handle<> mmodule;
@ -76,28 +76,23 @@ class python_interpreter_t : public xml::xpath_t::scope_t
public:
functor_t(const string& name, boost::python::object _func) : func(_func) {}
virtual ~functor_t() {}
virtual value_t operator()(xml::xpath_t::scope_t& locals);
virtual value_t operator()(xml::xpath_t::call_scope_t& args);
};
virtual void define(const string& name, xml::xpath_t::ptr_op_t def) {
// Pass any definitions up to our parent
parent->define(name, def);
}
virtual xml::xpath_t::ptr_op_t lookup(const string& name) {
if (boost::python::object func = eval(name))
return xml::xpath_t::wrap_functor(functor_t(name, func));
return WRAP_FUNCTOR(functor_t(name, func));
else
return parent ? parent->lookup(name) : NULL;
return xml::xpath_t::symbol_scope_t::lookup(name);
}
class lambda_t : public functor_t {
public:
lambda_t(boost::python::object code) : functor_t("<lambda>", code) {}
virtual value_t operator()(xml::xpath_t::scope_t& locals);
virtual value_t operator()(xml::xpath_t::call_scope_t& args);
};
};
} // namespace ledger
#endif // _PY_EVAL_H
#endif // _PYINTERP_H

View file

@ -38,41 +38,46 @@ report_t::~report_t()
TRACE_DTOR(report_t);
}
void report_t::apply_transforms(xml::document_t& document)
void report_t::apply_transforms(xml::xpath_t::scope_t& scope)
{
foreach (transform_t& transform, transforms)
transform.execute(document);
typedef tuple<shared_ptr<transform_t>, value_t> transform_details_tuple;
foreach (transform_details_tuple& transform_details, transforms) {
xml::xpath_t::call_scope_t call_args(scope);
call_args.set_args(transform_details.get<1>());
(*transform_details.get<0>())(call_args);
}
}
value_t report_t::abbrev(xml::xpath_t::scope_t& locals)
value_t report_t::abbrev(xml::xpath_t::call_scope_t& args)
{
if (locals.args.size() < 2)
if (args.size() < 2)
throw_(std::logic_error, "usage: abbrev(STRING, WIDTH [, STYLE, ABBREV_LEN])");
string str = locals.args[0].as_string();
long wid = locals.args[1];
string str = args[0].as_string();
long wid = args[1];
elision_style_t style = session.elision_style;
if (locals.args.size() == 3)
style = (elision_style_t)locals.args[2].as_long();
if (args.size() == 3)
style = (elision_style_t)args[2].as_long();
long abbrev_len = session.abbrev_length;
if (locals.args.size() == 4)
abbrev_len = locals.args[3].as_long();
if (args.size() == 4)
abbrev_len = args[3].as_long();
return value_t(abbreviate(str, wid, style, true, (int)abbrev_len), true);
}
value_t report_t::ftime(xml::xpath_t::scope_t& locals)
value_t report_t::ftime(xml::xpath_t::call_scope_t& args)
{
if (locals.args.size() < 1)
if (args.size() < 1)
throw_(std::logic_error, "usage: ftime(DATE [, DATE_FORMAT])");
moment_t date = locals.args[0].as_datetime();
moment_t date = args[0].as_datetime();
string date_format;
if (locals.args.size() == 2)
date_format = locals.args[1].as_string();
if (args.size() == 2)
date_format = args[1].as_string();
#if 0
// jww (2007-04-18): Need to setup an output facet here
else
@ -84,25 +89,27 @@ value_t report_t::ftime(xml::xpath_t::scope_t& locals)
#endif
}
#if 0
optional<value_t>
report_t::resolve(const string& name, xml::xpath_t::scope_t& locals)
report_t::resolve(const string& name, xml::xpath_t::call_scope_t& args)
{
const char * p = name.c_str();
switch (*p) {
case 'a':
if (name == "abbrev") {
return abbrev(locals);
return abbrev(args);
}
break;
case 'f':
if (name == "ftime") {
return ftime(locals);
return ftime(args);
}
break;
}
return xml::xpath_t::scope_t::resolve(name, locals);
return xml::xpath_t::scope_t::resolve(name, args);
}
#endif
xml::xpath_t::ptr_op_t report_t::lookup(const string& name)
{
@ -210,7 +217,7 @@ xml::xpath_t::ptr_op_t report_t::lookup(const string& name)
break;
}
return xml::xpath_t::scope_t::lookup(name);
return xml::xpath_t::symbol_scope_t::lookup(name);
}
} // namespace ledger

View file

@ -39,9 +39,9 @@ namespace ledger {
typedef std::list<string> strings_list;
class report_t : public xml::xpath_t::scope_t
class report_t : public xml::xpath_t::symbol_scope_t
{
public:
public:
optional<path> output_file;
string format_string;
string amount_expr;
@ -59,10 +59,10 @@ class report_t : public xml::xpath_t::scope_t
session_t& session;
transform_t * last_transform;
ptr_list<transform_t> transforms;
std::list<tuple<shared_ptr<transform_t>, value_t> > transforms;
explicit report_t(session_t& _session)
: xml::xpath_t::scope_t(_session),
: xml::xpath_t::symbol_scope_t(downcast<xml::xpath_t::scope_t>(_session)),
show_totals(false),
raw_mode(false),
session(_session),
@ -76,14 +76,14 @@ class report_t : public xml::xpath_t::scope_t
virtual ~report_t();
void apply_transforms(xml::document_t& document);
void apply_transforms(xml::xpath_t::scope_t& scope);
//
// Utility functions for value expressions
//
value_t ftime(xml::xpath_t::scope_t& locals);
value_t abbrev(xml::xpath_t::scope_t& locals);
value_t ftime(xml::xpath_t::call_scope_t& args);
value_t abbrev(xml::xpath_t::call_scope_t& args);
//
// Config options
@ -94,36 +94,36 @@ class report_t : public xml::xpath_t::scope_t
xml::xpath_t(expr).compile((xml::document_t *)NULL, this);
#endif
}
value_t option_eval(xml::xpath_t::scope_t& locals) {
eval(locals.args[0].as_string());
value_t option_eval(xml::xpath_t::call_scope_t& args) {
eval(args[0].as_string());
return NULL_VALUE;
}
value_t option_amount(xml::xpath_t::scope_t& locals) {
eval(string("t=") + locals.args[0].as_string());
value_t option_amount(xml::xpath_t::call_scope_t& args) {
eval(string("t=") + args[0].as_string());
return NULL_VALUE;
}
value_t option_total(xml::xpath_t::scope_t& locals) {
eval(string("T()=") + locals.args[0].as_string());
value_t option_total(xml::xpath_t::call_scope_t& args) {
eval(string("T()=") + args[0].as_string());
return NULL_VALUE;
}
value_t option_format(xml::xpath_t::scope_t& locals) {
format_string = locals.args[0].as_string();
value_t option_format(xml::xpath_t::call_scope_t& args) {
format_string = args[0].as_string();
return NULL_VALUE;
}
value_t option_raw(xml::xpath_t::scope_t& locals) {
value_t option_raw(xml::xpath_t::call_scope_t& args) {
raw_mode = true;
return NULL_VALUE;
}
value_t option_foo(xml::xpath_t::scope_t& locals) {
value_t option_foo(xml::xpath_t::call_scope_t& args) {
std::cout << "This is foo" << std::endl;
return NULL_VALUE;
}
value_t option_bar(xml::xpath_t::scope_t& locals) {
std::cout << "This is bar: " << locals.args[0] << std::endl;
value_t option_bar(xml::xpath_t::call_scope_t& args) {
std::cout << "This is bar: " << args[0] << std::endl;
return NULL_VALUE;
}
@ -132,44 +132,44 @@ class report_t : public xml::xpath_t::scope_t
//
#if 0
value_t option_select(xml::xpath_t::scope_t& locals) {
transforms.push_back(new select_transform(locals.args[0].as_string()));
value_t option_select(xml::xpath_t::call_scope_t& args) {
transforms.push_back(new select_transform(args[0].as_string()));
return NULL_VALUE;
}
value_t option_limit(xml::xpath_t::scope_t& locals) {
value_t option_limit(xml::xpath_t::call_scope_t& args) {
string expr = (string("//xact[") +
locals.args[0].as_string() + "]");
args[0].as_string() + "]");
transforms.push_back(new select_transform(expr));
return NULL_VALUE;
}
value_t option_remove(xml::xpath_t::scope_t& locals) {
transforms.push_back(new remove_transform(locals.args[0].as_string()));
value_t option_remove(xml::xpath_t::call_scope_t& args) {
transforms.push_back(new remove_transform(args[0].as_string()));
return NULL_VALUE;
}
value_t option_accounts(xml::xpath_t::scope_t& locals) {
value_t option_accounts(xml::xpath_t::call_scope_t& args) {
transforms.push_back(new accounts_transform);
return NULL_VALUE;
}
value_t option_compact(xml::xpath_t::scope_t& locals) {
value_t option_compact(xml::xpath_t::call_scope_t& args) {
transforms.push_back(new compact_transform);
return NULL_VALUE;
}
value_t option_clean(xml::xpath_t::scope_t& locals) {
value_t option_clean(xml::xpath_t::call_scope_t& args) {
transforms.push_back(new clean_transform);
return NULL_VALUE;
}
value_t option_entries(xml::xpath_t::scope_t& locals) {
value_t option_entries(xml::xpath_t::call_scope_t& args) {
transforms.push_back(new entries_transform);
return NULL_VALUE;
}
value_t option_split(xml::xpath_t::scope_t& locals) {
value_t option_split(xml::xpath_t::call_scope_t& args) {
transforms.push_back(new split_transform);
return NULL_VALUE;
}
value_t option_merge(xml::xpath_t::scope_t& locals) {
value_t option_merge(xml::xpath_t::call_scope_t& args) {
transforms.push_back(new merge_transform);
return NULL_VALUE;
}
@ -179,8 +179,6 @@ class report_t : public xml::xpath_t::scope_t
// Scope members
//
virtual optional<value_t> resolve(const string& name,
xml::xpath_t::scope_t& locals);
virtual xml::xpath_t::ptr_op_t lookup(const string& name);
};

View file

@ -68,6 +68,56 @@ void release_session_context()
#endif
}
session_t::session_t()
: symbol_scope_t(),
register_format
("%((//entry)%{date} %-.20{payee}"
"%((./xact)%32|%-22{abbrev(account, 22)} %12.67t %12.80T\n))"),
wide_register_format
("%D %-.35P %-.38A %22.108t %!22.132T\n%/"
"%48|%-.38A %22.108t %!22.132T\n"),
print_format
#if 1
("%(/%(/%{date} %-.20{payee}\n%(: %-34{account} %12t\n)\n))"),
#else
("\n%d %Y%C%P\n %-34W %12o%n\n%/ %-34W %12o%n\n"),
#endif
balance_format
("%(/%(//%20t %{\" \" * rdepth}%{rname}\n))--------------------\n%20t\n"),
equity_format
("%((/)%{ftime(now, date_format)} %-.20{\"Opening Balance\"}\n%((.//account[value != 0]) %-34{fullname} %12{value}\n)\n)"),
plot_amount_format
("%D %(@S(@t))\n"),
plot_total_format
("%D %(@S(@T))\n"),
write_hdr_format
("%d %Y%C%P\n"),
write_xact_format
(" %-34W %12o%n\n"),
prices_format
("%[%Y/%m/%d %H:%M:%S %Z] %-10A %12t %12T\n"),
pricesdb_format
("P %[%Y/%m/%d %H:%M:%S] %A %t\n"),
pricing_leeway(24 * 3600),
download_quotes(false),
use_cache(false),
cache_dirty(false),
now(now),
elision_style(ABBREVIATE),
abbrev_length(2),
ansi_codes(false),
ansi_invert(false)
{
TRACE_CTOR(session_t, "xml::xpath_t::scope_t&");
}
std::size_t session_t::read_journal(std::istream& in,
const path& pathname,
xml::builder_t& builder)
@ -173,6 +223,7 @@ std::size_t session_t::read_data(xml::builder_t& builder,
return entry_count;
}
#if 0
optional<value_t>
session_t::resolve(const string& name, xml::xpath_t::scope_t& locals)
{
@ -203,6 +254,7 @@ session_t::resolve(const string& name, xml::xpath_t::scope_t& locals)
}
return xml::xpath_t::scope_t::resolve(name, locals);
}
#endif
xml::xpath_t::ptr_op_t session_t::lookup(const string& name)
{
@ -239,7 +291,7 @@ xml::xpath_t::ptr_op_t session_t::lookup(const string& name)
break;
}
return xml::xpath_t::scope_t::lookup(name);
return xml::xpath_t::symbol_scope_t::lookup(name);
}
// jww (2007-04-26): All of Ledger should be accessed through a

View file

@ -39,7 +39,7 @@
namespace ledger {
class session_t : public xml::xpath_t::scope_t
class session_t : public xml::xpath_t::symbol_scope_t
{
public:
static session_t * current;
@ -79,53 +79,7 @@ class session_t : public xml::xpath_t::scope_t
ptr_list<journal_t> journals;
ptr_list<parser_t> parsers;
session_t() :
register_format
("%((//entry)%{date} %-.20{payee}"
"%((./xact)%32|%-22{abbrev(account, 22)} %12.67t %12.80T\n))"),
wide_register_format
("%D %-.35P %-.38A %22.108t %!22.132T\n%/"
"%48|%-.38A %22.108t %!22.132T\n"),
print_format
#if 1
("%(/%(/%{date} %-.20{payee}\n%(: %-34{account} %12t\n)\n))"),
#else
("\n%d %Y%C%P\n %-34W %12o%n\n%/ %-34W %12o%n\n"),
#endif
balance_format
("%(/%(//%20t %{\" \" * rdepth}%{rname}\n))--------------------\n%20t\n"),
equity_format
("%((/)%{ftime(now, date_format)} %-.20{\"Opening Balance\"}\n%((.//account[value != 0]) %-34{fullname} %12{value}\n)\n)"),
plot_amount_format
("%D %(@S(@t))\n"),
plot_total_format
("%D %(@S(@T))\n"),
write_hdr_format
("%d %Y%C%P\n"),
write_xact_format
(" %-34W %12o%n\n"),
prices_format
("%[%Y/%m/%d %H:%M:%S %Z] %-10A %12t %12T\n"),
pricesdb_format
("P %[%Y/%m/%d %H:%M:%S] %A %t\n"),
pricing_leeway(24 * 3600),
download_quotes(false),
use_cache(false),
cache_dirty(false),
now(now),
elision_style(ABBREVIATE),
abbrev_length(2),
ansi_codes(false),
ansi_invert(false) {
TRACE_CTOR(session_t, "xml::xpath_t::scope_t&");
}
session_t();
virtual ~session_t() {
TRACE_DTOR(session_t);
}
@ -178,8 +132,6 @@ class session_t : public xml::xpath_t::scope_t
// Scope members
//
virtual optional<value_t> resolve(const string& name,
xml::xpath_t::scope_t& locals = NULL);
virtual xml::xpath_t::ptr_op_t lookup(const string& name);
//
@ -208,19 +160,19 @@ class session_t : public xml::xpath_t::scope_t
// Option handlers
//
value_t option_file_(xml::xpath_t::scope_t& locals) {
assert(locals.args.size() == 1);
data_file = locals.args[0].as_string();
value_t option_file_(xml::xpath_t::call_scope_t& args) {
assert(args.size() == 1);
data_file = args[0].as_string();
return NULL_VALUE;
}
#if 0
#if defined(USE_BOOST_PYTHON)
value_t option_import_(xml::xpath_t::scope_t& locals) {
value_t option_import_(xml::xpath_t::call_scope_t& args) {
python_import(optarg);
return NULL_VALUE;
}
value_t option_import_stdin(xml::xpath_t::scope_t& locals) {
value_t option_import_stdin(xml::xpath_t::call_scope_t& args) {
python_eval(std::cin, PY_EVAL_MULTI);
return NULL_VALUE;
}

View file

@ -39,38 +39,38 @@ namespace ledger {
class transform_t {
public:
virtual ~transform_t() {}
virtual void execute(xml::document_t& document) = 0;
virtual value_t operator()(xml::xpath_t::scope_t& args) = 0;
};
class check_transform : public transform_t {
// --check checks the validity of the item list.
public:
virtual void execute(xml::document_t& document);
virtual value_t operator()(xml::xpath_t::call_scope_t& args);
};
class accounts_transform : public transform_t {
// --accounts transforms the report tree into an account-wise view.
public:
virtual void execute(xml::document_t& document);
virtual value_t operator()(xml::xpath_t::call_scope_t& args);
};
class compact_transform : public transform_t {
// --compact compacts an account tree to remove accounts with only
// one child account.
public:
virtual void execute(xml::document_t& document);
virtual value_t operator()(xml::xpath_t::call_scope_t& args);
};
class clean_transform : public transform_t {
// --clean clears out entries and accounts that have no contents.
public:
virtual void execute(xml::document_t& document);
virtual value_t operator()(xml::xpath_t::call_scope_t& args);
};
class entries_transform : public transform_t {
// --entries transforms the report tree into an entries-wise view.
public:
virtual void execute(xml::document_t& document);
virtual value_t operator()(xml::xpath_t::call_scope_t& args);
};
class optimize_transform : public transform_t {
@ -79,7 +79,7 @@ class optimize_transform : public transform_t {
// commodity (one the negative of the other), the amount of the
// second transaction will be nulled out.
public:
virtual void execute(xml::document_t& document);
virtual value_t operator()(xml::xpath_t::call_scope_t& args);
};
class split_transform : public transform_t {
@ -89,7 +89,7 @@ class split_transform : public transform_t {
// useful before sorting, for exampel, in order to sort by
// transaction instead of by entry.
public:
virtual void execute(xml::document_t& document);
virtual value_t operator()(xml::xpath_t::call_scope_t& args);
};
class merge_transform : public transform_t {
@ -97,7 +97,7 @@ class merge_transform : public transform_t {
// which share the same entry will be merged into a group of
// transactions under one reported entry.
public:
virtual void execute(xml::document_t& document);
virtual value_t operator()(xml::xpath_t::call_scope_t& args);
};
class combine_transform : public transform_t {
@ -107,14 +107,14 @@ class combine_transform : public transform_t {
// will show the terminating date or a label that is characteristic
// of the set).
public:
virtual void execute(xml::document_t& document);
virtual value_t operator()(xml::xpath_t::call_scope_t& args);
};
class group_transform : public transform_t {
// --group groups all transactions that affect the same account
// within an entry, so that they appear as a single transaction.
public:
virtual void execute(xml::document_t& document);
virtual value_t operator()(xml::xpath_t::call_scope_t& args);
};
class collapse_transform : public transform_t {
@ -123,7 +123,7 @@ class collapse_transform : public transform_t {
// fictitous account "<total>" is used to represent the final sum,
// if multiple accounts are involved.
public:
virtual void execute(xml::document_t& document);
virtual value_t operator()(xml::xpath_t::call_scope_t& args);
};
class subtotal_transform : public transform_t {
@ -131,7 +131,7 @@ class subtotal_transform : public transform_t {
// one giant entry. When used in conjunction with --group, the
// affect is very similar to a regular balance report.
public:
virtual void execute(xml::document_t& document);
virtual value_t operator()(xml::xpath_t::call_scope_t& args);
};
#if 0
@ -146,7 +146,7 @@ class select_transform : public transform_t
}
virtual ~select_transform() {}
virtual void execute(xml::document_t& document);
virtual value_t operator()(xml::xpath_t::call_scope_t& args);
};
class remove_transform : public select_transform
@ -155,7 +155,7 @@ class remove_transform : public select_transform
remove_transform(const string& selection_path)
: select_transform(selection_path) {}
virtual void execute(xml::document_t& document);
virtual value_t operator()(xml::xpath_t::call_scope_t& args);
};
#endif

View file

@ -521,6 +521,11 @@ inline void throw_unexpected_error(char, char) {
namespace ledger {
template <typename T, typename U>
inline T& downcast(U& object) {
return *polymorphic_downcast<T *>(&object);
}
path resolve_path(const path& pathname);
#ifdef HAVE_REALPATH

View file

@ -61,6 +61,10 @@ class value_t
public:
typedef std::vector<value_t> sequence_t;
typedef sequence_t::iterator iterator;
typedef sequence_t::const_iterator const_iterator;
typedef sequence_t::difference_type difference_type;
enum type_t {
VOID,
BOOLEAN,
@ -72,7 +76,6 @@ public:
STRING,
SEQUENCE,
XML_NODE,
CONST_XML_NODE,
POINTER
};
@ -217,12 +220,9 @@ 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 *");
template <typename T>
value_t(T * item) {
TRACE_CTOR(value_t, "T *");
set_pointer(item);
}
~value_t() {
@ -254,11 +254,22 @@ public:
else
storage->destroy();
}
void _reset() {
if (storage) {
storage->destroy();
storage = intrusive_ptr<storage_t>();
}
}
operator bool() const;
bool is_null() const {
return ! storage || is_type(VOID);
if (! storage) {
return true;
} else {
assert(! is_type(VOID));
return false;
}
}
type_t type() const {
type_t result = storage ? storage->type : VOID;
@ -272,9 +283,14 @@ private:
}
void set_type(type_t new_type) {
assert(new_type >= VOID && new_type <= POINTER);
_clear();
storage->type = new_type;
assert(is_type(new_type));
if (new_type == VOID) {
_reset();
assert(is_null());
} else {
_clear();
storage->type = new_type;
assert(is_type(new_type));
}
}
public:
@ -415,36 +431,21 @@ public:
}
bool is_xml_node() const {
return is_type(XML_NODE) || is_type(CONST_XML_NODE);
return is_type(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_mutable() {
xml::node_t * as_xml_node() const {
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;
}
template <typename T>
T * as_xml_node() const {
assert(is_xml_node());
return *(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);
@ -460,6 +461,12 @@ public:
_dup();
return any_cast<T *>(*(boost::any *) storage->data);
}
template <typename T>
T& as_ref_lval() {
assert(is_pointer());
_dup();
return *any_cast<T *>(*(boost::any *) storage->data);
}
boost::any as_any_pointer() const {
assert(is_pointer());
return *(boost::any *) storage->data;
@ -469,6 +476,11 @@ public:
assert(is_pointer());
return any_cast<T *>(*(boost::any *) storage->data);
}
template <typename T>
T& as_ref() 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);
@ -496,18 +508,66 @@ public:
void in_place_simplify();
value_t& operator[](const int index) {
return as_sequence_lval()[index];
assert(! is_null());
if (is_sequence())
return as_sequence_lval()[index];
else if (index == 0)
return *this;
assert(false);
static value_t null;
return null;
}
const value_t& operator[](const int index) const {
return as_sequence()[index];
assert(! is_null());
if (is_sequence())
return as_sequence()[index];
else if (index == 0)
return *this;
assert(false);
static value_t null;
return null;
}
void push_back(const value_t& val) {
return as_sequence_lval().push_back(val);
if (is_null()) {
*this = val;
} else {
if (! is_sequence())
in_place_cast(SEQUENCE);
if (! val.is_sequence())
as_sequence_lval().push_back(val);
else
std::copy(val.as_sequence().begin(), val.as_sequence().end(),
as_sequence_lval().end());
}
}
void pop_back() {
assert(! is_null());
if (! is_sequence()) {
_reset();
} else {
as_sequence_lval().pop_back();
std::size_t new_size = as_sequence().size();
if (new_size == 0)
_reset();
else if (new_size == 1)
*this = as_sequence().front();
}
}
const std::size_t size() const {
return as_sequence().size();
if (is_null())
return 0;
else if (is_sequence())
return as_sequence().size();
else
return 1;
}
value_t& operator+=(const value_t& val);
@ -542,7 +602,6 @@ public:
case SEQUENCE:
return "a sequence";
case XML_NODE:
case CONST_XML_NODE:
return "an xml node";
case POINTER:
return "a pointer";
@ -602,19 +661,12 @@ public:
friend std::ostream& operator<<(std::ostream& out, const value_t& val);
};
template <>
inline const xml::node_t * value_t::as_xml_node() const {
assert(is_xml_node());
assert(! is_type(CONST_XML_NODE));
return *(const xml::node_t **) storage->data;
}
#define NULL_VALUE (value_t())
std::ostream& operator<<(std::ostream& out, const value_t& val);
DECLARE_EXCEPTION(value_error);
#define NULL_VALUE (value_t())
} // namespace ledger
#endif // _VALUE_H

File diff suppressed because it is too large Load diff

View file

@ -51,77 +51,259 @@ public:
DECLARE_EXCEPTION(calc_error);
public:
class scope_t;
class call_scope_t;
typedef function<value_t (scope_t&)> function_t;
typedef function<value_t (call_scope_t&)> function_t;
#define MAKE_FUNCTOR(x) \
xml::xpath_t::wrap_functor(bind(&x, this, _1))
static ptr_op_t wrap_value(const value_t& val);
static ptr_op_t wrap_functor(const function_t& fobj);
xml::xpath_t::op_t::wrap_functor(bind(&x, this, _1))
#define WRAP_FUNCTOR(x) \
xml::xpath_t::op_t::wrap_functor(x)
public:
class scope_t : public noncopyable
{
typedef std::map<const string, ptr_op_t> symbol_map;
symbol_map symbols;
public:
optional<scope_t&> parent;
value_t::sequence_t args;
enum type_t {
CHILD_SCOPE,
SYMBOL_SCOPE,
CALL_SCOPE,
CONTEXT_SCOPE,
NODE_SCOPE,
PREDICATE_SCOPE
} type_;
enum kind_t { NORMAL, STATIC, ARGUMENT } kind;
explicit scope_t(const optional<scope_t&>& _parent = none,
kind_t _kind = NORMAL)
: parent(_parent), kind(_kind) {
TRACE_CTOR(xpath_t::scope_t, "kind_t, const optional<scope_t&>&");
}
explicit scope_t(scope_t& _parent, kind_t _kind = NORMAL)
: parent(_parent), kind(_kind) {
TRACE_CTOR(xpath_t::scope_t, "scope_t&, kind_t");
explicit scope_t(type_t _type) : type_(_type) {
TRACE_CTOR(xpath_t::scope_t, "type_t");
}
virtual ~scope_t() {
TRACE_DTOR(xpath_t::scope_t);
}
public:
virtual void define(const string& name, ptr_op_t def);
void define(const string& name, const function_t& def);
virtual ptr_op_t lookup(const string& name);
virtual optional<value_t> resolve(const string& name, scope_t& locals) {
if (parent)
return parent->resolve(name, locals);
return none;
const type_t type() const {
return type_;
}
friend struct op_t;
virtual void define(const string& name, ptr_op_t def) = 0;
void define(const string& name, const value_t& val);
virtual ptr_op_t lookup(const string& name) = 0;
value_t resolve(const string& name) {
return lookup(name)->calc(*this);
}
virtual optional<scope_t&> find_scope(const type_t _type,
bool skip_this = false) = 0;
template <typename T>
T& find_scope(bool skip_this = false) {
assert(false);
}
};
class function_scope_t : public scope_t
class child_scope_t : public scope_t
{
const node_t& node;
std::size_t index;
std::size_t size;
scope_t * parent;
public:
function_scope_t(const value_t::sequence_t& _sequence,
const node_t& _node,
std::size_t _index,
const optional<scope_t&>& _parent = none)
: scope_t(_parent, STATIC), node(_node), index(_index),
size(_sequence.size()) {}
explicit child_scope_t(type_t _type = CHILD_SCOPE)
: scope_t(_type), parent(NULL) {
TRACE_CTOR(xpath_t::child_scope_t, "type_t");
}
explicit child_scope_t(scope_t& _parent, type_t _type = CHILD_SCOPE)
: scope_t(_type), parent(&_parent) {
TRACE_CTOR(xpath_t::child_scope_t, "scope_t&, type_t");
}
virtual ~child_scope_t() {
TRACE_DTOR(xpath_t::child_scope_t);
}
public:
virtual void define(const string& name, ptr_op_t def) {
if (parent)
parent->define(name, def);
}
virtual ptr_op_t lookup(const string& name) {
if (parent)
return parent->lookup(name);
return ptr_op_t();
}
function_scope_t(const node_t& _node,
std::size_t _index,
std::size_t _size,
const optional<scope_t&>& _parent = none)
: scope_t(_parent, STATIC), node(_node), index(_index),
size(_size) {}
virtual optional<scope_t&> find_scope(type_t _type,
bool skip_this = false) {
for (scope_t * ptr = (skip_this ? parent : this); ptr; ) {
if (ptr->type() == _type)
return *ptr;
virtual optional<value_t> resolve(const string& name, scope_t& locals);
ptr = polymorphic_downcast<child_scope_t *>(ptr)->parent;
}
return none;
}
};
class symbol_scope_t : public child_scope_t
{
typedef std::map<const string, ptr_op_t> symbol_map;
symbol_map symbols;
public:
explicit symbol_scope_t()
: child_scope_t(SYMBOL_SCOPE) {
TRACE_CTOR(xpath_t::symbol_scope_t, "");
}
explicit symbol_scope_t(scope_t& _parent)
: child_scope_t(_parent, SYMBOL_SCOPE) {
TRACE_CTOR(xpath_t::symbol_scope_t, "scope_t&");
}
virtual ~symbol_scope_t() {
TRACE_DTOR(xpath_t::symbol_scope_t);
}
virtual void define(const string& name, ptr_op_t def);
void define(const string& name, const value_t& val) {
scope_t::define(name, val);
}
virtual ptr_op_t lookup(const string& name);
};
class call_scope_t : public child_scope_t
{
value_t args;
public:
explicit call_scope_t(scope_t& _parent)
: child_scope_t(_parent, CALL_SCOPE) {
TRACE_CTOR(xpath_t::call_scope_t, "scope_t&");
}
virtual ~call_scope_t() {
TRACE_DTOR(xpath_t::call_scope_t);
}
void set_args(const value_t& _args) {
args = _args;
}
value_t& value() {
return args;
}
value_t& operator[](const int index) {
return args[index];
}
const value_t& operator[](const int index) const {
return args[index];
}
void push_back(const value_t& val) {
args.push_back(val);
}
void pop_back() {
args.pop_back();
}
const std::size_t size() const {
return args.size();
}
};
class context_scope_t : public child_scope_t
{
public:
value_t element;
optional<value_t> sequence;
explicit context_scope_t(scope_t& _parent,
const value_t& _element,
const optional<value_t>& _sequence = none)
: child_scope_t(_parent, CONTEXT_SCOPE),
element(_element), sequence(_sequence)
{
TRACE_CTOR(xpath_t::context_scope_t,
"scope_t&, const value_t&, const optional<value_t>&");
assert(! element.is_sequence());
if (DO_VERIFY() && sequence) {
if (sequence->is_sequence()) {
value_t::sequence_t seq(sequence->as_sequence());
value_t::iterator i = std::find(seq.begin(), seq.end(), element);
assert(i != seq.end());
} else {
assert(element == *sequence);
}
}
}
virtual ~context_scope_t() {
TRACE_DTOR(xpath_t::context_scope_t);
}
const std::size_t index() const {
if (! sequence) {
return 0;
} else {
value_t::sequence_t seq(sequence->as_sequence());
value_t::iterator i = std::find(seq.begin(), seq.end(), element);
assert(i != seq.end());
int_least16_t offset = i - seq.begin();
assert(offset >= 0);
return std::size_t(offset);
}
}
const std::size_t size() const {
return sequence ? sequence->size() : (element.is_null() ? 0 : 1);
}
value_t& value() {
return element;
}
node_t& xml_node() {
if (! element.is_xml_node())
throw_(calc_error, "The current context value is not an XML node");
return *element.as_xml_node();
}
};
class node_scope_t : public context_scope_t
{
public:
node_scope_t(scope_t& _parent, node_t& _node)
: context_scope_t(_parent, &_node) {
TRACE_CTOR(xpath_t::node_scope_t, "scope_t&, node_t&");
type_ = NODE_SCOPE;
}
virtual ~node_scope_t() {
TRACE_DTOR(xpath_t::node_scope_t);
}
};
typedef node_scope_t document_scope_t;
class predicate_scope_t : public child_scope_t
{
public:
ptr_op_t predicate;
explicit predicate_scope_t(scope_t& _parent,
const ptr_op_t& _predicate)
: child_scope_t(_parent, PREDICATE_SCOPE), predicate(_predicate)
{
TRACE_CTOR(xpath_t::predicate_scope_t, "scope_t&, const ptr_op_t&");
}
virtual ~predicate_scope_t() {
TRACE_DTOR(xpath_t::predicate_scope_t);
}
bool test(scope_t& scope,
const value_t& val,
const optional<value_t>& sequence = none) const {
context_scope_t context_scope(scope, val, sequence);
if (predicate->is_value()) {
value_t& predicate_value(predicate->as_value());
if (predicate_value.is_long())
return predicate_value.as_long() == (long)context_scope.index() + 1;
}
return predicate->calc(context_scope).to_boolean();
}
};
#define XPATH_PARSE_NORMAL 0x00
@ -137,57 +319,59 @@ private:
struct token_t
{
enum kind_t {
IDENT, // [A-Za-z_][-A-Za-z0-9_:]*
VALUE, // any kind of literal value
AT_SYM, // @
IDENT, // [A-Za-z_][-A-Za-z0-9_:]*
DOLLAR, // $
AT_SYM, // @
DOT, // .
DOTDOT, // ..
SLASH, // /
LPAREN, // (
RPAREN, // )
LBRACKET, // (
RBRACKET, // )
EXCLAM, // !
NEQUAL, // !=
MINUS, // -
PLUS, // +
STAR, // *
POWER, // **
SLASH, // /
LBRACKET, // [
RBRACKET, // ]
EQUAL, // =
ASSIGN, // :=
NEQUAL, // !=
LESS, // <
LESSEQ, // <=
GREATER, // >
GREATEREQ, // >=
AMPER, // &
PIPE, // |
QUESTION, // ?
COLON, // :
COMMA, // ,
MINUS, // -
PLUS, // +
STAR, // *
KW_DIV,
EXCLAM, // !
KW_AND,
KW_OR,
KW_DIV,
KW_MOD,
PIPE, // |
KW_UNION,
COMMA, // ,
TOK_EOF,
UNKNOWN
} kind;
char symbol[3];
value_t value;
unsigned int length;
char symbol[3];
value_t value;
std::size_t length;
token_t() : kind(UNKNOWN), length(0) {
explicit token_t() : kind(UNKNOWN), length(0) {
TRACE_CTOR(xpath_t::token_t, "");
}
token_t(const token_t& other) {
assert(false);
TRACE_CTOR(xpath_t::token_t, "copy");
*this = other;
}
~token_t() {
TRACE_DTOR(xpath_t::token_t);
}
@ -202,7 +386,7 @@ private:
void clear() {
kind = UNKNOWN;
length = 0;
value = 0L;
value = NULL_VALUE;
symbol[0] = '\0';
symbol[1] = '\0';
@ -210,82 +394,23 @@ private:
}
void parse_ident(std::istream& in);
void next(std::istream& in, flags_t flags);
void rewind(std::istream& in);
void unexpected();
static void unexpected(char c, char wanted = '\0');
};
public:
class path_t
{
public:
typedef function<void (const value_t&)> visitor_t;
typedef function<bool (const node_t&, scope_t&)> predicate_t;
private:
struct value_appender_t {
value_t::sequence_t& sequence;
value_appender_t(value_t::sequence_t& _sequence)
: sequence(_sequence) {}
void operator()(const value_t& val) {
sequence.push_back(val);
}
};
ptr_op_t path_expr;
template <typename NodeType>
void walk_elements(NodeType& start,
const ptr_op_t& element,
const bool recurse,
scope_t& scope,
const visitor_t& func);
template <typename NodeType>
void check_element(NodeType& start,
const ptr_op_t& element,
scope_t& scope,
std::size_t index,
std::size_t size,
const visitor_t& 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_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, value_appender_t(result.as_sequence_lval()));
return result;
}
void visit(node_t& start, scope_t& scope, const visitor_t& func) {
if (path_expr)
walk_elements<node_t>(start, path_expr, false, scope, func);
}
void visit(const node_t& start, scope_t& scope, const visitor_t& func) {
if (path_expr)
walk_elements<const node_t>(start, path_expr, false, scope, func);
}
};
template <typename NodeType>
#if 0
class path_iterator_t
{
typedef NodeType * pointer;
typedef NodeType& reference;
path_t path;
reference start;
scope_t& scope;
path_t path;
node_t& start;
scope_t& scope;
mutable value_t::sequence_t sequence;
mutable bool searched;
@ -304,7 +429,7 @@ public:
typedef value_t::sequence_t::const_iterator const_iterator;
path_iterator_t(const xpath_t& path_expr,
reference _start, scope_t& _scope)
node_t& _start, scope_t& _scope)
: path(path_expr), start(_start), scope(_scope),
searched(false) {
}
@ -323,21 +448,21 @@ public:
iterator end() { return sequence.end(); }
const_iterator end() const { return sequence.end(); }
};
#endif
struct op_t : public noncopyable
{
enum kind_t {
VOID,
VALUE,
FUNC_NAME,
VAR_NAME,
ARG_INDEX,
NODE_ID,
NODE_NAME,
ATTR_ID,
ATTR_NAME,
FUNC_NAME,
VAR_NAME,
ARG_INDEX,
CONSTANTS, // constants end here
@ -345,15 +470,12 @@ public:
TERMINALS, // terminals end here
O_NOT,
O_NEG,
O_CALL,
O_ARG,
O_UNION,
O_ADD,
O_SUB,
O_MUL,
O_DIV,
O_FIND,
O_RFIND,
O_PRED,
O_NEQ,
O_EQ,
@ -362,22 +484,20 @@ public:
O_GT,
O_GTE,
O_ADD,
O_SUB,
O_MUL,
O_DIV,
O_NEG,
O_NOT,
O_AND,
O_OR,
O_QUES,
O_COLON,
O_UNION,
O_COMMA,
O_DEFINE,
O_EVAL,
O_ARG,
O_FIND,
O_RFIND,
O_PRED,
LAST // operators end here
};
@ -387,13 +507,13 @@ public:
variant<unsigned int, // used by ARG_INDEX and O_ARG
value_t, // used by constant VALUE
string, // used by constant SYMBOL
string, // used by constants SYMBOL, *_NAME
function_t, // used by terminal FUNCTION
node_t::nameid_t, // used by NODE_NAME and ATTR_NAME
node_t::nameid_t, // used by NODE_ID and ATTR_ID
ptr_op_t> // used by all binary operators
data;
op_t(const kind_t _kind) : kind(_kind), refc(0){
explicit op_t(const kind_t _kind) : kind(_kind), refc(0){
TRACE_CTOR(xpath_t::op_t, "const kind_t");
}
~op_t() {
@ -403,8 +523,6 @@ public:
assert(refc == 0);
}
op_t& operator=(const op_t&);
bool is_long() const {
return data.type() == typeid(unsigned int);
}
@ -475,22 +593,6 @@ public:
data = val;
}
#if 0
bool is_path() const {
return kind == PATH;
}
path_t& as_path() {
assert(kind == PATH);
return boost::get<path_t>(data);
}
const path_t& as_path() const {
return const_cast<op_t *>(this)->as_path();
}
void set_path(const path_t& val) {
data = val;
}
#endif
ptr_op_t& as_op() {
assert(kind > TERMINALS);
return boost::get<ptr_op_t>(data);
@ -538,23 +640,38 @@ public:
data = expr;
}
static ptr_op_t new_node(kind_t kind, ptr_op_t left = NULL,
ptr_op_t right = NULL);
static ptr_op_t new_node(kind_t _kind, ptr_op_t _left = NULL,
ptr_op_t _right = NULL);
ptr_op_t copy(ptr_op_t _left = NULL, ptr_op_t _right = NULL) const {
return new_node(kind, _left, _right);
}
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);
static ptr_op_t wrap_value(const value_t& val);
static ptr_op_t wrap_functor(const function_t& fobj);
void append_value(value_t::sequence_t& result_seq, value_t& value);
ptr_op_t compile(scope_t& scope);
value_t current_value(scope_t& scope);
node_t& current_xml_node(scope_t& scope);
value_t calc(scope_t& scope);
static ptr_op_t defer_sequence(value_t::sequence_t& result_seq);
struct print_context_t
{
scope_t& scope;
const bool relaxed;
const ptr_op_t& op_to_find;
unsigned long * start_pos;
unsigned long * end_pos;
bool print(std::ostream& out,
document_t& document,
const bool relaxed = true,
const ptr_op_t& op_to_find = NULL,
unsigned long * start_pos = NULL,
unsigned long * end_pos = NULL) const;
print_context_t(scope_t& _scope,
const bool _relaxed = false,
const ptr_op_t& _op_to_find = ptr_op_t(),
unsigned long * _start_pos = NULL,
unsigned long * _end_pos = NULL)
: scope(_scope), relaxed(_relaxed), op_to_find(_op_to_find),
start_pos(_start_pos), end_pos(_end_pos) {}
};
bool print(std::ostream& out, print_context_t& context) const;
void dump(std::ostream& out, const int depth) const;
friend inline void intrusive_ptr_add_ref(xpath_t::op_t * op) {
@ -565,15 +682,12 @@ public:
}
};
class op_predicate : public noncopyable
{
class op_predicate : public noncopyable {
ptr_op_t op;
public:
explicit op_predicate(ptr_op_t _op) : op(_op) {}
bool operator()(const node_t& node, scope_t& scope) {
xpath_t result(op->compile(node, scope, true));
return result.ptr->as_value().to_boolean();
bool operator()(scope_t& scope) const {
return op->calc(scope).to_boolean();
}
};
@ -660,14 +774,9 @@ public:
return parse_expr(string(p), tflags);
}
bool print(std::ostream& out,
document_t& document,
const bool relaxed,
const ptr_op_t op_to_find,
unsigned long * start_pos,
unsigned long * end_pos) const {
bool print(std::ostream& out, op_t::print_context_t& context) const {
if (ptr)
ptr->print(out, document, relaxed, op_to_find, start_pos, end_pos);
ptr->print(out, context);
return true;
}
@ -675,20 +784,20 @@ public:
string expr;
flags_t flags; // flags used to parse `expr'
xpath_t() : ptr(NULL), use_lookahead(false), flags(0) {
explicit xpath_t() : ptr(NULL), use_lookahead(false), flags(0) {
TRACE_CTOR(xpath_t, "");
}
xpath_t(ptr_op_t _ptr) : ptr(_ptr), use_lookahead(false) {
explicit xpath_t(ptr_op_t _ptr) : ptr(_ptr), use_lookahead(false) {
TRACE_CTOR(xpath_t, "ptr_op_t");
}
xpath_t(const string& _expr, flags_t _flags = XPATH_PARSE_RELAXED)
explicit xpath_t(const string& _expr, flags_t _flags = XPATH_PARSE_RELAXED)
: ptr(NULL), use_lookahead(false), flags(0) {
TRACE_CTOR(xpath_t, "const string&, flags_t");
if (! _expr.empty())
parse(_expr, _flags);
}
xpath_t(std::istream& in, flags_t _flags = XPATH_PARSE_RELAXED)
explicit xpath_t(std::istream& in, flags_t _flags = XPATH_PARSE_RELAXED)
: ptr(NULL), use_lookahead(false), flags(0) {
TRACE_CTOR(xpath_t, "std::istream&, flags_t");
parse(in, _flags);
@ -698,33 +807,29 @@ public:
expr(other.expr), flags(other.flags) {
TRACE_CTOR(xpath_t, "copy");
}
virtual ~xpath_t() {
~xpath_t() {
TRACE_DTOR(xpath_t);
}
#if 0
xpath_t& operator=(const string& _expr) {
parse(_expr);
return *this;
}
#endif
xpath_t& operator=(const xpath_t& _expr);
xpath_t& operator=(xpath_t& _xpath) {
ptr = _xpath.ptr;
expr = _xpath.expr;
flags = _xpath.flags;
use_lookahead = false;
return *this;
}
#if 0
operator ptr_op_t() throw() {
return ptr;
}
operator bool() const throw() {
return ptr != NULL;
}
operator string() const throw() {
return expr;
}
#endif
void parse(const string& _expr, flags_t _flags = XPATH_PARSE_RELAXED) {
expr = _expr;
@ -737,18 +842,22 @@ public:
ptr = parse_expr(in, _flags);
}
void compile(const node_t& context, scope_t& scope) {
void compile(scope_t& scope) {
if (ptr.get())
ptr = ptr->compile(context, scope);
ptr = ptr->compile(scope);
}
virtual value_t calc(const node_t& context, scope_t& scope) const;
static value_t eval(const string& _expr, const node_t& context,
scope_t& scope) {
return xpath_t(_expr).calc(context, scope);
value_t calc(scope_t& scope) const {
if (ptr.get())
return ptr->calc(scope);
return NULL_VALUE;
}
static value_t eval(const string& _expr, scope_t& scope) {
return xpath_t(_expr).calc(scope);
}
#if 0
path_iterator_t<node_t>
find_all(node_t& start, scope_t& scope) {
return path_iterator_t<node_t>(*this, start, scope);
@ -765,47 +874,81 @@ public:
path_t::visitor_t& func) {
path_t(*this).visit(start, scope, func);
}
#endif
void print(std::ostream& out, xml::document_t& document) const {
print(out, document, true, NULL, NULL, NULL);
void print(std::ostream& out, scope_t& scope) const {
op_t::print_context_t context(scope);
print(out, context);
}
void dump(std::ostream& out) const {
if (ptr)
ptr->dump(out, 0);
}
friend class scope_t;
};
inline xpath_t::ptr_op_t
xpath_t::op_t::new_node(kind_t _kind, ptr_op_t _left, ptr_op_t _right) {
ptr_op_t node(new op_t(_kind));
if (_left)
node->set_left(_left);
if (_right)
node->set_right(_right);
return node;
}
inline xpath_t::ptr_op_t
xpath_t::op_t::wrap_value(const value_t& val) {
xpath_t::ptr_op_t temp(new xpath_t::op_t(xpath_t::op_t::VALUE));
temp->set_value(val);
return temp;
}
inline xpath_t::ptr_op_t
xpath_t::op_t::wrap_functor(const function_t& fobj) {
xpath_t::ptr_op_t temp(new xpath_t::op_t(xpath_t::op_t::FUNCTION));
temp->set_function(fobj);
return temp;
}
template<>
inline xpath_t::symbol_scope_t&
xpath_t::scope_t::find_scope<xpath_t::symbol_scope_t>(bool skip_this) {
optional<scope_t&> scope = find_scope(SYMBOL_SCOPE, skip_this);
assert(scope);
return downcast<symbol_scope_t>(*scope);
}
template<>
inline xpath_t::call_scope_t&
xpath_t::scope_t::find_scope<xpath_t::call_scope_t>(bool skip_this) {
optional<scope_t&> scope = find_scope(CALL_SCOPE, skip_this);
assert(scope);
return downcast<call_scope_t>(*scope);
}
template<>
inline xpath_t::context_scope_t&
xpath_t::scope_t::find_scope<xpath_t::context_scope_t>(bool skip_this) {
optional<scope_t&> scope = find_scope(CONTEXT_SCOPE, skip_this);
assert(scope);
return downcast<context_scope_t>(*scope);
}
template<>
inline xpath_t::node_scope_t&
xpath_t::scope_t::find_scope<xpath_t::node_scope_t>(bool skip_this) {
optional<scope_t&> scope = find_scope(NODE_SCOPE, skip_this);
assert(scope);
return downcast<node_scope_t>(*scope);
}
#define FIND_SCOPE(scope_type, scope_ref) \
downcast<xml::xpath_t::scope_t>(scope_ref).find_scope<scope_type>()
} // 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 = locals.args[idx].as_pointer<T>();
assert(ptr);
return ptr;
}
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_mutable());
assert(ptr);
return ptr;
}
class xml_command
{
public:
value_t operator()(xml::xpath_t::scope_t& locals) {
std::ostream * out = get_ptr<std::ostream>(locals, 0);
xml::document_t * doc = get_node_ptr<xml::document_t>(locals, 1);
doc->print(*out);
return true;
}
};
value_t xml_command(xml::xpath_t::call_scope_t& args);
} // namespace ledger