summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2008-07-29 18:57:02 -0400
committerJohn Wiegley <johnw@newartisans.com>2008-07-29 18:57:02 -0400
commit200d919fe7c8bcf021011c16fb6ec50821444d5e (patch)
treec3da877b2968bf9ee697727c19bec5fe16c59144
parentd073a7e8a599def9c6dae0f98903d9b59766e9fc (diff)
downloadfork-ledger-200d919fe7c8bcf021011c16fb6ec50821444d5e.tar.gz
fork-ledger-200d919fe7c8bcf021011c16fb6ec50821444d5e.tar.bz2
fork-ledger-200d919fe7c8bcf021011c16fb6ec50821444d5e.zip
Changed the way scopes are structured for an upcoming design change.
-rw-r--r--journal.h6
-rw-r--r--parsexp.cc1067
-rw-r--r--parsexp.h235
-rw-r--r--pyinterp.cc5
-rw-r--r--pyinterp.h6
-rw-r--r--report.cc2
-rw-r--r--report.h6
-rw-r--r--scope.h224
-rw-r--r--session.cc6
-rw-r--r--session.h2
-rw-r--r--valexpr.cc1095
-rw-r--r--valexpr.h1007
12 files changed, 29 insertions, 3632 deletions
diff --git a/journal.h b/journal.h
index 2248714e..636616f2 100644
--- a/journal.h
+++ b/journal.h
@@ -351,7 +351,7 @@ class account_t
account_t(account_t * _parent = NULL,
const string& _name = "",
- const optional<string> _note = none)
+ const optional<string>& _note = none)
: parent(_parent), name(_name), note(_note),
depth(parent ? parent->depth + 1 : 0), data(NULL), ident(0) {
TRACE_CTOR(account_t, "account_t *, const string&, const string&");
@@ -502,10 +502,10 @@ public:
{
public:
parser_t() {
- TRACE_CTOR(parser_t, "");
+ TRACE_CTOR(journal_t::parser_t, "");
}
virtual ~parser_t() {
- TRACE_DTOR(parser_t);
+ TRACE_DTOR(journal_t::parser_t);
}
virtual bool test(std::istream& in) const = 0;
diff --git a/parsexp.cc b/parsexp.cc
deleted file mode 100644
index dcebbcd6..00000000
--- a/parsexp.cc
+++ /dev/null
@@ -1,1067 +0,0 @@
-/*
- * Copyright (c) 2003-2008, John Wiegley. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * - Neither the name of New Artisans LLC nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "parsexp.h"
-#include "parser.h"
-
-namespace ledger {
-namespace expr {
-
-void parser_t::token_t::parse_ident(std::istream& in)
-{
- if (in.eof()) {
- kind = TOK_EOF;
- return;
- }
- assert(in.good());
-
- char c = peek_next_nonws(in);
-
- if (in.eof()) {
- kind = TOK_EOF;
- return;
- }
- assert(in.good());
-
- kind = IDENT;
- length = 0;
-
- char buf[256];
- READ_INTO_(in, buf, 255, c, length,
- std::isalnum(c) || c == '_' || c == '.' || c == '-');
-
- switch (buf[0]) {
- case 'a':
- if (std::strcmp(buf, "and") == 0)
- kind = KW_AND;
- break;
- case 'd':
- if (std::strcmp(buf, "div") == 0)
- kind = KW_DIV;
- break;
- case 'e':
- if (std::strcmp(buf, "eq") == 0)
- kind = EQUAL;
- break;
- case 'f':
- if (std::strcmp(buf, "false") == 0) {
- kind = VALUE;
- value = false;
- }
- break;
- case 'g':
- if (std::strcmp(buf, "gt") == 0)
- kind = GREATER;
- else if (std::strcmp(buf, "ge") == 0)
- kind = GREATEREQ;
- break;
- case 'i':
- if (std::strcmp(buf, "is") == 0)
- kind = EQUAL;
- break;
- case 'l':
- if (std::strcmp(buf, "lt") == 0)
- kind = LESS;
- else if (std::strcmp(buf, "le") == 0)
- kind = LESSEQ;
- break;
- case 'm':
- if (std::strcmp(buf, "mod") == 0)
- kind = KW_MOD;
- break;
- case 'n':
- if (std::strcmp(buf, "ne") == 0)
- kind = NEQUAL;
- break;
- case 'o':
- if (std::strcmp(buf, "or") == 0)
- kind = KW_OR;
- break;
- case 't':
- if (std::strcmp(buf, "true") == 0) {
- kind = VALUE;
- value = true;
- }
- break;
- }
-
- if (kind == IDENT)
- value.set_string(buf);
-}
-
-void parser_t::token_t::next(std::istream& in, const flags_t flags)
-{
- if (in.eof()) {
- kind = TOK_EOF;
- return;
- }
- assert(in.good());
-
- char c = peek_next_nonws(in);
-
- if (in.eof()) {
- kind = TOK_EOF;
- return;
- }
- assert(in.good());
-
- symbol[0] = c;
- symbol[1] = '\0';
-
- length = 1;
-
- if (! (flags & EXPR_PARSE_RELAXED) &&
- (std::isalpha(c) || c == '_')) {
- parse_ident(in);
- return;
- }
-
- switch (c) {
- case '@':
- in.get(c);
- kind = AT_SYM;
- break;
-
- case '&':
- in.get(c);
- kind = KW_AND;
- break;
-
- case '(':
- in.get(c);
- kind = LPAREN;
- break;
- case ')':
- in.get(c);
- kind = RPAREN;
- break;
-
- case '[': {
- in.get(c);
- if (! (flags & EXPR_PARSE_NO_DATES)) {
- char buf[256];
- READ_INTO_(in, buf, 255, c, length, c != ']');
- if (c != ']')
- unexpected(c, ']');
- in.get(c);
- length++;
- interval_t timespan(buf);
- kind = VALUE;
- value = timespan.first();
- } else {
- kind = LBRACKET;
- }
- break;
- }
-
- case ']': {
- in.get(c);
- kind = RBRACKET;
- break;
- }
-
-
- case '\'':
- case '"': {
- char delim;
- in.get(delim);
- char buf[4096];
- READ_INTO_(in, buf, 4095, c, length, c != delim);
- if (c != delim)
- unexpected(c, delim);
- in.get(c);
- length++;
- kind = VALUE;
- value.set_string(buf);
- break;
- }
-
- case '{': {
- in.get(c);
- amount_t temp;
- temp.parse(in, AMOUNT_PARSE_NO_MIGRATE);
- in.get(c);
- if (c != '}')
- unexpected(c, '}');
- length++;
- kind = VALUE;
- value = temp;
- break;
- }
-
- case '!':
- in.get(c);
- c = in.peek();
- if (c == '=') {
- in.get(c);
- symbol[1] = c;
- symbol[2] = '\0';
- kind = NEQUAL;
- length = 2;
- break;
- }
- kind = EXCLAM;
- break;
-
- case '-':
- in.get(c);
- kind = MINUS;
- break;
- case '+':
- in.get(c);
- kind = PLUS;
- break;
-
- case '*':
- in.get(c);
- kind = STAR;
- break;
-
- case 'c':
- case 'C':
- case 'p':
- case 'w':
- case 'W':
- case 'e':
- case '/': {
- bool code_mask = c == 'c';
- bool commodity_mask = c == 'C';
- bool payee_mask = c == 'p';
- bool note_mask = c == 'e';
- bool short_account_mask = c == 'w';
-
- in.get(c);
- if (c == '/') {
- c = peek_next_nonws(in);
- if (c == '/') {
- in.get(c);
- c = in.peek();
- if (c == '/') {
- in.get(c);
- c = in.peek();
- short_account_mask = true;
- } else {
- payee_mask = true;
- }
- }
- } else {
- in.get(c);
- }
-
- // Read in the regexp
- char buf[256];
- READ_INTO_(in, buf, 255, c, length, c != '/');
- if (c != '/')
- unexpected(c, '/');
- in.get(c);
- length++;
-
- if (short_account_mask)
- kind = SHORT_ACCOUNT_MASK;
- else if (code_mask)
- kind = CODE_MASK;
- else if (commodity_mask)
- kind = COMMODITY_MASK;
- else if (payee_mask)
- kind = PAYEE_MASK;
- else if (note_mask)
- kind = NOTE_MASK;
- else
- kind = ACCOUNT_MASK;
-
- value.set_string(buf);
- break;
- }
-
- case '=':
- in.get(c);
- kind = EQUAL;
- break;
-
- case '<':
- in.get(c);
- if (in.peek() == '=') {
- in.get(c);
- symbol[1] = c;
- symbol[2] = '\0';
- kind = LESSEQ;
- length = 2;
- break;
- }
- kind = LESS;
- break;
-
- case '>':
- in.get(c);
- if (in.peek() == '=') {
- in.get(c);
- symbol[1] = c;
- symbol[2] = '\0';
- kind = GREATEREQ;
- length = 2;
- break;
- }
- kind = GREATER;
- break;
-
- case ',':
- in.get(c);
- kind = COMMA;
- break;
-
- case '.':
- in.get(c);
- c = in.peek();
- if (c == '.') {
- in.get(c);
- length++;
- kind = DOTDOT;
- break;
- }
- else if (! std::isdigit(c)) {
- kind = DOT;
- break;
- }
- in.unget(); // put the first '.' back
- // fall through...
-
- default:
- if (! (flags & EXPR_PARSE_RELAXED)) {
- kind = UNKNOWN;
- } else {
- amount_t temp;
- unsigned long pos = 0;
-
- // When in relaxed parsing mode, we want to migrate commodity
- // flags so that any precision specified by the user updates the
- // current maximum displayed precision.
- pos = (long)in.tellg();
-
- unsigned char parse_flags = 0;
- if (flags & EXPR_PARSE_NO_MIGRATE)
- parse_flags |= AMOUNT_PARSE_NO_MIGRATE;
- if (flags & EXPR_PARSE_NO_REDUCE)
- parse_flags |= AMOUNT_PARSE_NO_REDUCE;
-
- if (! temp.parse(in, parse_flags | AMOUNT_PARSE_SOFT_FAIL)) {
- // If the amount had no commodity, it must be an unambiguous
- // variable reference
-
- in.clear();
- in.seekg(pos, std::ios::beg);
-
- c = in.peek();
- assert(! (std::isdigit(c) || c == '.'));
- parse_ident(in);
- } else {
- kind = VALUE;
- value = temp;
- }
- }
- break;
- }
-}
-
-void parser_t::token_t::rewind(std::istream& in)
-{
- for (unsigned int i = 0; i < length; i++)
- in.unget();
-}
-
-
-void parser_t::token_t::unexpected()
-{
- switch (kind) {
- case TOK_EOF:
- throw_(parse_error, "Unexpected end of expression");
- case IDENT:
- throw_(parse_error, "Unexpected symbol '" << value << "'");
- case VALUE:
- throw_(parse_error, "Unexpected value '" << value << "'");
- default:
- throw_(parse_error, "Unexpected operator '" << symbol << "'");
- }
-}
-
-void parser_t::token_t::unexpected(char c, char wanted)
-{
- if ((unsigned char) c == 0xff) {
- if (wanted)
- throw_(parse_error, "Missing '" << wanted << "'");
- else
- throw_(parse_error, "Unexpected end");
- } else {
- if (wanted)
- throw_(parse_error, "Invalid char '" << c <<
- "' (wanted '" << wanted << "')");
- else
- throw_(parse_error, "Invalid char '" << c << "'");
- }
-}
-
-ptr_op_t
-parser_t::parse_value_term(std::istream& in, scope_t& scope, const flags_t tflags) const
-{
- ptr_op_t node;
-
- token_t& tok = next_token(in, tflags);
-
- switch (tok.kind) {
- case token_t::VALUE:
- node = new op_t(op_t::VALUE);
- node->set_value(tok.value);
- break;
-
- case token_t::SHORT_ACCOUNT_MASK:
- node = new op_t(op_t::F_SHORT_ACCOUNT_MASK);
- node->set_mask(tok.value.as_string());
- break;
- case token_t::CODE_MASK:
- node = new op_t(op_t::F_CODE_MASK);
- node->set_mask(tok.value.as_string());
- break;
- case token_t::COMMODITY_MASK:
- node = new op_t(op_t::F_COMMODITY_MASK);
- node->set_mask(tok.value.as_string());
- break;
- case token_t::PAYEE_MASK:
- node = new op_t(op_t::F_PAYEE_MASK);
- node->set_mask(tok.value.as_string());
- break;
- case token_t::NOTE_MASK:
- node = new op_t(op_t::F_NOTE_MASK);
- node->set_mask(tok.value.as_string());
- break;
- case token_t::ACCOUNT_MASK:
- node = new op_t(op_t::F_ACCOUNT_MASK);
- node->set_mask(tok.value.as_string());
- break;
-
- case token_t::IDENT: {
-#if 0
-#ifdef USE_BOOST_PYTHON
- if (tok.value->as_string() == "lambda") // special
- try {
- char c, buf[4096];
-
- std::strcpy(buf, "lambda ");
- READ_INTO(in, &buf[7], 4000, c, true);
-
- ptr_op_t eval = new op_t(op_t::O_EVAL);
- ptr_op_t lambda = new op_t(op_t::FUNCTION);
- lambda->functor = new python_functor_t(python_eval(buf));
- eval->set_left(lambda);
- ptr_op_t sym = new op_t(op_t::SYMBOL);
- sym->name = new string("__ptr");
- eval->set_right(sym);
-
- node = eval;
-
- goto done;
- }
- catch(const boost::python::error_already_set&) {
- throw_(parse_error, "Error parsing lambda expression");
- }
-#endif /* USE_BOOST_PYTHON */
-#endif
-
- string ident = tok.value.as_string();
-
- // An identifier followed by ( represents a function call
- tok = next_token(in, tflags);
-
- if (tok.kind == token_t::LPAREN) {
-#if 0
- node = new op_t(op_t::FUNC_NAME);
- node->set_string(ident);
-
- ptr_op_t call_node(new op_t(op_t::O_CALL));
- call_node->set_left(node);
- call_node->set_right(parse_value_expr(in, scope,
- tflags | EXPR_PARSE_PARTIAL));
-
- tok = next_token(in, tflags);
- if (tok.kind != token_t::RPAREN)
- tok.unexpected(0xff, ')');
-
- node = call_node;
-#endif
- } else {
- if (std::isdigit(ident[0])) {
- node = new op_t(op_t::O_ARG);
- node->set_long(lexical_cast<unsigned int>(ident.c_str()));
- } else {
- node = new op_t(op_t::O_LOOKUP);
- node->set_string(ident);
- }
- push_token(tok);
- }
- break;
- }
-
- case token_t::LPAREN:
- node = new op_t(op_t::O_COMMA);
- node->set_left(parse_value_expr(in, scope, tflags | EXPR_PARSE_PARTIAL));
- if (! node->left())
- throw_(parse_error, tok.symbol << " operator not followed by argument");
-
- tok = next_token(in, tflags);
- if (tok.kind != token_t::RPAREN)
- tok.unexpected(0xff, ')');
- break;
-
- default:
- push_token(tok);
- break;
- }
-
-#if 0
-#ifdef USE_BOOST_PYTHON
- done:
-#endif
-#endif
- return node;
-}
-
-ptr_op_t
-parser_t::parse_unary_expr(std::istream& in, scope_t& scope,
- const flags_t tflags) const
-{
- ptr_op_t node;
-
- token_t& tok = next_token(in, tflags);
-
- switch (tok.kind) {
- case token_t::EXCLAM: {
- ptr_op_t term(parse_value_term(in, scope, tflags));
- if (! term)
- throw_(parse_error,
- tok.symbol << " operator not followed by argument");
-
- // A very quick optimization
- if (term->kind == op_t::VALUE) {
- term->as_value_lval().in_place_negate();
- node = term;
- } else {
- node = new op_t(op_t::O_NOT);
- node->set_left(term);
- }
- break;
- }
-
- case token_t::MINUS: {
- ptr_op_t term(parse_value_term(in, scope, tflags));
- if (! term)
- throw_(parse_error,
- tok.symbol << " operator not followed by argument");
-
- // A very quick optimization
- if (term->kind == op_t::VALUE) {
- term->as_value_lval().in_place_negate();
- node = term;
- } else {
- node = new op_t(op_t::O_NEG);
- node->set_left(term);
- }
- break;
- }
-
- default:
- push_token(tok);
- node = parse_value_term(in, scope, tflags);
- break;
- }
-
- return node;
-}
-
-ptr_op_t
-parser_t::parse_mul_expr(std::istream& in, scope_t& scope, const flags_t tflags) const
-{
- ptr_op_t node(parse_unary_expr(in, scope, tflags));
-
- if (node) {
- token_t& tok = next_token(in, tflags);
- if (tok.kind == token_t::STAR || tok.kind == token_t::KW_DIV) {
- ptr_op_t prev(node);
- node = new op_t(tok.kind == token_t::STAR ?
- op_t::O_MUL : op_t::O_DIV);
- node->set_left(prev);
- node->set_right(parse_mul_expr(in, scope, tflags));
- if (! node->right())
- throw_(parse_error,
- tok.symbol << " operator not followed by argument");
-
- tok = next_token(in, tflags);
- }
- push_token(tok);
- }
-
- return node;
-}
-
-ptr_op_t
-parser_t::parse_add_expr(std::istream& in, scope_t& scope, const flags_t tflags) const
-{
- ptr_op_t node(parse_mul_expr(in, scope, tflags));
-
- if (node) {
- token_t& tok = next_token(in, tflags);
- if (tok.kind == token_t::PLUS ||
- tok.kind == token_t::MINUS) {
- ptr_op_t prev(node);
- node = new op_t(tok.kind == token_t::PLUS ?
- op_t::O_ADD : op_t::O_SUB);
- node->set_left(prev);
- node->set_right(parse_add_expr(in, scope, tflags));
- if (! node->right())
- throw_(parse_error,
- tok.symbol << " operator not followed by argument");
-
- tok = next_token(in, tflags);
- }
- push_token(tok);
- }
-
- return node;
-}
-
-ptr_op_t
-parser_t::parse_logic_expr(std::istream& in, scope_t& scope, const flags_t tflags) const
-{
- ptr_op_t node(parse_add_expr(in, scope, tflags));
-
- if (node) {
- op_t::kind_t kind = op_t::LAST;
- flags_t _flags = tflags;
- token_t& tok = next_token(in, tflags);
- switch (tok.kind) {
- case token_t::EQUAL:
- if (tflags & EXPR_PARSE_NO_ASSIGN)
- tok.rewind(in);
- else
- kind = op_t::O_EQ;
- break;
- case token_t::NEQUAL:
- kind = op_t::O_NEQ;
- break;
- case token_t::LESS:
- kind = op_t::O_LT;
- break;
- case token_t::LESSEQ:
- kind = op_t::O_LTE;
- break;
- case token_t::GREATER:
- kind = op_t::O_GT;
- break;
- case token_t::GREATEREQ:
- kind = op_t::O_GTE;
- break;
- default:
- push_token(tok);
- break;
- }
-
- if (kind != op_t::LAST) {
- ptr_op_t prev(node);
- node = new op_t(kind);
- node->set_left(prev);
- node->set_right(parse_add_expr(in, scope, _flags));
-
- if (! node->right()) {
- if (tok.kind == token_t::PLUS)
- throw_(parse_error,
- tok.symbol << " operator not followed by argument");
- else
- throw_(parse_error,
- tok.symbol << " operator not followed by argument");
- }
- }
- }
-
- return node;
-}
-
-ptr_op_t
-parser_t::parse_and_expr(std::istream& in, scope_t& scope, const flags_t tflags) const
-{
- ptr_op_t node(parse_logic_expr(in, scope, tflags));
-
- if (node) {
- token_t& tok = next_token(in, tflags);
- if (tok.kind == token_t::KW_AND) {
- ptr_op_t prev(node);
- node = new op_t(op_t::O_AND);
- node->set_left(prev);
- node->set_right(parse_and_expr(in, scope, tflags));
- if (! node->right())
- throw_(parse_error,
- tok.symbol << " operator not followed by argument");
- } else {
- push_token(tok);
- }
- }
- return node;
-}
-
-ptr_op_t
-parser_t::parse_or_expr(std::istream& in, scope_t& scope, const flags_t tflags) const
-{
- ptr_op_t node(parse_and_expr(in, scope, tflags));
-
- if (node) {
- token_t& tok = next_token(in, tflags);
- if (tok.kind == token_t::KW_OR) {
- ptr_op_t prev(node);
- node = new op_t(op_t::O_OR);
- node->set_left(prev);
- node->set_right(parse_or_expr(in, scope, tflags));
- if (! node->right())
- throw_(parse_error,
- tok.symbol << " operator not followed by argument");
- } else {
- push_token(tok);
- }
- }
- return node;
-}
-
-ptr_op_t
-parser_t::parse_value_expr(std::istream& in, scope_t& scope, const flags_t tflags) const
-{
- ptr_op_t node(parse_or_expr(in, scope, tflags));
-
- if (node) {
- token_t& tok = next_token(in, tflags);
- if (tok.kind == token_t::COMMA) {
- ptr_op_t prev(node);
- node = new op_t(op_t::O_COMMA);
- node->set_left(prev);
- node->set_right(parse_value_expr(in, scope, tflags));
- if (! node->right())
- throw_(parse_error,
- tok.symbol << " operator not followed by argument");
- tok = next_token(in, tflags);
- }
-
- if (tok.kind != token_t::TOK_EOF) {
- if (tflags & EXPR_PARSE_PARTIAL)
- push_token(tok);
- else
- tok.unexpected();
- }
- }
- else if (! (tflags & EXPR_PARSE_PARTIAL)) {
- throw_(parse_error, "Failed to parse value expression");
- }
-
- return node;
-}
-
-bool op_t::print(std::ostream& out, print_context_t& context) const
-{
- bool found = false;
-
- if (context.start_pos && this == context.op_to_find) {
- *context.start_pos = (long)out.tellp() - 1;
- found = true;
- }
-
- string symbol;
-
- switch (kind) {
- case VALUE: {
- as_value().print(out, context.relaxed);
- break;
- }
-
-#if 0
- case FUNC_NAME:
- out << as_string();
- break;
-
- case ATTR_NAME:
- out << '@' << as_string();
- break;
-
- case VAR_NAME:
- out << '$' << as_string();
- break;
-#endif
-
- case FUNCTION:
- out << "<FUNCTION>";
- break;
-
- case ARG_INDEX:
- out << '@' << as_long();
- break;
-
- case O_NOT:
- out << "!";
- if (left() && left()->print(out, context))
- found = true;
- break;
- case O_NEG:
- out << "-";
- if (left() && left()->print(out, context))
- found = true;
- break;
-
- case O_ADD:
- out << "(";
- if (left() && left()->print(out, context))
- found = true;
- out << " + ";
- if (right() && right()->print(out, context))
- found = true;
- out << ")";
- break;
- case O_SUB:
- out << "(";
- if (left() && left()->print(out, context))
- found = true;
- out << " - ";
- if (right() && right()->print(out, context))
- found = true;
- out << ")";
- break;
- case O_MUL:
- out << "(";
- if (left() && left()->print(out, context))
- found = true;
- out << " * ";
- if (right() && right()->print(out, context))
- found = true;
- out << ")";
- break;
- case O_DIV:
- out << "(";
- if (left() && left()->print(out, context))
- found = true;
- out << " / ";
- if (right() && right()->print(out, context))
- found = true;
- out << ")";
- break;
-
- case O_NEQ:
- out << "(";
- if (left() && left()->print(out, context))
- found = true;
- out << " != ";
- if (right() && right()->print(out, context))
- found = true;
- out << ")";
- break;
- case O_EQ:
- out << "(";
- if (left() && left()->print(out, context))
- found = true;
- out << " == ";
- if (right() && right()->print(out, context))
- found = true;
- out << ")";
- break;
- case O_LT:
- out << "(";
- if (left() && left()->print(out, context))
- found = true;
- out << " < ";
- if (right() && right()->print(out, context))
- found = true;
- out << ")";
- break;
- case O_LTE:
- out << "(";
- if (left() && left()->print(out, context))
- found = true;
- out << " <= ";
- if (right() && right()->print(out, context))
- found = true;
- out << ")";
- break;
- case O_GT:
- out << "(";
- if (left() && left()->print(out, context))
- found = true;
- out << " > ";
- if (right() && right()->print(out, context))
- found = true;
- out << ")";
- break;
- case O_GTE:
- out << "(";
- if (left() && left()->print(out, context))
- found = true;
- out << " >= ";
- if (right() && right()->print(out, context))
- found = true;
- out << ")";
- break;
-
- case O_AND:
- out << "(";
- if (left() && left()->print(out, context))
- found = true;
- out << " & ";
- if (right() && right()->print(out, context))
- found = true;
- out << ")";
- break;
- case O_OR:
- out << "(";
- if (left() && left()->print(out, context))
- found = true;
- out << " | ";
- if (right() && right()->print(out, context))
- found = true;
- out << ")";
- break;
-
- case O_COMMA:
- if (left() && left()->print(out, context))
- found = true;
- out << ", ";
- if (right() && right()->print(out, context))
- found = true;
- break;
-
-#if 0
- case O_CALL:
- if (left() && left()->print(out, context))
- found = true;
- out << "(";
- if (right() && right()->print(out, context))
- found = true;
- out << ")";
- break;
-#endif
-
- case LAST:
- default:
- assert(false);
- break;
- }
-
- if (! symbol.empty()) {
- if (amount_t::current_pool->find(symbol))
- out << '@';
- out << symbol;
- }
-
- if (context.end_pos && this == context.op_to_find)
- *context.end_pos = (long)out.tellp() - 1;
-
- return found;
-}
-
-void op_t::dump(std::ostream& out, const int depth) const
-{
- out.setf(std::ios::left);
- out.width(10);
- out << this << " ";
-
- for (int i = 0; i < depth; i++)
- out << " ";
-
- switch (kind) {
- case VALUE:
- out << "VALUE - " << as_value();
- break;
-
-#if 0
- case ATTR_NAME:
- out << "ATTR_NAME - " << as_string();
- break;
-
- case FUNC_NAME:
- out << "FUNC_NAME - " << as_string();
- break;
-
- case VAR_NAME:
- out << "VAR_NAME - " << as_string();
- break;
-#endif
-
- case ARG_INDEX:
- out << "ARG_INDEX - " << as_long();
- break;
-
- case FUNCTION:
- out << "FUNCTION";
- break;
-
-#if 0
- case O_CALL: out << "O_CALL"; break;
-#endif
-
- case O_NOT: out << "O_NOT"; break;
- case O_NEG: out << "O_NEG"; break;
-
- case O_ADD: out << "O_ADD"; break;
- case O_SUB: out << "O_SUB"; break;
- case O_MUL: out << "O_MUL"; break;
- case O_DIV: out << "O_DIV"; break;
-
- case O_NEQ: out << "O_NEQ"; break;
- case O_EQ: out << "O_EQ"; break;
- case O_LT: out << "O_LT"; break;
- case O_LTE: out << "O_LTE"; break;
- case O_GT: out << "O_GT"; break;
- case O_GTE: out << "O_GTE"; break;
-
- case O_AND: out << "O_AND"; break;
- case O_OR: out << "O_OR"; break;
-
- case O_COMMA: out << "O_COMMA"; break;
-
- case LAST:
- default:
- assert(false);
- break;
- }
-
- out << " (" << refc << ')' << std::endl;
-
- if (kind > TERMINALS) {
- if (left()) {
- left()->dump(out, depth + 1);
- if (right())
- right()->dump(out, depth + 1);
- } else {
- assert(! right());
- }
- }
-}
-
-} // namespace expr
-} // namespace ledger
diff --git a/parsexp.h b/parsexp.h
deleted file mode 100644
index 900f8d0c..00000000
--- a/parsexp.h
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright (c) 2003-2008, John Wiegley. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * - Neither the name of New Artisans LLC nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _PARSEXP_H
-#define _PARSEXP_H
-
-#include "valexpr.h"
-
-namespace ledger {
-namespace expr {
-
-DECLARE_EXCEPTION(error, parse_error);
-
-class parser_t : public noncopyable
-{
-#define EXPR_PARSE_NORMAL 0x00
-#define EXPR_PARSE_PARTIAL 0x01
-#define EXPR_PARSE_RELAXED 0x02
-#define EXPR_PARSE_NO_MIGRATE 0x04
-#define EXPR_PARSE_NO_REDUCE 0x08
-#define EXPR_PARSE_NO_ASSIGN 0x10
-#define EXPR_PARSE_NO_DATES 0x20
-
-public:
- typedef uint_least8_t flags_t;
-
-private:
- struct token_t : public noncopyable
- {
- enum kind_t {
- VALUE, // any kind of literal value
-
- SHORT_ACCOUNT_MASK,
- CODE_MASK,
- COMMODITY_MASK,
- PAYEE_MASK,
- NOTE_MASK,
- ACCOUNT_MASK,
-
- IDENT, // [A-Za-z_][-A-Za-z0-9_:]*
- DOLLAR, // $
- AT_SYM, // @
-
- DOT, // .
- DOTDOT, // ..
- SLASH, // /
-
- LPAREN, // (
- RPAREN, // )
- LBRACKET, // [
- RBRACKET, // ]
-
- EQUAL, // =
- NEQUAL, // !=
- LESS, // <
- LESSEQ, // <=
- GREATER, // >
- GREATEREQ, // >=
-
- MINUS, // -
- PLUS, // +
- STAR, // *
- KW_DIV,
-
- EXCLAM, // !
- KW_AND,
- KW_OR,
- KW_MOD,
-
- COMMA, // ,
-
- TOK_EOF,
- UNKNOWN
- } kind;
-
- char symbol[3];
- value_t value;
- std::size_t length;
-
- explicit token_t() : kind(UNKNOWN), length(0) {
- TRACE_CTOR(token_t, "");
- }
- ~token_t() throw() {
- TRACE_DTOR(token_t);
- }
-
- token_t& operator=(const token_t& other) {
- if (&other == this)
- return *this;
- assert(false);
- return *this;
- }
-
- void clear() {
- kind = UNKNOWN;
- length = 0;
- value = NULL_VALUE;
-
- symbol[0] = '\0';
- symbol[1] = '\0';
- symbol[2] = '\0';
- }
-
- 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');
- };
-
- mutable token_t lookahead;
- mutable bool use_lookahead;
-
- token_t& next_token(std::istream& in, flags_t tflags) const
- {
- if (use_lookahead)
- use_lookahead = false;
- else
- lookahead.next(in, tflags);
- return lookahead;
- }
-
- void push_token(const token_t& tok) const
- {
- assert(&tok == &lookahead);
- use_lookahead = true;
- }
-
- void push_token() const
- {
- use_lookahead = true;
- }
-
- ptr_op_t parse_value_term(std::istream& in, scope_t& scope,
- const flags_t flags) const;
- ptr_op_t parse_unary_expr(std::istream& in, scope_t& scope,
- const flags_t flags) const;
- ptr_op_t parse_mul_expr(std::istream& in, scope_t& scope,
- const flags_t flags) const;
- ptr_op_t parse_add_expr(std::istream& in, scope_t& scope,
- const flags_t flags) const;
- ptr_op_t parse_logic_expr(std::istream& in, scope_t& scope,
- const flags_t flags) const;
- ptr_op_t parse_and_expr(std::istream& in, scope_t& scope,
- const flags_t flags) const;
- ptr_op_t parse_or_expr(std::istream& in, scope_t& scope,
- const flags_t flags) const;
- ptr_op_t parse_querycolon_expr(std::istream& in, scope_t& scope,
- const flags_t flags) const;
- ptr_op_t parse_value_expr(std::istream& in, scope_t& scope,
- const flags_t flags) const;
-
- value_expr parse_expr(std::istream& in, string& str,
- scope_t& scope, const flags_t flags) {
- try {
- ptr_op_t top_node = parse_value_expr(in, scope, flags);
-
- if (use_lookahead) {
- use_lookahead = false;
- lookahead.rewind(in);
- }
- lookahead.clear();
-
- return value_expr(top_node, str);
- }
- catch (error * err) {
- err->context.push_back
- (new line_context(str, (long)in.tellg() - 1,
- "While parsing value expression:"));
- throw err;
- }
- }
-
-public:
- parser_t() : use_lookahead(false) {}
-
- value_expr parse(std::istream& in,
- const flags_t flags = EXPR_PARSE_RELAXED)
- {
- return parse_expr(in, empty_string, *global_scope, flags);
- }
-
- value_expr parse(std::istream& in, scope_t& scope,
- const flags_t flags = EXPR_PARSE_RELAXED)
- {
- return parse_expr(in, empty_string, scope, flags);
- }
-
- value_expr parse(string& str, const flags_t flags = EXPR_PARSE_RELAXED)
- {
- std::istringstream stream(str);
- return parse_expr(stream, str, *global_scope, flags);
- }
-
- value_expr parse(string& str, scope_t& scope,
- const flags_t flags = EXPR_PARSE_RELAXED)
- {
- std::istringstream stream(str);
- return parse_expr(stream, str, scope, flags);
- }
-};
-
-} // namespace expr
-} // namespace ledger
-
-#endif // _PARESXP_H
diff --git a/pyinterp.cc b/pyinterp.cc
index d702f291..07a619fe 100644
--- a/pyinterp.cc
+++ b/pyinterp.cc
@@ -86,9 +86,8 @@ struct python_run
}
};
-python_interpreter_t::python_interpreter_t(expr_t::scope_t& parent)
- : expr_t::symbol_scope_t(parent),
- mmodule(borrowed(PyImport_AddModule("__main__"))),
+python_interpreter_t::python_interpreter_t()
+ : scope_t(), mmodule(borrowed(PyImport_AddModule("__main__"))),
nspace(handle<>(borrowed(PyModule_GetDict(mmodule.get()))))
{
TRACE_CTOR(python_interpreter_t, "expr_t::scope_t&");
diff --git a/pyinterp.h b/pyinterp.h
index 4d3ac0c8..5486eea5 100644
--- a/pyinterp.h
+++ b/pyinterp.h
@@ -39,8 +39,7 @@
namespace ledger {
-class python_interpreter_t
- : public noncopyable, public expr_t::symbol_scope_t
+class python_interpreter_t : public noncopyable, public scope_t
{
boost::python::handle<> mmodule;
@@ -95,8 +94,7 @@ public:
virtual expr_t::ptr_op_t lookup(const string& name) {
if (boost::python::object func = eval(name))
return WRAP_FUNCTOR(functor_t(name, func));
- else
- return expr_t::symbol_scope_t::lookup(name);
+ return expr_t::ptr_op_t();
}
class lambda_t : public functor_t {
diff --git a/report.cc b/report.cc
index ff8000ee..3742e020 100644
--- a/report.cc
+++ b/report.cc
@@ -453,7 +453,7 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
break;
}
- return symbol_scope_t::lookup(name);
+ return session.lookup(name);
}
} // namespace ledger
diff --git a/report.h b/report.h
index 0a1366e1..7c5c6384 100644
--- a/report.h
+++ b/report.h
@@ -81,7 +81,7 @@ namespace ledger {
// says that the formatter should be "flushed" after the entities are
// iterated. This does not happen for the commodities iteration, however.
-class report_t : public symbol_scope_t
+class report_t : public noncopyable, public scope_t
{
report_t();
@@ -134,9 +134,7 @@ public:
session_t& session;
explicit report_t(session_t& _session)
- : symbol_scope_t(downcast<scope_t>(_session)),
-
- head_entries(0),
+ : head_entries(0),
tail_entries(0),
show_collapsed(false),
diff --git a/scope.h b/scope.h
index 4a031104..1abde444 100644
--- a/scope.h
+++ b/scope.h
@@ -37,36 +37,17 @@
namespace ledger {
-class scope_t : public noncopyable
+class scope_t
{
- scope_t();
-
-protected:
- enum type_t {
- CHILD_SCOPE,
- SYMBOL_SCOPE,
- CALL_SCOPE,
- CONTEXT_SCOPE
- } type_;
-
public:
- explicit scope_t(type_t _type) : type_(_type) {
- TRACE_CTOR(scope_t, "type_t");
+ explicit scope_t() {
+ TRACE_CTOR(scope_t, "");
}
virtual ~scope_t() {
TRACE_DTOR(scope_t);
}
- const type_t type() const {
- return type_;
- }
-
- void define(const string& name, const value_t& val) {
- define(name, expr_t::op_t::wrap_value(val));
- }
- void define(const string& name, const function_t& func) {
- define(name, expr_t::op_t::wrap_functor(func));
- }
+ virtual expr_t::ptr_op_t lookup(const string& name) = 0;
value_t resolve(const string& name) {
expr_t::ptr_op_t definition = lookup(name);
@@ -75,81 +56,29 @@ public:
else
return NULL_VALUE;
}
-
- virtual void define(const string& name, expr_t::ptr_op_t def) = 0;
- virtual expr_t::ptr_op_t lookup(const string& name) = 0;
-
-protected:
- virtual optional<scope_t&> find_scope(const type_t _type,
- bool skip_this = false) = 0;
- virtual optional<scope_t&> find_first_scope(const type_t _type1,
- const type_t _type2,
- bool skip_this = false) = 0;
- template <typename T>
- T& find_scope(bool skip_this = false) {
- assert(false);
- }
- template <typename T>
- optional<T&> maybe_find_scope(bool skip_this = false) {
- assert(false);
- }
-
- friend class child_scope_t;
- friend class expr_t::op_t;
};
-class child_scope_t : public scope_t
+class child_scope_t : public noncopyable, public scope_t
{
scope_t * parent;
- child_scope_t();
-
public:
- explicit child_scope_t(type_t _type = CHILD_SCOPE)
- : scope_t(_type), parent(NULL) {
- TRACE_CTOR(child_scope_t, "type_t");
+ explicit child_scope_t() : parent(NULL) {
+ TRACE_CTOR(child_scope_t, "");
}
- explicit child_scope_t(scope_t& _parent, type_t _type = CHILD_SCOPE)
- : scope_t(_type), parent(&_parent) {
- TRACE_CTOR(child_scope_t, "scope_t&, type_t");
+ explicit child_scope_t(scope_t& _parent)
+ : parent(&_parent) {
+ TRACE_CTOR(child_scope_t, "scope_t&");
}
virtual ~child_scope_t() {
TRACE_DTOR(child_scope_t);
}
- virtual void define(const string& name, expr_t::ptr_op_t def) {
- if (parent)
- parent->define(name, def);
- }
virtual expr_t::ptr_op_t lookup(const string& name) {
if (parent)
return parent->lookup(name);
return expr_t::ptr_op_t();
}
-
-protected:
- 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;
-
- ptr = polymorphic_downcast<child_scope_t *>(ptr)->parent;
- }
- return none;
- }
-
- virtual optional<scope_t&> find_first_scope(const type_t _type1,
- const type_t _type2,
- bool skip_this = false) {
- for (scope_t * ptr = (skip_this ? parent : this); ptr; ) {
- if (ptr->type() == _type1 || ptr->type() == _type2)
- return *ptr;
-
- ptr = polymorphic_downcast<child_scope_t *>(ptr)->parent;
- }
- return none;
- }
};
class symbol_scope_t : public child_scope_t
@@ -159,12 +88,10 @@ class symbol_scope_t : public child_scope_t
symbol_map symbols;
public:
- explicit symbol_scope_t()
- : child_scope_t(SYMBOL_SCOPE) {
+ explicit symbol_scope_t() {
TRACE_CTOR(symbol_scope_t, "");
}
- explicit symbol_scope_t(scope_t& _parent)
- : child_scope_t(_parent, SYMBOL_SCOPE) {
+ explicit symbol_scope_t(scope_t& _parent) : child_scope_t(_parent) {
TRACE_CTOR(symbol_scope_t, "scope_t&");
}
virtual ~symbol_scope_t() {
@@ -172,13 +99,13 @@ public:
}
void define(const string& name, const value_t& val) {
- scope_t::define(name, val);
+ define(name, expr_t::op_t::wrap_value(val));
}
void define(const string& name, const function_t& func) {
- scope_t::define(name, func);
+ define(name, expr_t::op_t::wrap_functor(func));
}
-
virtual void define(const string& name, expr_t::ptr_op_t def);
+
virtual expr_t::ptr_op_t lookup(const string& name);
};
@@ -189,8 +116,7 @@ class call_scope_t : public child_scope_t
call_scope_t();
public:
- explicit call_scope_t(scope_t& _parent)
- : child_scope_t(_parent, CALL_SCOPE) {
+ explicit call_scope_t(scope_t& _parent) : child_scope_t(_parent) {
TRACE_CTOR(call_scope_t, "scope_t&");
}
virtual ~call_scope_t() {
@@ -250,124 +176,6 @@ public:
T * operator->() { return value; }
};
-#if 0
-class context_scope_t : public child_scope_t
-{
-public:
- value_t current_element;
- std::size_t element_index;
- std::size_t sequence_size;
-
- explicit context_scope_t(scope_t& _parent,
- const value_t& _element = NULL_VALUE,
- const std::size_t _element_index = 0,
- const std::size_t _sequence_size = 0)
- : child_scope_t(_parent, CONTEXT_SCOPE), current_element(_element),
- element_index(_element_index), sequence_size(_sequence_size)
- {
- TRACE_CTOR(expr::context_scope_t, "scope_t&, const value_t&, ...");
- }
- virtual ~context_scope_t() {
- TRACE_DTOR(expr::context_scope_t);
- }
-
- const std::size_t index() const {
- return element_index;
- }
- const std::size_t size() const {
- return sequence_size;
- }
-
- value_t& value() {
- return current_element;
- }
-};
-
-struct context_t
-{
- const entry_t * entry() {
- return NULL;
- }
- const transaction_t * xact() {
- return NULL;
- }
- const account_t * account() {
- return NULL;
- }
-};
-
-struct entry_context_t : public context_t
-{
- const entry_t * entry_;
-
- const entry_t * entry() {
- return entry_;
- }
-};
-
-struct xact_context_t : public context_t
-{
- const transaction_t * xact_;
-
- const entry_t * entry() {
- return xact_->entry;
- }
- const transaction_t * xact() {
- return xact_;
- }
- const account_t * account() {
- return xact_->account;
- }
-};
-
-struct account_context_t : public context_t
-{
- const account_t * account_;
-
- const account_t * account() {
- return account_;
- }
-};
-#endif
-
-template<>
-inline symbol_scope_t&
-scope_t::find_scope<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 call_scope_t&
-scope_t::find_scope<call_scope_t>(bool skip_this) {
- optional<scope_t&> scope = find_scope(CALL_SCOPE, skip_this);
- assert(scope);
- return downcast<call_scope_t>(*scope);
-}
-
-#if 0
-template<>
-inline context_scope_t&
-scope_t::find_scope<context_scope_t>(bool skip_this) {
- optional<scope_t&> scope = find_scope(CONTEXT_SCOPE, skip_this);
- assert(scope);
- return downcast<context_scope_t>(*scope);
-}
-#endif
-
-#define FIND_SCOPE(scope_type, scope_ref) \
- downcast<scope_t>(scope_ref).find_scope<scope_type>()
-
-#define CALL_SCOPE(scope_ref) \
- FIND_SCOPE(call_scope_t, scope_ref)
-#define SYMBOL_SCOPE(scope_ref) \
- FIND_SCOPE(symbol_scope_t, scope_ref)
-#if 0
-#define CONTEXT_SCOPE(scope_ref) \
- FIND_SCOPE(context_scope_t, scope_ref)
-#endif
-
} // namespace ledger
#endif // _SCOPE_H
diff --git a/session.cc b/session.cc
index 4a565a9e..efb38d89 100644
--- a/session.cc
+++ b/session.cc
@@ -67,9 +67,7 @@ void release_session_context()
}
session_t::session_t()
- : symbol_scope_t(),
-
- register_format
+ : register_format
("%D %-.20P %-.22A %12.67t %!12.80T\n%/"
"%32|%-.22A %12.67t %!12.80T\n"),
wide_register_format
@@ -328,7 +326,7 @@ expr_t::ptr_op_t session_t::lookup(const string& name)
break;
}
- return symbol_scope_t::lookup(name);
+ return expr_t::ptr_op_t();
}
// jww (2007-04-26): All of Ledger should be accessed through a
diff --git a/session.h b/session.h
index 3c1bc89a..944b9ce2 100644
--- a/session.h
+++ b/session.h
@@ -37,7 +37,7 @@
namespace ledger {
-class session_t : public symbol_scope_t
+class session_t : public noncopyable, public scope_t
{
static void initialize();
static void shutdown();
diff --git a/valexpr.cc b/valexpr.cc
deleted file mode 100644
index 5826f420..00000000
--- a/valexpr.cc
+++ /dev/null
@@ -1,1095 +0,0 @@
-/*
- * Copyright (c) 2003-2008, John Wiegley. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * - Neither the name of New Artisans LLC nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "valexpr.h"
-#include "parsexp.h"
-#include "walk.h"
-#include "utils.h"
-
-namespace ledger {
-
-namespace expr {
-
-std::auto_ptr<symbol_scope_t> global_scope;
-datetime_t terminus;
-
-details_t::details_t(const transaction_t& _xact)
- : entry(_xact.entry), xact(&_xact), account(xact_account(_xact))
-{
- TRACE_CTOR(details_t, "const transaction_t&");
-}
-
-bool compute_amount(ptr_op_t expr, amount_t& amt,
- const transaction_t * xact, ptr_op_t context)
-{
- value_t result;
- try {
- expr->compute(result, xact ? details_t(*xact) : details_t(), context);
-
- // Most of the time when computing the amount of a transaction this cast
- // will do nothing at all.
- assert(result.valid());
- result.in_place_cast(value_t::AMOUNT);
- amt = result.as_amount();
- assert(amt.valid());
- }
- catch (error * err) {
- if (err->context.empty() ||
- ! dynamic_cast<valexpr_context *>(err->context.back()))
- err->context.push_back(new valexpr_context(expr));
- error_context * last = err->context.back();
- if (valexpr_context * ctxt = dynamic_cast<valexpr_context *>(last)) {
- ctxt->expr = expr;
- ctxt->desc = "While computing amount expression:";
- }
- throw err;
- }
- return true;
-}
-
-void scope_t::define(const string& name, const value_t& val) {
- define(name, op_t::wrap_value(val));
-}
-
-value_t scope_t::resolve(const string& name) {
- ptr_op_t definition = lookup(name);
- if (definition)
- return definition->calc(*this);
- else
- return NULL_VALUE;
-}
-
-void symbol_scope_t::define(const string& name, ptr_op_t def)
-{
- DEBUG("ledger.xpath.syms", "Defining '" << name << "' = " << def);
-
- std::pair<symbol_map::iterator, bool> result
- = symbols.insert(symbol_map::value_type(name, def));
- if (! result.second) {
- symbol_map::iterator i = symbols.find(name);
- assert(i != symbols.end());
- symbols.erase(i);
-
- std::pair<symbol_map::iterator, bool> result2
- = symbols.insert(symbol_map::value_type(name, def));
- if (! result2.second)
- throw_(compile_error,
- "Redefinition of '" << name << "' in same scope");
- }
-}
-
-namespace {
- int count_leaves(ptr_op_t expr)
- {
- int count = 0;
- if (expr->kind != op_t::O_COMMA) {
- count = 1;
- } else {
- count += count_leaves(expr->left());
- count += count_leaves(expr->right());
- }
- return count;
- }
-
- ptr_op_t reduce_leaves(ptr_op_t expr, const details_t& details,
- ptr_op_t context)
- {
- if (! expr)
- return NULL;
-
- value_expr temp;
-
- if (expr->kind != op_t::O_COMMA) {
- if (expr->kind < op_t::TERMINALS) {
- temp.reset(expr);
- } else {
- temp.reset(new op_t(op_t::VALUE));
- temp->set_value(NULL_VALUE);
- expr->compute(temp->as_value_lval(), details, context);
- }
- } else {
- temp.reset(new op_t(op_t::O_COMMA));
- temp->set_left(reduce_leaves(expr->left(), details, context));
- temp->set_right(reduce_leaves(expr->right(), details, context));
- }
- return temp.release();
- }
-
- ptr_op_t find_leaf(ptr_op_t context, int goal, long& found)
- {
- if (! context)
- return NULL;
-
- if (context->kind != op_t::O_COMMA) {
- if (goal == found++)
- return context;
- } else {
- ptr_op_t expr = find_leaf(context->left(), goal, found);
- if (expr)
- return expr;
- expr = find_leaf(context->right(), goal, found);
- if (expr)
- return expr;
- }
- return NULL;
- }
-}
-
-value_t get_amount(scope_t& scope)
-{
- assert("I can't get the amount!");
-}
-
-ptr_op_t symbol_scope_t::lookup(const string& name)
-{
- switch (name[0]) {
- case 'a':
- if (name[1] == '\0' || name == "amount")
- return WRAP_FUNCTOR(bind(get_amount, _1));
- break;
- }
-
- symbol_map::const_iterator i = symbols.find(name);
- if (i != symbols.end())
- return (*i).second;
-
- return child_scope_t::lookup(name);
-}
-
-
-void op_t::compute(value_t& result, const details_t& details,
- ptr_op_t context) const
-{
- try {
- switch (kind) {
- case ARG_INDEX:
- throw new compute_error("Cannot directly compute an arg_index");
-
- case VALUE:
- result = as_value();
- break;
-
- case F_NOW:
- result = terminus;
- break;
-
- case AMOUNT:
- if (details.xact) {
- if (transaction_has_xdata(*details.xact) &&
- transaction_xdata_(*details.xact).dflags & TRANSACTION_COMPOUND)
- result = transaction_xdata_(*details.xact).value;
- else
- result = details.xact->amount;
- }
- else if (details.account && account_has_xdata(*details.account)) {
- result = account_xdata(*details.account).value;
- }
- else {
- result = 0L;
- }
- break;
-
- case PRICE:
- if (details.xact) {
- bool set = false;
- if (transaction_has_xdata(*details.xact)) {
- transaction_xdata_t& xdata(transaction_xdata_(*details.xact));
- if (xdata.dflags & TRANSACTION_COMPOUND) {
- result = xdata.value.value();
- set = true;
- }
- }
- if (! set) {
- optional<amount_t> value = details.xact->amount.value();
- if (value)
- result = *value;
- else
- result = 0L;
- }
- }
- else if (details.account && account_has_xdata(*details.account)) {
- result = account_xdata(*details.account).value.value();
- }
- else {
- result = 0L;
- }
- break;
-
- case COST:
- if (details.xact) {
- bool set = false;
- if (transaction_has_xdata(*details.xact)) {
- transaction_xdata_t& xdata(transaction_xdata_(*details.xact));
- if (xdata.dflags & TRANSACTION_COMPOUND) {
- result = xdata.value.cost();
- set = true;
- }
- }
-
- if (! set) {
- if (details.xact->cost)
- result = *details.xact->cost;
- else
- result = details.xact->amount;
- }
- }
- else if (details.account && account_has_xdata(*details.account)) {
- result = account_xdata(*details.account).value.cost();
- }
- else {
- result = 0L;
- }
- break;
-
- case TOTAL:
- if (details.xact && transaction_has_xdata(*details.xact))
- result = transaction_xdata_(*details.xact).total;
- else if (details.account && account_has_xdata(*details.account))
- result = account_xdata(*details.account).total;
- else
- result = 0L;
- break;
- case PRICE_TOTAL:
- if (details.xact && transaction_has_xdata(*details.xact))
- result = transaction_xdata_(*details.xact).total.value();
- else if (details.account && account_has_xdata(*details.account))
- result = account_xdata(*details.account).total.value();
- else
- result = 0L;
- break;
- case COST_TOTAL:
- if (details.xact && transaction_has_xdata(*details.xact))
- result = transaction_xdata_(*details.xact).total.cost();
- else if (details.account && account_has_xdata(*details.account))
- result = account_xdata(*details.account).total.cost();
- else
- result = 0L;
- break;
-
- case VALUE_EXPR:
- if (value_expr::amount_expr.get())
- value_expr::amount_expr->compute(result, details, context);
- else
- result = 0L;
- break;
- case TOTAL_EXPR:
- if (value_expr::total_expr.get())
- value_expr::total_expr->compute(result, details, context);
- else
- result = 0L;
- break;
-
- case DATE:
- if (details.xact && transaction_has_xdata(*details.xact) &&
- is_valid(transaction_xdata_(*details.xact).date))
- result = transaction_xdata_(*details.xact).date;
- else if (details.xact)
- result = details.xact->date();
- else if (details.entry)
- result = details.entry->date();
- else
- result = terminus;
- break;
-
- case ACT_DATE:
- if (details.xact && transaction_has_xdata(*details.xact) &&
- is_valid(transaction_xdata_(*details.xact).date))
- result = transaction_xdata_(*details.xact).date;
- else if (details.xact)
- result = details.xact->actual_date();
- else if (details.entry)
- result = details.entry->actual_date();
- else
- result = terminus;
- break;
-
- case EFF_DATE:
- if (details.xact && transaction_has_xdata(*details.xact) &&
- is_valid(transaction_xdata_(*details.xact).date))
- result = transaction_xdata_(*details.xact).date;
- else if (details.xact)
- result = details.xact->effective_date();
- else if (details.entry)
- result = details.entry->effective_date();
- else
- result = terminus;
- break;
-
- case CLEARED:
- if (details.xact)
- result = details.xact->state == transaction_t::CLEARED;
- else
- result = false;
- break;
- case PENDING:
- if (details.xact)
- result = details.xact->state == transaction_t::PENDING;
- else
- result = false;
- break;
-
- case REAL:
- if (details.xact)
- result = ! (details.xact->has_flags(TRANSACTION_VIRTUAL));
- else
- result = true;
- break;
-
- case ACTUAL:
- if (details.xact)
- result = ! (details.xact->has_flags(TRANSACTION_AUTO));
- else
- result = true;
- break;
-
- case INDEX:
- if (details.xact && transaction_has_xdata(*details.xact))
- result = long(transaction_xdata_(*details.xact).index + 1);
- else if (details.account && account_has_xdata(*details.account))
- result = long(account_xdata(*details.account).count);
- else
- result = 0L;
- break;
-
- case COUNT:
- if (details.xact && transaction_has_xdata(*details.xact))
- result = long(transaction_xdata_(*details.xact).index + 1);
- else if (details.account && account_has_xdata(*details.account))
- result = long(account_xdata(*details.account).total_count);
- else
- result = 0L;
- break;
-
- case DEPTH:
- if (details.account)
- result = long(details.account->depth);
- else
- result = 0L;
- break;
-
- case F_PRICE: {
- long arg_index = 0;
- ptr_op_t expr = find_leaf(context, 0, arg_index);
- expr->compute(result, details, context);
- result = result.value();
- break;
- }
-
- case F_DATE: {
- long arg_index = 0;
- ptr_op_t expr = find_leaf(context, 0, arg_index);
- expr->compute(result, details, context);
- result = result.as_datetime();
- break;
- }
-
- case F_DATECMP: {
- long arg_index = 0;
- ptr_op_t expr = find_leaf(context, 0, arg_index);
- expr->compute(result, details, context);
- result = result.as_datetime();
- if (! result)
- break;
-
- arg_index = 0;
- expr = find_leaf(context, 1, arg_index);
- value_t moment;
- expr->compute(moment, details, context);
- if (moment.is_type(value_t::DATETIME)) {
- result.cast(value_t::INTEGER);
- moment.cast(value_t::INTEGER);
- result -= moment;
- } else {
- throw new compute_error("Invalid date passed to datecmp(value,date)",
- new valexpr_context(expr));
- }
- break;
- }
-
- case F_YEAR:
- case F_MONTH:
- case F_DAY: {
- long arg_index = 0;
- ptr_op_t expr = find_leaf(context, 0, arg_index);
- expr->compute(result, details, context);
-
- if (! result.is_type(value_t::DATETIME))
- throw new compute_error("Invalid date passed to year|month|day(date)",
- new valexpr_context(expr));
-
- const datetime_t& moment(result.as_datetime());
- switch (kind) {
- case F_YEAR:
- result = (long)moment.date().year();
- break;
- case F_MONTH:
- result = (long)moment.date().month();
- break;
- case F_DAY:
- result = (long)moment.date().day();
- break;
- default:
- break;
- }
- break;
- }
-
- case F_ARITH_MEAN: {
- long arg_index = 0;
- ptr_op_t expr = find_leaf(context, 0, arg_index);
- if (details.xact && transaction_has_xdata(*details.xact)) {
- expr->compute(result, details, context);
- result /= amount_t(long(transaction_xdata_(*details.xact).index + 1));
- }
- else if (details.account && account_has_xdata(*details.account) &&
- account_xdata(*details.account).total_count) {
- expr->compute(result, details, context);
- result /= amount_t(long(account_xdata(*details.account).total_count));
- }
- else {
- result = 0L;
- }
- break;
- }
-
- case F_PARENT:
- if (details.account && details.account->parent)
- left()->compute(result, details_t(*details.account->parent), context);
- break;
-
- case F_ABS: {
- long arg_index = 0;
- ptr_op_t expr = find_leaf(context, 0, arg_index);
- expr->compute(result, details, context);
- result.abs();
- break;
- }
-
- case F_ROUND: {
- long arg_index = 0;
- ptr_op_t expr = find_leaf(context, 0, arg_index);
- expr->compute(result, details, context);
- result.round();
- break;
- }
-
- case F_COMMODITY: {
- long arg_index = 0;
- ptr_op_t expr = find_leaf(context, 0, arg_index);
- expr->compute(result, details, context);
- if (! result.is_type(value_t::AMOUNT))
- throw new compute_error("Argument to commodity() must be a commoditized amount",
- new valexpr_context(expr));
- amount_t temp("1");
- temp.set_commodity(result.as_amount().commodity());
- result = temp;
- break;
- }
-
- case F_SET_COMMODITY: {
- long arg_index = 0;
- ptr_op_t expr = find_leaf(context, 0, arg_index);
- value_t temp;
- expr->compute(temp, details, context);
-
- arg_index = 0;
- expr = find_leaf(context, 1, arg_index);
- expr->compute(result, details, context);
- if (! result.is_type(value_t::AMOUNT))
- throw new compute_error
- ("Second argument to set_commodity() must be a commoditized amount",
- new valexpr_context(expr));
- amount_t one("1");
- one.set_commodity(result.as_amount().commodity());
- result = one;
-
- result *= temp;
- break;
- }
-
- case F_QUANTITY: {
- long arg_index = 0;
- ptr_op_t expr = find_leaf(context, 0, arg_index);
- expr->compute(result, details, context);
-
- const balance_t * bal = NULL;
- switch (result.type()) {
- case value_t::BALANCE_PAIR:
- bal = &(result.as_balance_pair().quantity());
- // fall through...
-
- case value_t::BALANCE:
- if (! bal)
- bal = &result.as_balance();
-
- if (bal->amounts.size() < 2) {
- result.cast(value_t::AMOUNT);
- } else {
- value_t temp;
- for (balance_t::amounts_map::const_iterator i = bal->amounts.begin();
- i != bal->amounts.end();
- i++) {
- amount_t x = (*i).second;
- x.clear_commodity();
- temp += x;
- }
- result = temp;
- assert(temp.is_type(value_t::AMOUNT));
- }
- // fall through...
-
- case value_t::AMOUNT:
- result.as_amount_lval().clear_commodity();
- break;
-
- default:
- break;
- }
- break;
- }
-
- case F_CODE_MASK:
- if (details.entry && details.entry->code)
- result = as_mask().match(*details.entry->code);
- else
- result = false;
- break;
-
- case F_PAYEE_MASK:
- if (details.entry)
- result = as_mask().match(details.entry->payee);
- else
- result = false;
- break;
-
- case F_NOTE_MASK:
- if (details.xact && details.xact->note)
- result = as_mask().match(*details.xact->note);
- else
- result = false;
- break;
-
- case F_ACCOUNT_MASK:
- if (details.account)
- result = as_mask().match(details.account->fullname());
- else
- result = false;
- break;
-
- case F_SHORT_ACCOUNT_MASK:
- if (details.account)
- result = as_mask().match(details.account->name);
- else
- result = false;
- break;
-
- case F_COMMODITY_MASK:
- if (details.xact)
- result = as_mask().match(details.xact->amount.commodity().base_symbol());
- else
- result = false;
- break;
-
- case O_ARG: {
- long arg_index = 0;
- assert(left()->kind == ARG_INDEX);
- ptr_op_t expr = find_leaf(context, left()->as_long(), arg_index);
- if (expr)
- expr->compute(result, details, context);
- else
- result = 0L;
- break;
- }
-
- case O_COMMA:
- if (! left())
- throw new compute_error("Comma operator missing left operand",
- new valexpr_context(const_cast<op_t *>(this)));
- if (! right())
- throw new compute_error("Comma operator missing right operand",
- new valexpr_context(const_cast<op_t *>(this)));
- left()->compute(result, details, context);
- right()->compute(result, details, context);
- break;
-
- case O_DEF:
- result = 0L;
- break;
-
- case O_REF: {
- assert(left());
- if (right()) {
- value_expr args(reduce_leaves(right(), details, context));
- left()->compute(result, details, args.get());
- } else {
- left()->compute(result, details, context);
- }
- break;
- }
-
- case F_VALUE: {
- long arg_index = 0;
- ptr_op_t expr = find_leaf(context, 0, arg_index);
- expr->compute(result, details, context);
-
- arg_index = 0;
- expr = find_leaf(context, 1, arg_index);
- value_t moment;
- expr->compute(moment, details, context);
- if (! moment.is_type(value_t::DATETIME))
- throw new compute_error("Invalid date passed to P(value,date)",
- new valexpr_context(expr));
-
- result = result.value(moment.as_datetime());
- break;
- }
-
- case O_NOT:
- left()->compute(result, details, context);
- if (result.strip_annotations())
- result = false;
- else
- result = true;
- break;
-
- case O_QUES: {
- assert(left());
- assert(right());
- assert(right()->kind == O_COL);
- left()->compute(result, details, context);
- if (result.strip_annotations())
- right()->left()->compute(result, details, context);
- else
- right()->right()->compute(result, details, context);
- break;
- }
-
- case O_AND:
- assert(left());
- assert(right());
- left()->compute(result, details, context);
- result = result.strip_annotations();
- if (result)
- right()->compute(result, details, context);
- break;
-
- case O_OR:
- assert(left());
- assert(right());
- left()->compute(result, details, context);
- if (! result.strip_annotations())
- right()->compute(result, details, context);
- break;
-
- case O_NEQ:
- case O_EQ:
- case O_LT:
- case O_LTE:
- case O_GT:
- case O_GTE: {
- assert(left());
- assert(right());
- value_t temp;
- left()->compute(temp, details, context);
- right()->compute(result, details, context);
- switch (kind) {
- case O_NEQ: result = temp != result; break;
- case O_EQ: result = temp == result; break;
- case O_LT: result = temp < result; break;
- case O_LTE: result = temp <= result; break;
- case O_GT: result = temp > result; break;
- case O_GTE: result = temp >= result; break;
- default: assert(false); break;
- }
- break;
- }
-
- case O_NEG:
- assert(left());
- left()->compute(result, details, context);
- result.negate();
- break;
-
- case O_ADD:
- case O_SUB:
- case O_MUL:
- case O_DIV: {
- assert(left());
- assert(right());
- value_t temp;
- right()->compute(temp, details, context);
- left()->compute(result, details, context);
- switch (kind) {
- case O_ADD: result += temp; break;
- case O_SUB: result -= temp; break;
- case O_MUL: result *= temp; break;
- case O_DIV: result /= temp; break;
- default: assert(false); break;
- }
- break;
- }
-
- case O_PERC: {
- assert(left());
- result = "100.0%";
- value_t temp;
- left()->compute(temp, details, context);
- result *= temp;
- break;
- }
-
- case LAST:
- default:
- assert(false);
- break;
- }
- }
- catch (error * err) {
- if (err->context.empty() ||
- ! dynamic_cast<valexpr_context *>(err->context.back()))
- err->context.push_back(new valexpr_context(const_cast<op_t *>(this)));
- throw err;
- }
-}
-
-void valexpr_context::describe(std::ostream& out) const throw()
-{
- if (! expr) {
- out << "valexpr_context expr not set!" << std::endl;
- return;
- }
-
- if (! desc.empty())
- out << desc << std::endl;
-
- out << " ";
-#if 0
- unsigned long start = (long)out.tellp() - 1;
- unsigned long begin;
- unsigned long end;
- bool found = print_value_expr(out, expr, true, error_node, &begin, &end);
- out << std::endl;
- if (found) {
- out << " ";
- for (unsigned int i = 0; i < end - start; i++) {
- if (i >= begin - start)
- out << "^";
- else
- out << " ";
- }
- out << std::endl;
- }
-#endif
-}
-
-ptr_op_t op_t::compile(scope_t& scope)
-{
- switch (kind) {
-#if 0
- case VAR_NAME:
- case FUNC_NAME:
- if (ptr_op_t def = scope.lookup(as_string())) {
-#if 1
- return def;
-#else
- // Aren't definitions compiled when they go in? Would
- // recompiling here really add any benefit?
- return def->compile(scope);
-#endif
- }
- return this;
-#endif
-
- default:
- break;
- }
-
- if (kind < TERMINALS)
- return this;
-
- ptr_op_t lhs(left()->compile(scope));
- ptr_op_t rhs(right() ? right()->compile(scope) : ptr_op_t());
-
- if (lhs == left() && (! rhs || rhs == right()))
- return this;
-
- ptr_op_t intermediate(copy(lhs, rhs));
-
- if (lhs->is_value() && (! rhs || rhs->is_value()))
- return wrap_value(intermediate->calc(scope));
-
- return intermediate;
-}
-
-
-value_t op_t::calc(scope_t& scope)
-{
-#if 0
- bool find_all_nodes = false;
-#endif
-
- switch (kind) {
- case VALUE:
- return as_value();
-
-#if 0
- case VAR_NAME:
- case FUNC_NAME:
- if (ptr_op_t reference = compile(scope)) {
- return reference->calc(scope);
- } else {
- throw_(calc_error, "No " << (kind == VAR_NAME ? "variable" : "function")
- << " named '" << as_string() << "'");
- }
- break;
-#endif
-
- case FUNCTION:
- // This should never be evaluated directly; it only appears as the
- // left node of an O_CALL operator.
- assert(false);
- break;
-
-#if 0
- case O_CALL: {
- call_scope_t call_args(scope);
-
- if (right())
- call_args.set_args(right()->calc(scope));
-
- ptr_op_t func = left();
- string name;
-
- if (func->kind == FUNC_NAME) {
- name = func->as_string();
- func = func->compile(scope);
- }
-
- if (func->kind != FUNCTION)
- throw_(calc_error,
- name.empty() ? string("Attempt to call non-function") :
- (string("Attempt to call unknown function '") + name + "'"));
-
- return func->as_function()(call_args);
- }
-#endif
-
- case ARG_INDEX: {
- call_scope_t& args(CALL_SCOPE(scope));
-
- if (as_long() >= 0 && as_long() < args.size())
- return args[as_long()];
- else
- throw_(calc_error, "Reference to non-existing argument");
- break;
- }
-
-#if 0
- case O_FIND:
- case O_RFIND:
- return select_nodes(scope, left()->calc(scope), right(), kind == O_RFIND);
-
- case O_PRED: {
- value_t values = left()->calc(scope);
-
- if (! values.is_null()) {
- op_predicate pred(right());
-
- if (! values.is_sequence()) {
- context_scope_t value_scope(scope, values, 0, 1);
- if (pred(value_scope))
- return values;
- return NULL_VALUE;
- } else {
- std::size_t index = 0;
- std::size_t size = values.as_sequence().size();
-
- value_t result;
-
- foreach (const value_t& value, values.as_sequence()) {
- context_scope_t value_scope(scope, value, index, size);
- if (pred(value_scope))
- result.push_back(value);
- index++;
- }
- return result;
- }
- }
- break;
- }
-
- case NODE_ID:
- switch (as_name()) {
- case document_t::CURRENT:
- return current_value(scope);
-
- case document_t::PARENT:
- if (optional<parent_node_t&> parent = current_xml_node(scope).parent())
- return &*parent;
- else
- throw_(std::logic_error, "Attempt to access parent of root node");
- break;
-
- case document_t::ROOT:
- return &current_xml_node(scope).document();
-
- case document_t::ALL:
- find_all_nodes = true;
- break;
-
- default:
- break; // pass down to the NODE_NAME case
- }
- // fall through...
-
- case NODE_NAME: {
- node_t& current_node(current_xml_node(scope));
-
- if (current_node.is_parent_node()) {
- const bool have_name_id = kind == NODE_ID;
-
- parent_node_t& parent(current_node.as_parent_node());
-
- value_t result;
- foreach (node_t * child, parent) {
- if (find_all_nodes ||
- ( have_name_id && as_name() == child->name_id()) ||
- (! have_name_id && as_string() == child->name()))
- result.push_back(child);
- }
- return result;
- }
- break;
- }
-
- case ATTR_ID:
- case ATTR_NAME:
- if (optional<value_t&> value =
- kind == ATTR_ID ? current_xml_node(scope).get_attr(as_name()) :
- current_xml_node(scope).get_attr(as_string()))
- return *value;
-
- break;
-#endif
-
- case O_NEQ:
- return left()->calc(scope) != right()->calc(scope);
- case O_EQ:
- return left()->calc(scope) == right()->calc(scope);
- case O_LT:
- return left()->calc(scope) < right()->calc(scope);
- case O_LTE:
- return left()->calc(scope) <= right()->calc(scope);
- case O_GT:
- return left()->calc(scope) > right()->calc(scope);
- case O_GTE:
- return left()->calc(scope) >= right()->calc(scope);
-
- case O_ADD:
- return left()->calc(scope) + right()->calc(scope);
- case O_SUB:
- return left()->calc(scope) - right()->calc(scope);
- case O_MUL:
- return left()->calc(scope) * right()->calc(scope);
- case O_DIV:
- return left()->calc(scope) / right()->calc(scope);
-
- case O_NEG:
- assert(! right());
- return left()->calc(scope).negate();
-
- case O_NOT:
- assert(! right());
- return ! left()->calc(scope);
-
- case O_AND:
- return left()->calc(scope) && right()->calc(scope);
- case O_OR:
- return left()->calc(scope) || right()->calc(scope);
-
-#if 0
- case O_UNION:
-#endif
- case O_COMMA: {
- value_t result(left()->calc(scope));
-
- ptr_op_t next = right();
- while (next) {
- ptr_op_t value_op;
- if (next->kind == O_COMMA /* || next->kind == O_UNION */) {
- value_op = next->left();
- next = next->right();
- } else {
- value_op = next;
- next = NULL;
- }
-
- result.push_back(value_op->calc(scope));
- }
- return result;
- }
-
- case LAST:
- default:
- assert(false);
- break;
- }
-
- return NULL_VALUE;
-}
-
-} // namespace expr
-
-std::auto_ptr<value_expr> value_expr::amount_expr;
-std::auto_ptr<value_expr> value_expr::total_expr;
-std::auto_ptr<expr::parser_t> value_expr::parser;
-
-void value_expr::initialize()
-{
- parser.reset(new expr::parser_t);
-}
-
-void value_expr::shutdown()
-{
- amount_expr.reset();
- total_expr.reset();
- parser.reset();
-}
-
-value_expr::value_expr(const string& _expr_str) : expr_str(_expr_str)
-{
- TRACE_CTOR(value_expr, "const string&");
-
- if (! _expr_str.empty())
- ptr = parser->parse(expr_str).ptr;
-}
-
-} // namespace ledger
diff --git a/valexpr.h b/valexpr.h
deleted file mode 100644
index 7c2a63a1..00000000
--- a/valexpr.h
+++ /dev/null
@@ -1,1007 +0,0 @@
-/*
- * Copyright (c) 2003-2008, John Wiegley. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * - Neither the name of New Artisans LLC nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _VALEXPR_H
-#define _VALEXPR_H
-
-#include "value.h"
-#include "utils.h"
-#include "mask.h"
-
-namespace ledger {
-
-class entry_t;
-class transaction_t;
-class account_t;
-
-namespace expr {
-
-DECLARE_EXCEPTION(error, compile_error);
-DECLARE_EXCEPTION(error, calc_error);
-
-#if 0
-struct context_t
-{
- const entry_t * entry() {
- return NULL;
- }
- const transaction_t * xact() {
- return NULL;
- }
- const account_t * account() {
- return NULL;
- }
-};
-
-struct entry_context_t : public context_t
-{
- const entry_t * entry_;
-
- const entry_t * entry() {
- return entry_;
- }
-};
-
-struct xact_context_t : public context_t
-{
- const transaction_t * xact_;
-
- const entry_t * entry() {
- return xact_->entry;
- }
- const transaction_t * xact() {
- return xact_;
- }
- const account_t * account() {
- return xact_->account;
- }
-};
-
-struct account_context_t : public context_t
-{
- const account_t * account_;
-
- const account_t * account() {
- return account_;
- }
-};
-#endif
-
-struct details_t
-{
- const entry_t * entry;
- const transaction_t * xact;
- const account_t * account;
-
- details_t() : entry(NULL), xact(NULL), account(NULL) {
- TRACE_CTOR(details_t, "");
- }
- details_t(const details_t& other)
- : entry(other.entry),
- xact(other.xact),
- account(other.account) {
- TRACE_CTOR(details_t, "copy");
- }
- details_t(const entry_t& _entry)
- : entry(&_entry), xact(NULL), account(NULL) {
- TRACE_CTOR(details_t, "const entry_t&");
- }
- details_t(const transaction_t& _xact);
- details_t(const account_t& _account)
- : entry(NULL), xact(NULL), account(&_account) {
- TRACE_CTOR(details_t, "const account_t&");
- }
- ~details_t() throw() {
- TRACE_DTOR(details_t);
- }
-};
-
-struct op_t;
-typedef intrusive_ptr<op_t> ptr_op_t;
-
-class call_scope_t;
-
-typedef function<value_t (call_scope_t&)> function_t;
-
-#define MAKE_FUNCTOR(x) expr::op_t::wrap_functor(bind(&x, this, _1))
-#define WRAP_FUNCTOR(x) expr::op_t::wrap_functor(x)
-
-class scope_t : public noncopyable
-{
- scope_t();
-
-public:
- enum type_t {
- CHILD_SCOPE,
- SYMBOL_SCOPE,
- CALL_SCOPE,
- CONTEXT_SCOPE
- } type_;
-
- explicit scope_t(type_t _type) : type_(_type) {
- TRACE_CTOR(scope_t, "type_t");
- }
- virtual ~scope_t() {
- TRACE_DTOR(scope_t);
- }
-
- const type_t type() const {
- return type_;
- }
-
- 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);
-
- virtual optional<scope_t&> find_scope(const type_t _type,
- bool skip_this = false) = 0;
- virtual optional<scope_t&> find_first_scope(const type_t _type1,
- const type_t _type2,
- bool skip_this = false) = 0;
-
- template <typename T>
- T& find_scope(bool skip_this = false) {
- assert(false);
- }
- template <typename T>
- optional<T&> maybe_find_scope(bool skip_this = false) {
- assert(false);
- }
-};
-
-class child_scope_t : public scope_t
-{
- scope_t * parent;
-
- child_scope_t();
-
-public:
- explicit child_scope_t(type_t _type = CHILD_SCOPE)
- : scope_t(_type), parent(NULL) {
- TRACE_CTOR(child_scope_t, "type_t");
- }
- explicit child_scope_t(scope_t& _parent, type_t _type = CHILD_SCOPE)
- : scope_t(_type), parent(&_parent) {
- TRACE_CTOR(child_scope_t, "scope_t&, type_t");
- }
- virtual ~child_scope_t() {
- TRACE_DTOR(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();
- }
-
- 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;
-
- ptr = polymorphic_downcast<child_scope_t *>(ptr)->parent;
- }
- return none;
- }
-
- virtual optional<scope_t&> find_first_scope(const type_t _type1,
- const type_t _type2,
- bool skip_this = false) {
- for (scope_t * ptr = (skip_this ? parent : this); ptr; ) {
- if (ptr->type() == _type1 || ptr->type() == _type2)
- return *ptr;
-
- 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(symbol_scope_t, "");
- }
- explicit symbol_scope_t(scope_t& _parent)
- : child_scope_t(_parent, SYMBOL_SCOPE) {
- TRACE_CTOR(symbol_scope_t, "scope_t&");
- }
- virtual ~symbol_scope_t() {
- TRACE_DTOR(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;
-
- call_scope_t();
-
-public:
- explicit call_scope_t(scope_t& _parent)
- : child_scope_t(_parent, CALL_SCOPE) {
- TRACE_CTOR(call_scope_t, "scope_t&");
- }
- virtual ~call_scope_t() {
- TRACE_DTOR(call_scope_t);
- }
-
- void set_args(const value_t& _args) {
- args = _args;
- }
-
- value_t& value() {
- return args;
- }
-
- value_t& operator[](const unsigned int index) {
- // jww (2008-07-21): exception here if it's out of bounds
- return args[index];
- }
- const value_t& operator[](const unsigned int index) const {
- // jww (2008-07-21): exception here if it's out of bounds
- 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();
- }
-};
-
-template <typename T>
-class var_t : public noncopyable
-{
- T * value;
-
- var_t();
-
-public:
- // jww (2008-07-21): Give a good exception here if we can't find "name"
- var_t(scope_t& scope, const string& name)
- : value(scope.resolve(name).template as_pointer<T>()) {
- TRACE_CTOR(var_t, "scope_t&, const string&");
- }
- var_t(call_scope_t& scope, const unsigned int idx)
- : value(scope[idx].template as_pointer<T>()) {
- TRACE_CTOR(var_t, "call_scope_t&, const unsigned int");
- }
- ~var_t() throw() {
- TRACE_DTOR(var_t);
- }
-
- T& operator *() { return *value; }
- T * operator->() { return value; }
-};
-
-#if 0
-class context_scope_t : public child_scope_t
-{
-public:
- value_t current_element;
- std::size_t element_index;
- std::size_t sequence_size;
-
- explicit context_scope_t(scope_t& _parent,
- const value_t& _element = NULL_VALUE,
- const std::size_t _element_index = 0,
- const std::size_t _sequence_size = 0)
- : child_scope_t(_parent, CONTEXT_SCOPE), current_element(_element),
- element_index(_element_index), sequence_size(_sequence_size)
- {
- TRACE_CTOR(expr::context_scope_t, "scope_t&, const value_t&, ...");
- }
- virtual ~context_scope_t() {
- TRACE_DTOR(expr::context_scope_t);
- }
-
- const std::size_t index() const {
- return element_index;
- }
- const std::size_t size() const {
- return sequence_size;
- }
-
- value_t& value() {
- return current_element;
- }
-};
-#endif
-
-class op_t : public noncopyable
-{
- op_t();
-
-public:
- enum kind_t {
- // Constants
- VALUE,
- MASK,
- ARG_INDEX,
-
- CONSTANTS,
-
- // Item details
- AMOUNT,
- COST,
- PRICE,
- DATE,
- ACT_DATE,
- EFF_DATE,
- CLEARED,
- PENDING,
- REAL,
- ACTUAL,
- INDEX,
- DEPTH,
-
- // Item totals
- COUNT,
- TOTAL,
- COST_TOTAL,
- PRICE_TOTAL,
-
- // Relating to format_t
- VALUE_EXPR,
- TOTAL_EXPR,
-
- // Functions
- FUNCTION,
-
- F_NOW,
- F_ARITH_MEAN,
- F_QUANTITY,
- F_COMMODITY,
- F_SET_COMMODITY,
- F_VALUE,
- F_ABS,
- F_ROUND,
- F_PRICE,
- F_DATE,
- F_DATECMP,
- F_YEAR,
- F_MONTH,
- F_DAY,
-
- BEGIN_MASKS,
- F_CODE_MASK,
- F_PAYEE_MASK,
- F_NOTE_MASK,
- F_ACCOUNT_MASK,
- F_SHORT_ACCOUNT_MASK,
- F_COMMODITY_MASK,
- END_MASKS,
-
- TERMINALS,
-
- F_PARENT,
-
- // Binary operators
- O_NEG,
- O_ADD,
- O_SUB,
- O_MUL,
- O_DIV,
- O_PERC,
- O_NEQ,
- O_EQ,
- O_LT,
- O_LTE,
- O_GT,
- O_GTE,
- O_NOT,
- O_AND,
- O_OR,
- O_QUES,
- O_COL,
- O_COMMA,
- O_DEF,
- O_REF,
- O_ARG,
- O_LOOKUP,
-
- LAST
- };
-
- kind_t kind;
- mutable short refc;
- ptr_op_t left_;
-
- variant<unsigned int, // used by ARG_INDEX and O_ARG
- value_t, // used by constant VALUE
- mask_t, // used by constant MASK
- function_t, // used by terminal FUNCTION
-#if 0
- node_t::nameid_t, // used by NODE_ID and ATTR_ID
-#endif
- ptr_op_t> // used by all binary operators
- data;
-
- explicit op_t(const kind_t _kind) : kind(_kind), refc(0){
- TRACE_CTOR(op_t, "const kind_t");
- }
- ~op_t() {
- TRACE_DTOR(op_t);
- assert(refc == 0);
- }
-
- bool is_long() const {
- return data.type() == typeid(unsigned int);
- }
- unsigned int& as_long_lval() {
- assert(kind == ARG_INDEX || kind == O_ARG);
- return boost::get<unsigned int>(data);
- }
- const unsigned int& as_long() const {
- return const_cast<op_t *>(this)->as_long_lval();
- }
- void set_long(unsigned int val) {
- data = val;
- }
-
- bool is_value() const {
- if (kind == VALUE) {
- assert(data.type() == typeid(value_t));
- return true;
- }
- return false;
- }
- value_t& as_value_lval() {
- assert(is_value());
- value_t& val(boost::get<value_t>(data));
- assert(val.valid());
- return val;
- }
- const value_t& as_value() const {
- return const_cast<op_t *>(this)->as_value_lval();
- }
- void set_value(const value_t& val) {
- assert(val.valid());
- data = val;
- }
-
- bool is_string() const {
- if (kind == VALUE) {
- assert(data.type() == typeid(value_t));
- return boost::get<value_t>(data).is_string();
- }
- return false;
- }
- string& as_string_lval() {
- assert(is_string());
- return boost::get<value_t>(data).as_string_lval();
- }
- const string& as_string() const {
- return const_cast<op_t *>(this)->as_string_lval();
- }
- void set_string(const string& val) {
- data = value_t(val);
- }
-
- bool is_mask() const {
- if (kind > BEGIN_MASKS && kind < END_MASKS) {
- assert(data.type() == typeid(mask_t));
- return true;
- }
- return false;
- }
- mask_t& as_mask_lval() {
- assert(is_mask());
- return boost::get<mask_t>(data);
- }
- const mask_t& as_mask() const {
- return const_cast<op_t *>(this)->as_mask_lval();
- }
- void set_mask(const mask_t& val) {
- data = val;
- }
- void set_mask(const string& expr) {
- data = mask_t(expr);
- }
-
- bool is_function() const {
- return kind == FUNCTION;
- }
- function_t& as_function_lval() {
- assert(kind == FUNCTION);
- return boost::get<function_t>(data);
- }
- const function_t& as_function() const {
- return const_cast<op_t *>(this)->as_function_lval();
- }
- void set_function(const function_t& val) {
- data = val;
- }
-
-#if 0
- bool is_name() const {
- return data.type() == typeid(node_t::nameid_t);
- }
- node_t::nameid_t& as_name_lval() {
- assert(kind == NODE_ID || kind == ATTR_ID);
- return boost::get<node_t::nameid_t>(data);
- }
- const node_t::nameid_t& as_name() const {
- return const_cast<op_t *>(this)->as_name_lval();
- }
- void set_name(const node_t::nameid_t& val) {
- data = val;
- }
-#endif
-
- ptr_op_t& as_op_lval() {
- assert(kind > TERMINALS);
- return boost::get<ptr_op_t>(data);
- }
- const ptr_op_t& as_op() const {
- return const_cast<op_t *>(this)->as_op_lval();
- }
-
- void acquire() const {
- DEBUG("ledger.xpath.memory",
- "Acquiring " << this << ", refc now " << refc + 1);
- assert(refc >= 0);
- refc++;
- }
- void release() const {
- DEBUG("ledger.xpath.memory",
- "Releasing " << this << ", refc now " << refc - 1);
- assert(refc > 0);
- if (--refc == 0)
- checked_delete(this);
- }
-
- ptr_op_t& left() {
- return left_;
- }
- const ptr_op_t& left() const {
- assert(kind > TERMINALS);
- return left_;
- }
- void set_left(const ptr_op_t& expr) {
- assert(kind > TERMINALS);
- left_ = expr;
- }
-
- ptr_op_t& right() {
- assert(kind > TERMINALS);
- return as_op_lval();
- }
- const ptr_op_t& right() const {
- assert(kind > TERMINALS);
- return as_op();
- }
- void set_right(const ptr_op_t& expr) {
- assert(kind > TERMINALS);
- data = expr;
- }
-
- 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);
- }
-
- static ptr_op_t wrap_value(const value_t& val);
- static ptr_op_t wrap_functor(const function_t& fobj);
-
- ptr_op_t compile(scope_t& scope);
- value_t current_value(scope_t& scope);
-#if 0
- node_t& current_xml_node(scope_t& scope);
-#endif
- value_t calc(scope_t& scope);
-
- void compute(value_t& result,
- const details_t& details = details_t(),
- ptr_op_t context = NULL) const;
-
- value_t compute(const details_t& details = details_t(),
- ptr_op_t context = NULL) const {
- value_t temp;
- compute(temp, details, context);
- return temp;
- }
-
- 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;
-
- 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(op_t * op) {
- op->acquire();
- }
- friend inline void intrusive_ptr_release(op_t * op) {
- op->release();
- }
-};
-
-class op_predicate : public noncopyable
-{
- ptr_op_t op;
-
- op_predicate();
-
-public:
- explicit op_predicate(ptr_op_t _op) : op(_op) {
- TRACE_CTOR(op_predicate, "ptr_op_t");
- }
- ~op_predicate() throw() {
- TRACE_DTOR(op_predicate);
- }
- bool operator()(scope_t& scope) {
- return op->calc(scope).to_boolean();
- }
-};
-
-class valexpr_context : public error_context
-{
-public:
- ptr_op_t expr;
- ptr_op_t error_node;
-
- valexpr_context(const ptr_op_t& _expr,
- const string& desc = "") throw()
- : error_context(desc), expr(_expr), error_node(_expr) {}
- virtual ~valexpr_context() throw() {}
-
- virtual void describe(std::ostream& out) const throw();
-};
-
-class compute_error : public error
-{
-public:
- compute_error(const string& reason, error_context * ctxt = NULL) throw()
- : error(reason, ctxt) {}
- virtual ~compute_error() throw() {}
-};
-
-class value_expr_error : public error
-{
-public:
- value_expr_error(const string& reason,
- error_context * ctxt = NULL) throw()
- : error(reason, ctxt) {}
- virtual ~value_expr_error() throw() {}
-};
-
-extern std::auto_ptr<symbol_scope_t> global_scope;
-
-extern datetime_t terminus;
-
-bool compute_amount(const ptr_op_t expr, amount_t& amt,
- const transaction_t * xact,
- const ptr_op_t context = NULL);
-
-//////////////////////////////////////////////////////////////////////
-
-inline void guarded_compute(const ptr_op_t expr,
- value_t& result,
- const details_t& details = details_t(),
- const ptr_op_t context = NULL) {
- try {
- expr->compute(result, details);
- }
- catch (error * err) {
- if (err->context.empty() ||
- ! dynamic_cast<valexpr_context *>(err->context.back()))
- err->context.push_back(new valexpr_context(expr));
- error_context * last = err->context.back();
- if (valexpr_context * ctxt = dynamic_cast<valexpr_context *>(last)) {
- ctxt->expr = expr;
- ctxt->desc = "While computing value expression:";
- }
- throw err;
- }
-}
-
-inline value_t guarded_compute(const ptr_op_t expr,
- const details_t& details = details_t(),
- ptr_op_t context = NULL) {
- value_t temp;
- guarded_compute(expr, temp, details, context);
- return temp;
-}
-
-template<>
-inline symbol_scope_t&
-scope_t::find_scope<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 call_scope_t&
-scope_t::find_scope<call_scope_t>(bool skip_this) {
- optional<scope_t&> scope = find_scope(CALL_SCOPE, skip_this);
- assert(scope);
- return downcast<call_scope_t>(*scope);
-}
-
-#if 0
-template<>
-inline context_scope_t&
-scope_t::find_scope<context_scope_t>(bool skip_this) {
- optional<scope_t&> scope = find_scope(CONTEXT_SCOPE, skip_this);
- assert(scope);
- return downcast<context_scope_t>(*scope);
-}
-#endif
-
-#define FIND_SCOPE(scope_type, scope_ref) \
- downcast<scope_t>(scope_ref).find_scope<scope_type>()
-
-#define CALL_SCOPE(scope_ref) \
- FIND_SCOPE(call_scope_t, scope_ref)
-#define SYMBOL_SCOPE(scope_ref) \
- FIND_SCOPE(symbol_scope_t, scope_ref)
-#if 0
-#define CONTEXT_SCOPE(scope_ref) \
- FIND_SCOPE(context_scope_t, scope_ref)
-#endif
-
-inline ptr_op_t op_t::new_node(kind_t _kind, ptr_op_t _left, ptr_op_t _right) {
- ptr_op_t node(new op_t(_kind));
- node->set_left(_left);
- node->set_right(_right);
- return node;
-}
-
-inline ptr_op_t op_t::wrap_value(const value_t& val) {
- ptr_op_t temp(new op_t(op_t::VALUE));
- temp->set_value(val);
- return temp;
-}
-
-inline ptr_op_t op_t::wrap_functor(const function_t& fobj) {
- ptr_op_t temp(new op_t(op_t::FUNCTION));
- temp->set_function(fobj);
- return temp;
-}
-
-class parser_t;
-
-} // namespace expr
-
-//////////////////////////////////////////////////////////////////////
-
-class value_expr
-{
- expr::ptr_op_t ptr;
-
-public:
- string expr_str;
-
- typedef expr::details_t details_t;
-
- value_expr() {
- TRACE_CTOR(value_expr, "");
- }
-
- value_expr(const string& _expr_str);
- value_expr(const expr::ptr_op_t _ptr, const string& _expr_str = "")
- : ptr(_ptr), expr_str(_expr_str) {
- TRACE_CTOR(value_expr, "const expr::ptr_op_t");
- }
- value_expr(const value_expr& other)
- : ptr(other.ptr), expr_str(other.expr_str) {
- TRACE_CTOR(value_expr, "copy");
- }
- virtual ~value_expr() throw() {
- TRACE_DTOR(value_expr);
- }
-
- value_expr& operator=(const value_expr& _expr) {
- expr_str = _expr.expr_str;
- reset(_expr.get());
- return *this;
- }
- value_expr& operator=(const string& _expr) {
- return *this = value_expr(_expr);
- }
-
- operator bool() const throw() {
- return ptr.get() != NULL;
- }
- operator string() const throw() {
- return expr_str;
- }
- operator const expr::ptr_op_t() const throw() {
- return ptr;
- }
-
- const expr::ptr_op_t operator->() const throw() {
- return ptr;
- }
-
- const expr::ptr_op_t get() const throw() { return ptr; }
- const expr::ptr_op_t release() throw() {
- const expr::ptr_op_t tmp = ptr;
- ptr = expr::ptr_op_t();
- return tmp;
- }
- void reset(const expr::ptr_op_t p = expr::ptr_op_t()) throw() {
- ptr = p;
- }
-
- virtual void compute(value_t& result,
- const details_t& details = details_t(),
- expr::ptr_op_t context = NULL) {
- guarded_compute(ptr, result, details, context);
- }
- virtual value_t compute(const details_t& details = details_t(),
- expr::ptr_op_t context = NULL) {
- value_t temp;
- guarded_compute(ptr, temp, details, context);
- return temp;
- }
-
-#if 0
- void compile(scope_t& scope) {
- if (ptr.get())
- ptr = ptr->compile(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);
- }
-
- path_iterator_t find_all(scope_t& scope) {
- return path_iterator_t(*this, scope);
- }
-
- 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);
- }
-#endif
-
- friend bool print_value_expr(std::ostream& out,
- const expr::ptr_op_t node,
- const expr::ptr_op_t node_to_find,
- unsigned long * start_pos,
- unsigned long * end_pos);
-
- static std::auto_ptr<value_expr> amount_expr;
- static std::auto_ptr<value_expr> total_expr;
- static std::auto_ptr<expr::parser_t> parser;
-
- static void initialize();
- static void shutdown();
-};
-
-typedef value_expr::details_t details_t; // jww (2008-07-20): remove
-
-inline void compute_amount(value_t& result,
- const details_t& details = details_t()) {
- if (value_expr::amount_expr.get())
- value_expr::amount_expr->compute(result, details);
-}
-
-inline value_t compute_amount(const details_t& details = details_t()) {
- if (value_expr::amount_expr.get())
- return value_expr::amount_expr->compute(details);
-}
-
-inline void compute_total(value_t& result,
- const details_t& details = details_t()) {
- if (value_expr::total_expr.get())
- value_expr::total_expr->compute(result, details);
-}
-
-inline value_t compute_total(const details_t& details = details_t()) {
- if (value_expr::total_expr.get())
- return value_expr::total_expr->compute(details);
-}
-
-//////////////////////////////////////////////////////////////////////
-
-template <typename T>
-class item_predicate
-{
-public:
- value_expr predicate;
-
- item_predicate() {
- TRACE_CTOR(item_predicate, "");
- }
- item_predicate(const item_predicate& other) : predicate(other.predicate) {
- TRACE_CTOR(item_predicate, "copy");
- }
- item_predicate(const value_expr& _predicate) : predicate(_predicate) {
- TRACE_CTOR(item_predicate, "const value_expr&");
- }
- item_predicate(const string& _predicate) : predicate(_predicate) {
- TRACE_CTOR(item_predicate, "const string&");
- }
- ~item_predicate() throw() {
- TRACE_DTOR(item_predicate);
- }
-
- bool operator()(const T& item) const {
- return (! predicate ||
- predicate->compute(value_expr::details_t(item)).strip_annotations());
- }
-};
-
-} // namespace ledger
-
-#endif // _VALEXPR_H