diff options
-rw-r--r-- | src/account.cc | 50 | ||||
-rw-r--r-- | src/convert.cc | 8 | ||||
-rw-r--r-- | src/expr.h | 20 | ||||
-rw-r--r-- | src/global.h | 1 | ||||
-rw-r--r-- | src/interactive.cc | 199 | ||||
-rw-r--r-- | src/interactive.h | 164 | ||||
-rw-r--r-- | src/item.cc | 13 | ||||
-rw-r--r-- | src/op.cc | 52 | ||||
-rw-r--r-- | src/op.h | 3 | ||||
-rw-r--r-- | src/option.h | 4 | ||||
-rw-r--r-- | src/parser.cc | 4 | ||||
-rw-r--r-- | src/post.cc | 98 | ||||
-rw-r--r-- | src/pyinterp.cc | 2 | ||||
-rw-r--r-- | src/pyinterp.h | 3 | ||||
-rw-r--r-- | src/report.cc | 218 | ||||
-rw-r--r-- | src/report.h | 53 | ||||
-rw-r--r-- | src/scope.cc | 19 | ||||
-rw-r--r-- | src/scope.h | 333 | ||||
-rw-r--r-- | src/session.cc | 7 | ||||
-rw-r--r-- | src/session.h | 7 | ||||
-rw-r--r-- | src/xact.cc | 25 | ||||
-rw-r--r-- | tools/Makefile.am | 2 |
22 files changed, 533 insertions, 752 deletions
diff --git a/src/account.cc b/src/account.cc index f26b7913..809b6e46 100644 --- a/src/account.cc +++ b/src/account.cc @@ -34,7 +34,6 @@ #include "account.h" #include "post.h" #include "xact.h" -#include "interactive.h" namespace ledger { @@ -189,27 +188,26 @@ std::ostream& operator<<(std::ostream& out, const account_t& account) } namespace { - value_t get_partial_name(call_scope_t& scope) + value_t get_partial_name(call_scope_t& args) { - in_context_t<account_t> env(scope, "&b"); - return string_value(env->partial_name(env.has(0) ? - env.get<bool>(0) : false)); + return string_value(args.context<account_t>() + .partial_name(args.has<bool>(0) && + args.get<bool>(0))); } - value_t get_account(call_scope_t& scope) { // this gets the name - interactive_t args(scope, "&v"); - account_t& account(find_scope<account_t>(scope)); - if (args.has(0)) { + value_t get_account(call_scope_t& args) { // this gets the name + account_t& account(args.context<account_t>()); + if (args.has<string>(0)) { account_t * acct = account.parent; for (; acct && acct->parent; acct = acct->parent) ; - if (scope[0].is_string()) + if (args[0].is_string()) return scope_value(acct->find_account(args.get<string>(0), false)); - else if (scope[0].is_mask()) + else if (args[0].is_mask()) return scope_value(acct->find_account_re(args.get<mask_t>(0).str())); else return NULL_VALUE; } - else if (scope.type_context() == value_t::SCOPE) { + else if (args.type_context() == value_t::SCOPE) { return scope_value(&account); } else { @@ -282,39 +280,35 @@ namespace { } template <value_t (*Func)(account_t&)> - value_t get_wrapper(call_scope_t& scope) { - return (*Func)(find_scope<account_t>(scope)); + value_t get_wrapper(call_scope_t& args) { + return (*Func)(args.context<account_t>()); } value_t get_parent(account_t& account) { return scope_value(account.parent); } - value_t fn_any(call_scope_t& scope) + value_t fn_any(call_scope_t& args) { - interactive_t args(scope, "X&X"); - - account_t& account(find_scope<account_t>(scope)); - expr_t& expr(args.get<expr_t&>(0)); + account_t& account(args.context<account_t>()); + expr_t::ptr_op_t expr(args.get<expr_t::ptr_op_t>(0)); foreach (post_t * p, account.posts) { - bind_scope_t bound_scope(scope, *p); - if (expr.calc(bound_scope).to_boolean()) + bind_scope_t bound_scope(args, *p); + if (expr->calc(bound_scope).to_boolean()) return true; } return false; } - value_t fn_all(call_scope_t& scope) + value_t fn_all(call_scope_t& args) { - interactive_t args(scope, "X&X"); - - account_t& account(find_scope<account_t>(scope)); - expr_t& expr(args.get<expr_t&>(0)); + account_t& account(args.context<account_t>()); + expr_t::ptr_op_t expr(args.get<expr_t::ptr_op_t>(0)); foreach (post_t * p, account.posts) { - bind_scope_t bound_scope(scope, *p); - if (! expr.calc(bound_scope).to_boolean()) + bind_scope_t bound_scope(args, *p); + if (! expr->calc(bound_scope).to_boolean()) return false; } return true; diff --git a/src/convert.cc b/src/convert.cc index f33a6b2e..d7ee52b7 100644 --- a/src/convert.cc +++ b/src/convert.cc @@ -34,7 +34,6 @@ #include "convert.h" #include "csv.h" #include "scope.h" -#include "interactive.h" #include "iterators.h" #include "report.h" #include "xact.h" @@ -43,11 +42,10 @@ namespace ledger { -value_t convert_command(call_scope_t& scope) +value_t convert_command(call_scope_t& args) { - interactive_t args(scope, "s"); - report_t& report(find_scope<report_t>(scope)); - journal_t& journal(*report.session.journal.get()); + report_t& report(args.context<report_t>()); + journal_t& journal(*report.session.journal.get()); string bucket_name; if (report.HANDLED(account_)) @@ -58,7 +58,6 @@ public: class op_t; typedef intrusive_ptr<op_t> ptr_op_t; typedef intrusive_ptr<const op_t> const_ptr_op_t; - protected: ptr_op_t ptr; @@ -142,6 +141,25 @@ private: #endif // HAVE_BOOST_SERIALIZATION }; +/** + * Dealing with expr pointers tucked into value objects. + */ +inline bool is_expr(const value_t& val) { + return val.is_any() && val.as_any().type() == typeid(expr_t::ptr_op_t); +} +inline expr_t::ptr_op_t as_expr(const value_t& val) { + VERIFY(val.is_any()); + return val.as_any<expr_t::ptr_op_t>(); +} +inline void set_expr(value_t& val, expr_t::ptr_op_t op) { + val.set_any(op); +} +inline value_t expr_value(expr_t::ptr_op_t op) { + value_t temp; + temp.set_any(op); + return temp; +} + } // namespace ledger #endif // _EXPR_H diff --git a/src/global.h b/src/global.h index 87f2495a..115183a5 100644 --- a/src/global.h +++ b/src/global.h @@ -38,7 +38,6 @@ #ifndef _GLOBAL_H #define _GLOBAL_H -#include "interactive.h" #include "option.h" #include "report.h" diff --git a/src/interactive.cc b/src/interactive.cc deleted file mode 100644 index b95057dd..00000000 --- a/src/interactive.cc +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (c) 2003-2010, 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 <system.hh> - -#include "interactive.h" - -namespace ledger { - -void interactive_t::verify_arguments() const -{ - value_t::sequence_t::const_iterator i; - - const char * p = spec.c_str(); - const char * label = _("unknown"); - bool wrong_arg = false; - bool dont_skip = false; - bool optional = *p == '&'; - bool exit_loop = *p == '*'; - std::size_t offset = 1; - bool is_seq = args.value().is_sequence(); - const value_t * next_arg = NULL; - string vlabel; - - if (is_seq) { - i = args.begin(); - if (i != args.end()) - next_arg = &(*i); - } - else if (! args.value().is_null()) { - next_arg = &args.value(); - } - - for (; ! wrong_arg && ! exit_loop && *p && next_arg; p++) { - DEBUG("interactive.verify", - "Want " << *p << " got: " << next_arg->label()); - - wrong_arg = false; - switch (*p) { - case 'a': - label = _("an amount"); - wrong_arg = (! next_arg->is_long() && - ! next_arg->is_amount() && - ! next_arg->is_balance()); - break; - case 'b': - label = _("a boolean"); - wrong_arg = false; // booleans are converted - break; - case 'd': - label = _("a date"); - wrong_arg = (! next_arg->is_date() && - ! next_arg->is_datetime()); - break; - case 't': - label = _("a date/time"); - wrong_arg = (! next_arg->is_date() && - ! next_arg->is_datetime()); - break; - case 'i': - case 'l': - label = _("an integer"); - if (next_arg->is_long() || - (next_arg->is_amount() && - ! next_arg->as_amount().has_commodity())) { - wrong_arg = false; - } - else if (next_arg->is_string()) { - wrong_arg = false; - for (const char * q = next_arg->as_string().c_str(); *q; q++) { - if (! std::isdigit(*q) && *q != '-') { - wrong_arg = true; - break; - } - } - } - else { - wrong_arg = true; - } - break; - case 'm': - label = _("a regex"); - wrong_arg = ! next_arg->is_mask(); - break; - case 's': - label = _("a string"); - wrong_arg = ! next_arg->is_string(); - break; - case 'v': - label = _("any value"); - wrong_arg = false; - break; - case '^': - label = _("a scope"); - wrong_arg = ! next_arg->is_scope(); - break; - case 'X': - label = _("an expression"); - wrong_arg = ! next_arg->is_expr(); - break; - case 'S': - label = _("a sequence"); - wrong_arg = false; - break; - case '&': - optional = true; - dont_skip = true; - break; - case '*': - optional = true; - exit_loop = true; - dont_skip = true; - break; - } - if (wrong_arg && optional && next_arg->is_null()) - wrong_arg = false; - - if (wrong_arg) { - vlabel = next_arg->label(); - break; - } - - if (! dont_skip) { - if (is_seq) { - if (++i != args.end()) { - next_arg = &(*i); - offset++; - } else { - next_arg = NULL; - } - } else { - next_arg = NULL; - } - } - dont_skip = false; - } - - if (*p == '&' || *p == '*') - optional = true; - - DEBUG("interactive.verify", "Remaining args are optional"); - - if (wrong_arg) { - throw_(calc_error, _("Expected %1 for argument %2, but received %3") - << label << offset << vlabel); - } - else if (*p && ! optional && ! next_arg) { - throw_(calc_error, _("Too few arguments to function")); - } - else if (! *p && next_arg) { - throw_(calc_error, _("Too many arguments to function")); - } -} - -string join_args(call_scope_t& args) -{ - std::ostringstream buf; - bool first = true; - - for (std::size_t i = 0; i < args.size(); i++) { - if (first) - first = false; - else - buf << ' '; - buf << args[i]; - } - - return buf.str(); -} - -} // namespace ledger diff --git a/src/interactive.h b/src/interactive.h deleted file mode 100644 index 04c23ae5..00000000 --- a/src/interactive.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2003-2010, 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. - */ - -/** - * @addtogroup expr - */ - -/** - * @file interactive.h - * @author John Wiegley - * - * @ingroup expr - */ -#ifndef _INTERACTIVE_H -#define _INTERACTIVE_H - -#include "scope.h" - -namespace ledger { - -class interactive_t : public noncopyable -{ - call_scope_t& args; - string spec; - -public: - explicit interactive_t(call_scope_t& _args, const string& _spec = "") - : args(_args), spec(_spec) { - TRACE_CTOR(interactive_t, "call_scope_t&, const string&"); - verify_arguments(); - } - virtual ~interactive_t() { - TRACE_DTOR(interactive_t); - } - - void verify_arguments() const; - - bool has(std::size_t index) const { - if (index < args.size() && ! args[index].is_null()) - return true; - return false; - } - - value_t& value_at(std::size_t index) { - assert(has(index)); - return args[index]; - } - - template <typename T> - T get(std::size_t index); -}; - -template <> -inline bool interactive_t::get<bool>(std::size_t index) { - return value_at(index).to_boolean(); -} -template <> -inline int interactive_t::get<int>(std::size_t index) { - return value_at(index).to_int(); -} -template <> -inline long interactive_t::get<long>(std::size_t index) { - return value_at(index).to_long(); -} -template <> -inline amount_t interactive_t::get<amount_t>(std::size_t index) { - return value_at(index).to_amount(); -} -template <> -inline string interactive_t::get<string>(std::size_t index) { - return value_at(index).to_string(); -} -template <> -inline mask_t interactive_t::get<mask_t>(std::size_t index) { - return value_at(index).to_mask(); -} -template <> -inline date_t interactive_t::get<date_t>(std::size_t index) { - return value_at(index).to_date(); -} -template <> -inline datetime_t interactive_t::get<datetime_t>(std::size_t index) { - return value_at(index).to_datetime(); -} -template <> -inline value_t::sequence_t& -interactive_t::get<value_t::sequence_t&>(std::size_t index) { - return value_at(index).as_sequence_lval(); -} -template <> -inline const value_t::sequence_t& -interactive_t::get<const value_t::sequence_t&>(std::size_t index) { - return value_at(index).as_sequence(); -} -template <> -inline scope_t * -interactive_t::get<scope_t *>(std::size_t index) { - return value_at(index).as_scope(); -} -template <> -inline expr_t& interactive_t::get<expr_t&>(std::size_t index) { - return value_at(index).as_expr_lval(); -} -template <> -inline const expr_t& interactive_t::get<const expr_t&>(std::size_t index) { - return value_at(index).as_expr(); -} - -template <typename T> -class in_context_t : public interactive_t -{ - T& context; - -public: - explicit in_context_t(call_scope_t& args, const string& spec) - : interactive_t(args, spec), context(find_scope<T>(args)) { - TRACE_CTOR(in_context_t, "call_scope_t&, const string&"); - } - virtual ~in_context_t() { - TRACE_DTOR(in_context_t); - } - - T& operator *() { - return context; - } - T * operator->() { - return &context; - } -}; - -string join_args(call_scope_t& args); - -} // namespace ledger - -#endif // _INTERACTIVE_H - diff --git a/src/item.cc b/src/item.cc index f59c9e29..f0273e59 100644 --- a/src/item.cc +++ b/src/item.cc @@ -32,7 +32,6 @@ #include <system.hh> #include "item.h" -#include "interactive.h" namespace ledger { @@ -256,9 +255,9 @@ namespace { if (args.size() == 1) { if (args[0].is_string()) - return item.has_tag(args[0].as_string()); + return item.has_tag(args.get<string>(0)); else if (args[0].is_mask()) - return item.has_tag(args[0].as_mask()); + return item.has_tag(args.get<mask_t>(0)); else throw_(std::runtime_error, _("Expected string or mask for argument 1, but received %1") @@ -266,7 +265,7 @@ namespace { } else if (args.size() == 2) { if (args[0].is_mask() && args[1].is_mask()) - return item.has_tag(args[0].to_mask(), args[1].to_mask()); + return item.has_tag(args.get<mask_t>(0), args.get<mask_t>(1)); else throw_(std::runtime_error, _("Expected masks for arguments 1 and 2, but received %1 and %2") @@ -288,9 +287,9 @@ namespace { if (args.size() == 1) { if (args[0].is_string()) - val = item.get_tag(args[0].as_string()); + val = item.get_tag(args.get<string>(0)); else if (args[0].is_mask()) - val = item.get_tag(args[0].as_mask()); + val = item.get_tag(args.get<mask_t>(0)); else throw_(std::runtime_error, _("Expected string or mask for argument 1, but received %1") @@ -298,7 +297,7 @@ namespace { } else if (args.size() == 2) { if (args[0].is_mask() && args[1].is_mask()) - val = item.get_tag(args[0].to_mask(), args[1].to_mask()); + val = item.get_tag(args.get<mask_t>(0), args.get<mask_t>(1)); else throw_(std::runtime_error, _("Expected masks for arguments 1 and 2, but received %1 and %2") @@ -39,15 +39,11 @@ namespace ledger { namespace { - value_t split_cons_expr(expr_t::ptr_op_t op, - scope_t& scope, - std::vector<expr_t>& exprs) + value_t split_cons_expr(expr_t::ptr_op_t op) { - value_t seq; - if (op->kind == expr_t::op_t::O_CONS) { - exprs.push_back(expr_t(op->left(), &scope)); - seq.push_back(value_t(exprs.back())); + value_t seq; + seq.push_back(expr_value(op->left())); expr_t::ptr_op_t next = op->right(); while (next) { @@ -59,19 +55,18 @@ namespace { value_op = next; next = NULL; } - exprs.push_back(expr_t(value_op, &scope)); - seq.push_back(value_t(exprs.back())); + seq.push_back(expr_value(value_op)); } + return seq; } else { - exprs.push_back(expr_t(op, &scope)); - seq.push_back(value_t(exprs.back())); + return expr_value(op); } - return seq; } - void check_type_context(scope_t& scope, value_t& result) + inline void check_type_context(scope_t& scope, value_t& result) { - if (scope.type_context() != value_t::VOID && + if (scope.type_required() && + scope.type_context() != value_t::VOID && result.type() != scope.type_context()) { throw_(calc_error, _("Expected return of %1, but received %2") @@ -162,7 +157,7 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth) // Evaluating an identifier is the same as calling its definition // directly, so we create an empty call_scope_t to reflect the scope for // this implicit call. - call_scope_t call_args(scope, scope.type_context()); + call_scope_t call_args(scope, scope.type_context(), scope.type_required()); result = left()->compile(call_args, depth + 1) ->calc(call_args, locus, depth + 1); check_type_context(scope, result); @@ -173,7 +168,7 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth) // Evaluating a FUNCTION is the same as calling it directly; this happens // when certain functions-that-look-like-variables (such as "amount") are // resolved. - call_scope_t call_args(scope, scope.type_context()); + call_scope_t call_args(scope, scope.type_context(), scope.type_required()); result = as_function()(call_args); check_type_context(scope, result); #if defined(DEBUG_ON) @@ -239,24 +234,11 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth) break; } - case O_CALL: - case O_EXPAND: { - call_scope_t call_args(scope, scope.type_context()); - // When evaluating a macro call, these expressions have to live beyond the - // call to calc() below. - optional<std::vector<expr_t> > args_expr; - - if (has_right()) { - if (kind == O_CALL) { - call_args.set_args(right()->calc(scope, locus, depth + 1)); - } else { - // macros defer calculation to the callee - args_expr = std::vector<expr_t>(); - call_args.set_args(split_cons_expr(right()->kind == O_SEQ ? - right()->left() : right(), - scope, *args_expr)); - } - } + case O_CALL: { + call_scope_t call_args(scope, scope.type_context(), scope.type_required()); + if (has_right()) + call_args.set_args(split_cons_expr(right()->kind == O_SEQ ? + right()->left() : right())); ptr_op_t func = left(); const string& name(func->as_ident()); @@ -656,7 +638,6 @@ bool expr_t::op_t::print(std::ostream& out, const context_t& context) const break; case O_CALL: - case O_EXPAND: if (left() && left()->print(out, context)) found = true; if (has_right()) { @@ -728,7 +709,6 @@ void expr_t::op_t::dump(std::ostream& out, const int depth) const case O_DEFINE: out << "O_DEFINE"; break; case O_LOOKUP: out << "O_LOOKUP"; break; case O_CALL: out << "O_CALL"; break; - case O_EXPAND: out << "O_EXPAND"; break; case O_MATCH: out << "O_MATCH"; break; case O_NOT: out << "O_NOT"; break; @@ -105,7 +105,6 @@ public: O_DEFINE, O_LOOKUP, O_CALL, - O_EXPAND, O_MATCH, BINARY_OPERATORS, @@ -278,7 +277,7 @@ public: }; bool print(std::ostream& out, const context_t& context = context_t()) const; - void dump(std::ostream& out, const int depth) const; + void dump(std::ostream& out, const int depth = 0) const; static ptr_op_t wrap_value(const value_t& val); static ptr_op_t wrap_functor(const expr_t::func_t& fobj); diff --git a/src/option.h b/src/option.h index 91ff26f9..e2a4a839 100644 --- a/src/option.h +++ b/src/option.h @@ -167,7 +167,7 @@ public: throw_(std::runtime_error, _("To many arguments provided for %1") << desc()); else if (! args[0].is_string()) throw_(std::runtime_error, _("Context argument for %1 not a string") << desc()); - on_with(args[0].as_string(), args[1]); + on_with(args.get<string>(0), args[1]); } else if (args.size() < 1) { throw_(std::runtime_error, _("No argument provided for %1") << desc()); @@ -176,7 +176,7 @@ public: throw_(std::runtime_error, _("Context argument for %1 not a string") << desc()); } else { - on_only(args[0].as_string()); + on_only(args.get<string>(0)); } handler_thunk(args); diff --git a/src/parser.cc b/src/parser.cc index db989f07..a15775d1 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -59,8 +59,6 @@ expr_t::parser_t::parse_value_term(std::istream& in, tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT)); if (tok.kind == token_t::LPAREN) { op_t::kind_t kind = op_t::O_CALL; - if (ident == "any" || ident == "all") - kind = op_t::O_EXPAND; ptr_op_t call_node(new op_t(kind)); call_node->set_left(node); node = call_node; @@ -81,7 +79,7 @@ expr_t::parser_t::parse_value_term(std::istream& in, .minus_flags(PARSE_SINGLE)); tok = next_token(in, tflags, ')'); - if (node->kind == op_t::O_CONS) { + if (node && node->kind == op_t::O_CONS) { ptr_op_t prev(node); node = new op_t(op_t::O_SEQ); node->set_left(prev); diff --git a/src/post.cc b/src/post.cc index d4a16122..bbf43227 100644 --- a/src/post.cc +++ b/src/post.cc @@ -35,7 +35,6 @@ #include "xact.h" #include "account.h" #include "journal.h" -#include "interactive.h" #include "format.h" namespace ledger { @@ -197,15 +196,13 @@ namespace { return post.has_xdata() && post.xdata().has_flags(POST_EXT_DIRECT_AMT); } - value_t get_commodity(call_scope_t& scope) + value_t get_commodity(call_scope_t& args) { - in_context_t<post_t> env(scope, "&v"); - if (env.has(0)) { - return string_value(env.value_at(0).to_amount().commodity().symbol()); + if (args.has<amount_t>(0)) { + return string_value(args.get<amount_t>(0).commodity().symbol()); } else { - post_t& post(find_scope<post_t>(scope)); - if (post.has_xdata() && - post.xdata().has_flags(POST_EXT_COMPOUND)) + post_t& post(args.context<post_t>()); + if (post.has_xdata() && post.xdata().has_flags(POST_EXT_COMPOUND)) return string_value(post.xdata().compound_value.to_amount() .commodity().symbol()); else @@ -254,48 +251,48 @@ namespace { return 1L; } - value_t get_account(call_scope_t& scope) + value_t get_account(call_scope_t& args) { - in_context_t<post_t> env(scope, "&v"); - account_t& account(*env->reported_account()); - string name; + post_t& post(args.context<post_t>()); + account_t& account(*post.reported_account()); + string name; - if (env.has(0)) { - if (env.value_at(0).is_long()) { - if (env.get<long>(0) > 2) + if (args.has(0)) { + if (args[0].is_long()) { + if (args.get<long>(0) > 2) name = format_t::truncate(account.fullname(), - env.get<long>(0) - 2, + args.get<long>(0) - 2, 2 /* account_abbrev_length */); else name = account.fullname(); } else { - account_t * account = NULL; - account_t * master = env->account; + account_t * acct = NULL; + account_t * master = &account; while (master->parent) master = master->parent; - if (env.value_at(0).is_string()) { - name = env.get<string>(0); - account = master->find_account(name, false); + if (args[0].is_string()) { + name = args.get<string>(0); + acct = master->find_account(name, false); } - else if (env.value_at(0).is_mask()) { - name = env.get<mask_t>(0).str(); - account = master->find_account_re(name); + else if (args[0].is_mask()) { + name = args.get<mask_t>(0).str(); + acct = master->find_account_re(name); } else { throw_(std::runtime_error, _("Expected string or mask for argument 1, but received %1") - << env.value_at(0).label()); + << args[0].label()); } - if (! account) + if (! acct) throw_(std::runtime_error, - _("Could not find an account matching ") << env.value_at(0)); + _("Could not find an account matching ") << args[0]); else - return value_t(static_cast<scope_t *>(account)); + return value_t(static_cast<scope_t *>(acct)); } } - else if (scope.type_context() == value_t::SCOPE) { + else if (args.type_context() == value_t::SCOPE) { return scope_value(&account); } else { @@ -304,14 +301,13 @@ namespace { return string_value(name); } - value_t get_display_account(call_scope_t& scope) + value_t get_display_account(call_scope_t& args) { - in_context_t<post_t> env(scope, "&v"); - - value_t acct = get_account(scope); + post_t& post(args.context<post_t>()); + value_t acct = get_account(args); if (acct.is_string()) { - if (env->has_flags(POST_VIRTUAL)) { - if (env->must_balance()) + if (post.has_flags(POST_VIRTUAL)) { + if (post.must_balance()) acct = string_value(string("[") + acct.as_string() + "]"); else acct = string_value(string("(") + acct.as_string() + ")"); @@ -349,44 +345,40 @@ namespace { return (*Func)(find_scope<post_t>(scope)); } - value_t fn_any(call_scope_t& scope) + value_t fn_any(call_scope_t& args) { - interactive_t args(scope, "X&X"); - - post_t& post(find_scope<post_t>(scope)); - expr_t& expr(args.get<expr_t&>(0)); + post_t& post(args.context<post_t>()); + expr_t::ptr_op_t expr(args.get<expr_t::ptr_op_t>(0)); foreach (post_t * p, post.xact->posts) { - bind_scope_t bound_scope(scope, *p); - if (p == &post && args.has(1) && - ! args.get<expr_t&>(1).calc(bound_scope).to_boolean()) { + bind_scope_t bound_scope(args, *p); + if (p == &post && args.has<expr_t::ptr_op_t>(1) && + ! args.get<expr_t::ptr_op_t>(1)->calc(bound_scope).to_boolean()) { // If the user specifies any(EXPR, false), and the context is a // posting, then that posting isn't considered by the test. ; // skip it } - else if (expr.calc(bound_scope).to_boolean()) { + else if (expr->calc(bound_scope).to_boolean()) { return true; } } return false; } - value_t fn_all(call_scope_t& scope) + value_t fn_all(call_scope_t& args) { - interactive_t args(scope, "X&X"); - - post_t& post(find_scope<post_t>(scope)); - expr_t& expr(args.get<expr_t&>(0)); + post_t& post(args.context<post_t>()); + expr_t::ptr_op_t expr(args.get<expr_t::ptr_op_t>(0)); foreach (post_t * p, post.xact->posts) { - bind_scope_t bound_scope(scope, *p); - if (p == &post && args.has(1) && - ! args.get<expr_t&>(1).calc(bound_scope).to_boolean()) { + bind_scope_t bound_scope(args, *p); + if (p == &post && args.has<expr_t::ptr_op_t>(1) && + ! args.get<expr_t::ptr_op_t>(1)->calc(bound_scope).to_boolean()) { // If the user specifies any(EXPR, false), and the context is a // posting, then that posting isn't considered by the test. ; // skip it } - else if (! expr.calc(bound_scope).to_boolean()) { + else if (! expr->calc(bound_scope).to_boolean()) { return false; } } diff --git a/src/pyinterp.cc b/src/pyinterp.cc index 76fc0561..8052f6a4 100644 --- a/src/pyinterp.cc +++ b/src/pyinterp.cc @@ -286,7 +286,7 @@ value_t python_interpreter_t::python_command(call_scope_t& args) std::strcpy(argv[0], argv0); for (std::size_t i = 0; i < args.size(); i++) { - string arg = args[i].as_string(); + string arg = args.get<string>(i); argv[i + 1] = new char[arg.length() + 1]; std::strcpy(argv[i + 1], arg.c_str()); } diff --git a/src/pyinterp.h b/src/pyinterp.h index 3d747d5c..1dfd0747 100644 --- a/src/pyinterp.h +++ b/src/pyinterp.h @@ -109,8 +109,7 @@ public: virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, const string& name); - OPTION_(python_interpreter_t, import_, DO_(scope) { - interactive_t args(scope, "ss"); + OPTION_(python_interpreter_t, import_, DO_(args) { parent->import_option(args.get<string>(1)); }); }; diff --git a/src/report.cc b/src/report.cc index 9656d57a..3d44c2d4 100644 --- a/src/report.cc +++ b/src/report.cc @@ -448,44 +448,42 @@ value_t report_t::fn_display_total(call_scope_t& scope) return HANDLER(display_total_).expr.calc(scope); } -value_t report_t::fn_market(call_scope_t& scope) +value_t report_t::fn_market(call_scope_t& args) { - interactive_t args(scope, "a&ts"); - - value_t result; - optional<datetime_t> moment = (args.has(1) ? + optional<datetime_t> moment = (args.has<datetime_t>(1) ? args.get<datetime_t>(1) : optional<datetime_t>()); - if (args.has(2)) - result = args.value_at(0).exchange_commodities(args.get<string>(2), - /* add_prices= */ false, - moment); + value_t result; + if (args.has<string>(2)) + result = args[0].exchange_commodities(args.get<string>(2), + /* add_prices= */ false, moment); else - result = args.value_at(0).value(moment); + result = args[0].value(moment); + + DEBUG("fn_market", "value = " << args[0]); + if (moment) + DEBUG("fn_market", "moment = " << *moment); + DEBUG("fn_market", "result = " << result); if (! result.is_null()) return result; - return args.value_at(0); + return args[0]; } -value_t report_t::fn_get_at(call_scope_t& scope) +value_t report_t::fn_get_at(call_scope_t& args) { - interactive_t args(scope, "Sl"); - - DEBUG("report.get_at", "get_at[0] = " << args.value_at(0)); - DEBUG("report.get_at", "get_at[1] = " << args.value_at(1)); - - if (args.get<long>(1) == 0) { - if (! args.value_at(0).is_sequence()) - return args.value_at(0); + std::size_t index = static_cast<std::size_t>(args.get<long>(1)); + if (index == 0) { + if (! args[0].is_sequence()) + return args[0]; } else { - if (! args.value_at(0).is_sequence()) + if (! args[0].is_sequence()) throw_(std::runtime_error, _("Attempting to get argument at index %1 from %2") - << args.get<long>(1) << args.value_at(0).label()); + << index << args[0].label()); } - return args.get<const value_t::sequence_t&>(0)[args.get<long>(1)]; + return args[0].as_sequence()[index]; } value_t report_t::fn_is_seq(call_scope_t& scope) @@ -500,7 +498,7 @@ value_t report_t::fn_strip(call_scope_t& args) value_t report_t::fn_trim(call_scope_t& args) { - string temp(args.value().to_string()); + string temp(args.value().to_string()); scoped_array<char> buf(new char[temp.length() + 1]); std::strcpy(buf.get(), temp.c_str()); @@ -527,31 +525,26 @@ value_t report_t::fn_trim(call_scope_t& args) value_t report_t::fn_print(call_scope_t& args) { std::ostream& out(output_stream); - bool first = true; - for (call_scope_t::iterator i = args.begin(); i != args.end(); i++) { + bool first = true; + for (std::size_t i = 0; i < args.size(); i++) { if (first) first = false; else out << ' '; - (*i).print(out); + args[i].print(out); } return true; } -value_t report_t::scrub(value_t val) +value_t report_t::fn_scrub(call_scope_t& args) { - value_t temp(val.strip_annotations(what_to_keep())); + value_t temp(args.value().strip_annotations(what_to_keep())); if (HANDLED(base)) return temp; else return temp.unreduced(); } -value_t report_t::fn_scrub(call_scope_t& args) -{ - return scrub(args.value()); -} - value_t report_t::fn_rounded(call_scope_t& args) { return args.value().rounded(); @@ -562,57 +555,52 @@ value_t report_t::fn_unrounded(call_scope_t& args) return args.value().unrounded(); } -value_t report_t::fn_quantity(call_scope_t& scope) +value_t report_t::fn_quantity(call_scope_t& args) { - interactive_t args(scope, "a"); return args.get<amount_t>(0).number(); } -value_t report_t::fn_floor(call_scope_t& scope) +value_t report_t::fn_floor(call_scope_t& args) { - interactive_t args(scope, "v"); - return args.value_at(0).floored(); + return args[0].floored(); } -value_t report_t::fn_abs(call_scope_t& scope) +value_t report_t::fn_abs(call_scope_t& args) { - interactive_t args(scope, "v"); - return args.value_at(0).abs(); + return args[0].abs(); } -value_t report_t::fn_truncated(call_scope_t& scope) +value_t report_t::fn_truncated(call_scope_t& args) { - interactive_t args(scope, "v&ll"); return string_value(format_t::truncate (args.get<string>(0), - args.has(1) && args.get<int>(1) > 0 ? args.get<int>(1) : 0, - args.has(2) ? args.get<int>(2) : 0)); + args.has<int>(1) && + args.get<int>(1) > 0 ? args.get<int>(1) : 0, + args.has<int>(2) ? args.get<int>(2) : 0)); } -value_t report_t::fn_justify(call_scope_t& scope) +value_t report_t::fn_justify(call_scope_t& args) { - interactive_t args(scope, "vl&lbb"); - uint_least8_t flags(AMOUNT_PRINT_ELIDE_COMMODITY_QUOTES); - if (args.has(3) && args.get<bool>(3)) + if (args.has<bool>(3) && args.get<bool>(3)) flags |= AMOUNT_PRINT_RIGHT_JUSTIFY; - if (args.has(4) && args.get<bool>(4)) + if (args.has<bool>(4) && args.get<bool>(4)) flags |= AMOUNT_PRINT_COLORIZE; std::ostringstream out; - args.value_at(0) - .print(out, args.get<int>(1), args.has(2) ? args.get<int>(2) : -1, flags); + args[0].print(out, args.get<int>(1), + args.has<int>(2) ? args.get<int>(2) : -1, flags); + return string_value(out.str()); } -value_t report_t::fn_quoted(call_scope_t& scope) +value_t report_t::fn_quoted(call_scope_t& args) { - interactive_t args(scope, "v"); std::ostringstream out; out << '"'; - foreach (const char ch, args.value_at(0).to_string()) { + foreach (const char ch, args.get<string>(0)) { if (ch == '"') out << "\\\""; else @@ -623,9 +611,8 @@ value_t report_t::fn_quoted(call_scope_t& scope) return string_value(out.str()); } -value_t report_t::fn_join(call_scope_t& scope) +value_t report_t::fn_join(call_scope_t& args) { - interactive_t args(scope, "s"); std::ostringstream out; foreach (const char ch, args.get<string>(0)) { @@ -637,21 +624,18 @@ value_t report_t::fn_join(call_scope_t& scope) return string_value(out.str()); } -value_t report_t::fn_format_date(call_scope_t& scope) +value_t report_t::fn_format_date(call_scope_t& args) { - interactive_t args(scope, "d&s"); - if (args.has(1)) + if (args.has<string>(1)) return string_value(format_date(args.get<date_t>(0), FMT_CUSTOM, args.get<string>(1).c_str())); else return string_value(format_date(args.get<date_t>(0), FMT_PRINTED)); } -value_t report_t::fn_ansify_if(call_scope_t& scope) +value_t report_t::fn_ansify_if(call_scope_t& args) { - interactive_t args(scope, "v&s"); - - if (args.has(1)) { + if (args.has<string>(1)) { string color = args.get<string>(1); std::ostringstream buf; if (color == "black") buf << "\033[30m"; @@ -665,127 +649,105 @@ value_t report_t::fn_ansify_if(call_scope_t& scope) else if (color == "bold") buf << "\033[1m"; else if (color == "underline") buf << "\033[4m"; else if (color == "blink") buf << "\033[5m"; - buf << args.value_at(0); + buf << args[0]; buf << "\033[0m"; return string_value(buf.str()); - } else { - return args.value_at(0); } + return args[0]; } -value_t report_t::fn_percent(call_scope_t& scope) +value_t report_t::fn_percent(call_scope_t& args) { - interactive_t args(scope, "aa"); return (amount_t("100.00%") * (args.get<amount_t>(0) / args.get<amount_t>(1)).number()); } -value_t report_t::fn_price(call_scope_t& scope) +value_t report_t::fn_price(call_scope_t& args) { - interactive_t args(scope, "v"); - return args.value_at(0).price(); + return args[0].price(); } -value_t report_t::fn_commodity(call_scope_t& scope) +value_t report_t::fn_commodity(call_scope_t& args) { - in_context_t<post_t> env(scope, "v"); - return string_value(env.value_at(0).to_amount().commodity().symbol()); + return string_value(args.get<amount_t>(0).commodity().symbol()); } -value_t report_t::fn_lot_date(call_scope_t& scope) +value_t report_t::fn_lot_date(call_scope_t& args) { - interactive_t args(scope, "v"); - if (args.value_at(0).has_annotation()) { - const annotation_t& details(args.value_at(0).annotation()); + if (args[0].has_annotation()) { + const annotation_t& details(args[0].annotation()); if (details.date) return *details.date; } return NULL_VALUE; } -value_t report_t::fn_lot_price(call_scope_t& scope) +value_t report_t::fn_lot_price(call_scope_t& args) { - interactive_t args(scope, "v"); - if (args.value_at(0).has_annotation()) { - const annotation_t& details(args.value_at(0).annotation()); + if (args[0].has_annotation()) { + const annotation_t& details(args[0].annotation()); if (details.price) return *details.price; } return NULL_VALUE; } -value_t report_t::fn_lot_tag(call_scope_t& scope) +value_t report_t::fn_lot_tag(call_scope_t& args) { - interactive_t args(scope, "v"); - if (args.value_at(0).has_annotation()) { - const annotation_t& details(args.value_at(0).annotation()); + if (args[0].has_annotation()) { + const annotation_t& details(args[0].annotation()); if (details.tag) return string_value(*details.tag); } return NULL_VALUE; } -value_t report_t::fn_to_boolean(call_scope_t& scope) +value_t report_t::fn_to_boolean(call_scope_t& args) { - interactive_t args(scope, "v"); - args.value_at(0).in_place_cast(value_t::BOOLEAN); - return args.value_at(0); + return args.get<bool>(0); } -value_t report_t::fn_to_int(call_scope_t& scope) +value_t report_t::fn_to_int(call_scope_t& args) { - interactive_t args(scope, "v"); - args.value_at(0).in_place_cast(value_t::INTEGER); - return args.value_at(0); + // This method is not called fn_to_long, because that would be + // confusing to users who don't care about the distinction between + // integer and long. + return args.get<long>(0); } -value_t report_t::fn_to_datetime(call_scope_t& scope) +value_t report_t::fn_to_datetime(call_scope_t& args) { - interactive_t args(scope, "v"); - args.value_at(0).in_place_cast(value_t::DATETIME); - return args.value_at(0); + return args.get<datetime_t>(0); } -value_t report_t::fn_to_date(call_scope_t& scope) +value_t report_t::fn_to_date(call_scope_t& args) { - interactive_t args(scope, "v"); - args.value_at(0).in_place_cast(value_t::DATE); - return args.value_at(0); + return args.get<date_t>(0); } -value_t report_t::fn_to_amount(call_scope_t& scope) +value_t report_t::fn_to_amount(call_scope_t& args) { - interactive_t args(scope, "v"); - args.value_at(0).in_place_cast(value_t::AMOUNT); - return args.value_at(0); + return args.get<amount_t>(0); } -value_t report_t::fn_to_balance(call_scope_t& scope) +value_t report_t::fn_to_balance(call_scope_t& args) { - interactive_t args(scope, "v"); - args.value_at(0).in_place_cast(value_t::BALANCE); - return args.value_at(0); + return args.get<balance_t>(0); } -value_t report_t::fn_to_string(call_scope_t& scope) +value_t report_t::fn_to_string(call_scope_t& args) { - interactive_t args(scope, "v"); - args.value_at(0).in_place_cast(value_t::STRING); - return args.value_at(0); + return string_value(args.get<string>(0)); } -value_t report_t::fn_to_mask(call_scope_t& scope) +value_t report_t::fn_to_mask(call_scope_t& args) { - interactive_t args(scope, "v"); - args.value_at(0).in_place_cast(value_t::MASK); - return args.value_at(0); + return args.get<mask_t>(0); } -value_t report_t::fn_to_sequence(call_scope_t& scope) +value_t report_t::fn_to_sequence(call_scope_t& args) { - interactive_t args(scope, "v"); - args.value_at(0).in_place_cast(value_t::SEQUENCE); - return args.value_at(0); + return args[0].to_sequence(); } namespace { @@ -837,21 +799,19 @@ value_t report_t::reload_command(call_scope_t&) return true; } -value_t report_t::echo_command(call_scope_t& scope) +value_t report_t::echo_command(call_scope_t& args) { - interactive_t args(scope, "s"); std::ostream& out(output_stream); out << args.get<string>(0) << std::endl; return true; } -value_t report_t::pricemap_command(call_scope_t& scope) +value_t report_t::pricemap_command(call_scope_t& args) { - interactive_t args(scope, "&s"); std::ostream& out(output_stream); commodity_pool_t::current_pool->print_pricemap - (out, what_to_keep(), args.has(0) ? + (out, what_to_keep(), args.has<string>(0) ? optional<datetime_t>(datetime_t(parse_date(args.get<string>(0)))) : none); return true; diff --git a/src/report.h b/src/report.h index 00cbec28..44aed03b 100644 --- a/src/report.h +++ b/src/report.h @@ -42,7 +42,6 @@ #ifndef _REPORT_H #define _REPORT_H -#include "interactive.h" #include "expr.h" #include "query.h" #include "chain.h" @@ -145,7 +144,6 @@ public: value_t fn_strip(call_scope_t& scope); value_t fn_trim(call_scope_t& scope); value_t fn_print(call_scope_t& scope); - value_t scrub(value_t val); value_t fn_scrub(call_scope_t& scope); value_t fn_quantity(call_scope_t& scope); value_t fn_rounded(call_scope_t& scope); @@ -366,7 +364,7 @@ public: on(whence, str); } DO_(args) { - set_expr(args[0].to_string(), args[1].to_string()); + set_expr(args.get<string>(0), args.get<string>(1)); }); OPTION(report_t, amount_data); // -j @@ -394,12 +392,12 @@ public: }); OPTION_(report_t, begin_, DO_(args) { // -b - date_interval_t interval(args[1].to_string()); + date_interval_t interval(args.get<string>(1)); optional<date_t> begin = interval.begin(parent->session.current_year); if (! begin) throw_(std::invalid_argument, _("Could not determine beginning of period '%1'") - << args[1].to_string()); + << args.get<string>(1)); string predicate = "date>=[" + to_iso_extended_string(*begin) + "]"; parent->HANDLER(limit_).on(string("--begin"), predicate); @@ -488,10 +486,9 @@ public: OPTION(report_t, date_format_); OPTION(report_t, datetime_format_); - OPTION_(report_t, depth_, DO_(scope) { - interactive_t args(scope, "sl"); - parent->HANDLER(display_).on(string("--depth"), - string("depth<=") + args.get<string>(1)); + OPTION_(report_t, depth_, DO_(args) { + parent->HANDLER(display_) + .on(string("--depth"), string("depth<=") + args.get<string>(1)); }); OPTION_(report_t, deviation, DO() { @@ -522,7 +519,7 @@ public: on(whence, str); } DO_(args) { - set_expr(args[0].to_string(), args[1].to_string()); + set_expr(args.get<string>(0), args.get<string>(1)); }); OPTION__ @@ -536,7 +533,7 @@ public: on(whence, str); } DO_(args) { - set_expr(args[0].to_string(), args[1].to_string()); + set_expr(args.get<string>(0), args.get<string>(1)); }); OPTION(report_t, dow); @@ -544,14 +541,14 @@ public: OPTION(report_t, empty); // -E OPTION_(report_t, end_, DO_(args) { // -e - date_interval_t interval(args[1].to_string()); + date_interval_t interval(args.get<string>(1)); // Use begin() here so that if the user says --end=2008, we end on // 2008/01/01 instead of 2009/01/01 (which is what end() would return). optional<date_t> end = interval.begin(parent->session.current_year); if (! end) throw_(std::invalid_argument, _("Could not determine end of period '%1'") - << args[1].to_string()); + << args.get<string>(1)); string predicate = "date<[" + to_iso_extended_string(*end) + "]"; parent->HANDLER(limit_).on(string("--end"), predicate); @@ -563,7 +560,7 @@ public: OPTION(report_t, exact); OPTION_(report_t, exchange_, DO_(args) { // -X - on_with(args[0].as_string(), args[1]); + on_with(args.get<string>(0), args[1]); call_scope_t no_args(*parent); no_args.push_back(args[0]); parent->HANDLER(market).parent = parent; @@ -611,7 +608,7 @@ public: on(whence, str); } DO_(args) { - set_expr(args[0].to_string(), args[1].to_string()); + set_expr(args.get<string>(0), args.get<string>(1)); }); OPTION__(report_t, group_title_format_, CTOR(report_t, group_title_format_) { @@ -667,12 +664,12 @@ public: OPTION(report_t, no_total); OPTION_(report_t, now_, DO_(args) { - date_interval_t interval(args[1].to_string()); + date_interval_t interval(args.get<string>(1)); optional<date_t> begin = interval.begin(parent->session.current_year); if (! begin) throw_(std::invalid_argument, _("Could not determine beginning of period '%1'") - << args[1].to_string()); + << args.get<string>(1)); ledger::epoch = parent->terminus = datetime_t(*begin); parent->session.current_year = ledger::epoch->date().year(); }); @@ -769,7 +766,7 @@ public: OPTION(report_t, prepend_format_); OPTION_(report_t, prepend_width_, DO_(args) { - value = args[1].to_long(); + value = args.get<long>(1); }); OPTION_(report_t, price, DO() { // -I @@ -842,13 +839,13 @@ public: on(whence, str); } DO_(args) { - set_expr(args[0].to_string(), args[1].to_string()); + set_expr(args.get<string>(0), args.get<string>(1)); }); OPTION(report_t, seed_); OPTION_(report_t, sort_, DO_(args) { // -S - on_with(args[0].as_string(), args[1]); + on_with(args.get<string>(0), args[1]); parent->HANDLER(sort_xacts_).off(); parent->HANDLER(sort_all_).off(); }); @@ -878,13 +875,13 @@ public: on(whence, str); } DO_(args) { - set_expr(args[0].to_string(), args[1].to_string()); + set_expr(args.get<string>(0), args.get<string>(1)); }); OPTION(report_t, total_data); // -J OPTION_(report_t, truncate_, DO_(args) { - string style(args[1].to_string()); + string style(args.get<string>(1)); if (style == "leading") format_t::default_style = format_t::TRUNCATE_LEADING; else if (style == "middle") @@ -934,27 +931,27 @@ public: OPTION__(report_t, meta_width_, bool specified; CTOR(report_t, meta_width_) { specified = false; } - DO_(args) { value = args[1].to_long(); specified = true; }); + DO_(args) { value = args.get<long>(1); specified = true; }); OPTION__(report_t, date_width_, bool specified; CTOR(report_t, date_width_) { specified = false; } - DO_(args) { value = args[1].to_long(); specified = true; }); + DO_(args) { value = args.get<long>(1); specified = true; }); OPTION__(report_t, payee_width_, bool specified; CTOR(report_t, payee_width_) { specified = false; } - DO_(args) { value = args[1].to_long(); specified = true; }); + DO_(args) { value = args.get<long>(1); specified = true; }); OPTION__(report_t, account_width_, bool specified; CTOR(report_t, account_width_) { specified = false; } - DO_(args) { value = args[1].to_long(); specified = true; }); + DO_(args) { value = args.get<long>(1); specified = true; }); OPTION__(report_t, amount_width_, bool specified; CTOR(report_t, amount_width_) { specified = false; } - DO_(args) { value = args[1].to_long(); specified = true; }); + DO_(args) { value = args.get<long>(1); specified = true; }); OPTION__(report_t, total_width_, bool specified; CTOR(report_t, total_width_) { specified = false; } - DO_(args) { value = args[1].to_long(); specified = true; }); + DO_(args) { value = args.get<long>(1); specified = true; }); }; diff --git a/src/scope.cc b/src/scope.cc index faad352a..52cf6a90 100644 --- a/src/scope.cc +++ b/src/scope.cc @@ -71,4 +71,23 @@ expr_t::ptr_op_t symbol_scope_t::lookup(const symbol_t::kind_t kind, return child_scope_t::lookup(kind, name); } +value_t& call_scope_t::resolve(const std::size_t index, + value_t::type_t context, + const bool required) +{ + if (index >= args.size()) + throw_(calc_error, _("Too few arguments to function")); + + value_t& value(args[index]); + if (value.is_any()) { + context_scope_t scope(*this, context, required); + value = as_expr(value)->calc(scope); + if (required && ! value.is_type(context)) + throw_(calc_error, _("Expected %1 for argument %2, but received %3") + << value.label(context) << index + << value.label()); + } + return value; +} + } // namespace ledger diff --git a/src/scope.h b/src/scope.h index 1b10d7a6..f9bea6b6 100644 --- a/src/scope.h +++ b/src/scope.h @@ -117,6 +117,9 @@ public: virtual value_t::type_t type_context() const { return value_t::VOID; } + virtual bool type_required() const { + return false; + } #if defined(HAVE_BOOST_SERIALIZATION) private: @@ -172,6 +175,76 @@ private: #endif // HAVE_BOOST_SERIALIZATION }; +class bind_scope_t : public child_scope_t +{ + bind_scope_t(); + +public: + scope_t& grandchild; + + explicit bind_scope_t(scope_t& _parent, + scope_t& _grandchild) + : child_scope_t(_parent), grandchild(_grandchild) { + TRACE_CTOR(bind_scope_t, "scope_t&, scope_t&"); + } + virtual ~bind_scope_t() { + TRACE_DTOR(bind_scope_t); + } + + virtual void define(const symbol_t::kind_t kind, const string& name, + expr_t::ptr_op_t def) { + parent->define(kind, name, def); + grandchild.define(kind, name, def); + } + + virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, + const string& name) { + if (expr_t::ptr_op_t def = grandchild.lookup(kind, name)) + return def; + return child_scope_t::lookup(kind, name); + } + +#if defined(HAVE_BOOST_SERIALIZATION) +private: + /** Serialization. */ + + friend class boost::serialization::access; + + template<class Archive> + void serialize(Archive& ar, const unsigned int /* version */) { + ar & boost::serialization::base_object<child_scope_t>(*this); + ar & grandchild; + } +#endif // HAVE_BOOST_SERIALIZATION +}; + +template <typename T> +T * search_scope(scope_t * ptr) +{ + if (T * sought = dynamic_cast<T *>(ptr)) + return sought; + + if (bind_scope_t * scope = dynamic_cast<bind_scope_t *>(ptr)) { + if (T * sought = search_scope<T>(&scope->grandchild)) + return sought; + return search_scope<T>(scope->parent); + } + else if (child_scope_t * scope = dynamic_cast<child_scope_t *>(ptr)) { + return search_scope<T>(scope->parent); + } + return NULL; +} + +template <typename T> +inline T& find_scope(child_scope_t& scope, bool skip_this = true) +{ + if (T * sought = search_scope<T>(skip_this ? scope.parent : &scope)) + return *sought; + + throw_(std::runtime_error, _("Could not find scope")); + return reinterpret_cast<T&>(scope); // never executed +} + class symbol_scope_t : public child_scope_t { typedef std::map<symbol_t, expr_t::ptr_op_t> symbol_map; @@ -212,12 +285,15 @@ private: class context_scope_t : public child_scope_t { value_t::type_t value_type_context; + bool required; public: explicit context_scope_t(scope_t& _parent, - value_t::type_t _type_context = value_t::VOID) - : child_scope_t(_parent), value_type_context(_type_context) { - TRACE_CTOR(context_scope_t, "scope_t&, value_t::type_t"); + value_t::type_t _type_context = value_t::VOID, + const bool _required = true) + : child_scope_t(_parent), value_type_context(_type_context), + required(_required) { + TRACE_CTOR(context_scope_t, "scope_t&, value_t::type_t, bool"); } virtual ~context_scope_t() { TRACE_DTOR(context_scope_t); @@ -226,17 +302,26 @@ public: virtual value_t::type_t type_context() const { return value_type_context; } + virtual bool type_required() const { + return required; + } }; class call_scope_t : public context_scope_t { - value_t args; + value_t args; + mutable void * ptr; + + value_t& resolve(const std::size_t index, + value_t::type_t context = value_t::VOID, + const bool required = false); public: explicit call_scope_t(scope_t& _parent, - value_t::type_t _type_context = value_t::VOID) - : context_scope_t(_parent, _type_context) { - TRACE_CTOR(call_scope_t, "scope_t&, value_t::type_t"); + value_t::type_t _type_context = value_t::VOID, + const bool _required = true) + : context_scope_t(_parent, _type_context, _required), ptr(NULL) { + TRACE_CTOR(call_scope_t, "scope_t&, value_t::type_t, bool"); } virtual ~call_scope_t() { TRACE_DTOR(call_scope_t); @@ -246,15 +331,36 @@ public: args = _args; } value_t& value() { + // Make sure that all of the arguments have been resolved. + for (std::size_t index = 0; index < args.size(); index++) + resolve(index); return args; } value_t& operator[](const std::size_t index) { - return args[index]; + return resolve(index); } +#if 0 const value_t& operator[](const std::size_t index) const { return args[index]; } +#endif + + bool has(std::size_t index) { + return index < args.size() && ! (*this)[index].is_null(); + } + template <typename T> + bool has(std::size_t index); + template <typename T> + T get(std::size_t index, bool convert = true); + + template <typename T> + T& context() { + if (ptr == NULL) + ptr = &find_scope<T>(*this); + assert(ptr != NULL); + return *static_cast<T *>(ptr); + } void push_front(const value_t& val) { args.push_front(val); @@ -309,74 +415,169 @@ private: #endif // HAVE_BOOST_SERIALIZATION }; -class bind_scope_t : public child_scope_t -{ - bind_scope_t(); - -public: - scope_t& grandchild; - - explicit bind_scope_t(scope_t& _parent, - scope_t& _grandchild) - : child_scope_t(_parent), grandchild(_grandchild) { - TRACE_CTOR(bind_scope_t, "scope_t&, scope_t&"); +template <> +inline bool call_scope_t::has<bool>(std::size_t index) { + if (index < args.size()) { + resolve(index, value_t::BOOLEAN, false); + return ! args[index].is_null(); } - virtual ~bind_scope_t() { - TRACE_DTOR(bind_scope_t); + return false; +} +template <> +inline bool call_scope_t::has<int>(std::size_t index) { + if (index < args.size()) { + resolve(index, value_t::INTEGER, false); + return ! args[index].is_null(); } - - virtual void define(const symbol_t::kind_t kind, const string& name, - expr_t::ptr_op_t def) { - parent->define(kind, name, def); - grandchild.define(kind, name, def); + return false; +} +template <> +inline bool call_scope_t::has<long>(std::size_t index) { + if (index < args.size()) { + resolve(index, value_t::INTEGER, false); + return ! args[index].is_null(); } - - virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, - const string& name) { - if (expr_t::ptr_op_t def = grandchild.lookup(kind, name)) - return def; - return child_scope_t::lookup(kind, name); + return false; +} +template <> +inline bool call_scope_t::has<amount_t>(std::size_t index) { + if (index < args.size()) { + resolve(index, value_t::AMOUNT, false); + return ! args[index].is_null(); } - -#if defined(HAVE_BOOST_SERIALIZATION) -private: - /** Serialization. */ - - friend class boost::serialization::access; - - template<class Archive> - void serialize(Archive& ar, const unsigned int /* version */) { - ar & boost::serialization::base_object<child_scope_t>(*this); - ar & grandchild; + return false; +} +template <> +inline bool call_scope_t::has<balance_t>(std::size_t index) { + if (index < args.size()) { + resolve(index, value_t::BALANCE, false); + return ! args[index].is_null(); } -#endif // HAVE_BOOST_SERIALIZATION -}; - -template <typename T> -T * search_scope(scope_t * ptr) -{ - if (T * sought = dynamic_cast<T *>(ptr)) - return sought; - - if (bind_scope_t * scope = dynamic_cast<bind_scope_t *>(ptr)) { - if (T * sought = search_scope<T>(&scope->grandchild)) - return sought; - return search_scope<T>(scope->parent); + return false; +} +template <> +inline bool call_scope_t::has<string>(std::size_t index) { + if (index < args.size()) { + resolve(index, value_t::STRING, false); + return ! args[index].is_null(); } - else if (child_scope_t * scope = dynamic_cast<child_scope_t *>(ptr)) { - return search_scope<T>(scope->parent); + return false; +} +template <> +inline bool call_scope_t::has<date_t>(std::size_t index) { + if (index < args.size()) { + resolve(index, value_t::DATE, false); + return ! args[index].is_null(); } - return NULL; + return false; +} +template <> +inline bool call_scope_t::has<datetime_t>(std::size_t index) { + if (index < args.size()) { + resolve(index, value_t::DATETIME, false); + return ! args[index].is_null(); + } + return false; +} +template <> +inline bool call_scope_t::has<scope_t *>(std::size_t index) { + if (index < args.size()) { + resolve(index, value_t::SCOPE, false); + return ! args[index].is_null(); + } + return false; +} +template <> +inline bool call_scope_t::has<expr_t::ptr_op_t>(std::size_t index) { + if (index < args.size()) { + resolve(index, value_t::ANY, false); + return ! args[index].is_null(); + } + return false; } -template <typename T> -inline T& find_scope(child_scope_t& scope, bool skip_this = true) -{ - if (T * sought = search_scope<T>(skip_this ? scope.parent : &scope)) - return *sought; +template <> +inline bool call_scope_t::get<bool>(std::size_t index, bool convert) { + if (convert) + return resolve(index, value_t::BOOLEAN, false).to_boolean(); + else + return resolve(index, value_t::BOOLEAN).as_boolean(); +} +template <> +inline int call_scope_t::get<int>(std::size_t index, bool) { + return resolve(index, value_t::INTEGER, false).to_int(); +} +template <> +inline long call_scope_t::get<long>(std::size_t index, bool convert) { + if (convert) + return resolve(index, value_t::INTEGER, false).to_long(); + else + return resolve(index, value_t::INTEGER).as_long(); +} +template <> +inline amount_t call_scope_t::get<amount_t>(std::size_t index, bool convert) { + if (convert) + return resolve(index, value_t::AMOUNT, false).to_amount(); + else + return resolve(index, value_t::AMOUNT).as_amount(); +} +template <> +inline balance_t call_scope_t::get<balance_t>(std::size_t index, bool convert) { + if (convert) + return resolve(index, value_t::BALANCE, false).to_balance(); + else + return resolve(index, value_t::BALANCE).as_balance(); +} +template <> +inline string call_scope_t::get<string>(std::size_t index, bool convert) { + if (convert) + return resolve(index, value_t::STRING, false).to_string(); + else + return resolve(index, value_t::STRING).as_string(); +} +template <> +inline mask_t call_scope_t::get<mask_t>(std::size_t index, bool convert) { + if (convert) + return resolve(index, value_t::MASK, false).to_mask(); + else + return resolve(index, value_t::MASK).as_mask(); +} +template <> +inline date_t call_scope_t::get<date_t>(std::size_t index, bool convert) { + if (convert) + return resolve(index, value_t::DATE, false).to_date(); + else + return resolve(index, value_t::DATE).as_date(); +} +template <> +inline datetime_t call_scope_t::get<datetime_t>(std::size_t index, bool convert) { + if (convert) + return resolve(index, value_t::DATETIME, false).to_datetime(); + else + return resolve(index, value_t::DATETIME).as_datetime(); +} - throw_(std::runtime_error, _("Could not find scope")); - return reinterpret_cast<T&>(scope); // never executed +#if 0 +template <> +inline value_t::sequence_t& +call_scope_t::get<value_t::sequence_t&>(std::size_t index, bool) { + return resolve(index, value_t::SEQUENCE).as_sequence_lval(); +} +template <> +inline const value_t::sequence_t& +call_scope_t::get<const value_t::sequence_t&>(std::size_t index, bool) { + return resolve(index, value_t::SEQUENCE).as_sequence(); +} +#endif + +template <> +inline scope_t * call_scope_t::get<scope_t *>(std::size_t index, bool) { + return resolve(index, value_t::SCOPE).as_scope(); +} +template <> +inline expr_t::ptr_op_t +call_scope_t::get<expr_t::ptr_op_t>(std::size_t index, bool) { + return resolve(index, value_t::ANY).as_any<expr_t::ptr_op_t>(); } class value_scope_t : public scope_t diff --git a/src/session.cc b/src/session.cc index b5441766..df6eaf7d 100644 --- a/src/session.cc +++ b/src/session.cc @@ -182,12 +182,11 @@ void session_t::close_journal_files() amount_t::initialize(); } -value_t session_t::fn_account(call_scope_t& scope) +value_t session_t::fn_account(call_scope_t& args) { - interactive_t args(scope, "v"); - if (scope[0].is_string()) + if (args[0].is_string()) return scope_value(journal->find_account(args.get<string>(0), false)); - else if (scope[0].is_mask()) + else if (args[0].is_mask()) return scope_value(journal->find_account_re(args.get<mask_t>(0).str())); else return NULL_VALUE; diff --git a/src/session.h b/src/session.h index 5130e3fb..597268ee 100644 --- a/src/session.h +++ b/src/session.h @@ -42,7 +42,6 @@ #ifndef _SESSION_H #define _SESSION_H -#include "interactive.h" #include "account.h" #include "journal.h" #include "option.h" @@ -110,7 +109,7 @@ public: (session_t, price_exp_, // -Z CTOR(session_t, price_exp_) { value = 24L * 3600L; } DO_(args) { - value = args[1].to_long() * 60L; + value = args.get<long>(1) * 60L; }); OPTION__ @@ -123,13 +122,13 @@ public: data_files.clear(); parent->flush_on_next_data_file = false; } - data_files.push_back(args[1].as_string()); + data_files.push_back(args.get<string>(1)); }); OPTION_(session_t, input_date_format_, DO_(args) { // This changes static variables inside times.h, which affects the basic // date parser. - set_input_date_format(args[1].as_string().c_str()); + set_input_date_format(args.get<string>(1).c_str()); }); OPTION(session_t, master_account_); diff --git a/src/xact.cc b/src/xact.cc index 0bf1fc2c..1188fd0f 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -36,7 +36,6 @@ #include "account.h" #include "journal.h" #include "pool.h" -#include "interactive.h" namespace ledger { @@ -503,31 +502,27 @@ namespace { return (*Func)(find_scope<xact_t>(scope)); } - value_t fn_any(call_scope_t& scope) + value_t fn_any(call_scope_t& args) { - interactive_t args(scope, "X&X"); - - post_t& post(find_scope<post_t>(scope)); - expr_t& expr(args.get<expr_t&>(0)); + post_t& post(args.context<post_t>()); + expr_t::ptr_op_t expr(args.get<expr_t::ptr_op_t>(0)); foreach (post_t * p, post.xact->posts) { - bind_scope_t bound_scope(scope, *p); - if (expr.calc(bound_scope).to_boolean()) + bind_scope_t bound_scope(args, *p); + if (expr->calc(bound_scope).to_boolean()) return true; } return false; } - value_t fn_all(call_scope_t& scope) + value_t fn_all(call_scope_t& args) { - interactive_t args(scope, "X&X"); - - post_t& post(find_scope<post_t>(scope)); - expr_t& expr(args.get<expr_t&>(0)); + post_t& post(args.context<post_t>()); + expr_t::ptr_op_t expr(args.get<expr_t::ptr_op_t>(0)); foreach (post_t * p, post.xact->posts) { - bind_scope_t bound_scope(scope, *p); - if (! expr.calc(bound_scope).to_boolean()) + bind_scope_t bound_scope(args, *p); + if (! expr->calc(bound_scope).to_boolean()) return false; } return true; diff --git a/tools/Makefile.am b/tools/Makefile.am index 5b032f72..fa83c1ca 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -44,7 +44,6 @@ libledger_expr_la_SOURCES = \ src/query.cc \ src/predicate.cc \ src/scope.cc \ - src/interactive.cc \ src/expr.cc \ src/op.cc \ src/parser.cc \ @@ -115,7 +114,6 @@ pkginclude_HEADERS = \ src/exprbase.h \ src/expr.h \ src/scope.h \ - src/interactive.h \ src/predicate.h \ src/query.h \ src/format.h \ |