summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2010-06-13 05:02:14 -0400
committerJohn Wiegley <johnw@newartisans.com>2010-06-13 05:02:14 -0400
commitea1642b3f969463a49e5a671478c92e4ef129665 (patch)
tree9eba47b8708123b4e3f539dd9d747f1f85d9d2fe
parentad3b30a9641b8e09c38ea76e7011b614152d8faf (diff)
downloadfork-ledger-ea1642b3f969463a49e5a671478c92e4ef129665.tar.gz
fork-ledger-ea1642b3f969463a49e5a671478c92e4ef129665.tar.bz2
fork-ledger-ea1642b3f969463a49e5a671478c92e4ef129665.zip
Completely reworked argument passing in expressions
-rw-r--r--src/account.cc50
-rw-r--r--src/convert.cc8
-rw-r--r--src/expr.h20
-rw-r--r--src/global.h1
-rw-r--r--src/interactive.cc199
-rw-r--r--src/interactive.h164
-rw-r--r--src/item.cc13
-rw-r--r--src/op.cc52
-rw-r--r--src/op.h3
-rw-r--r--src/option.h4
-rw-r--r--src/parser.cc4
-rw-r--r--src/post.cc98
-rw-r--r--src/pyinterp.cc2
-rw-r--r--src/pyinterp.h3
-rw-r--r--src/report.cc218
-rw-r--r--src/report.h53
-rw-r--r--src/scope.cc19
-rw-r--r--src/scope.h333
-rw-r--r--src/session.cc7
-rw-r--r--src/session.h7
-rw-r--r--src/xact.cc25
-rw-r--r--tools/Makefile.am2
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_))
diff --git a/src/expr.h b/src/expr.h
index fa49cdc4..e6eeebf6 100644
--- a/src/expr.h
+++ b/src/expr.h
@@ -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")
diff --git a/src/op.cc b/src/op.cc
index 0feb157f..c2001ec3 100644
--- a/src/op.cc
+++ b/src/op.cc
@@ -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;
diff --git a/src/op.h b/src/op.h
index 27fdea3b..aa591b28 100644
--- a/src/op.h
+++ b/src/op.h
@@ -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 \