summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--src/account.cc9
-rw-r--r--src/interactive.cc184
-rw-r--r--src/interactive.h142
-rw-r--r--src/precmd.cc1
-rw-r--r--src/precmd.h4
-rw-r--r--src/report.cc44
-rw-r--r--src/report.h4
-rw-r--r--src/scope.cc17
-rw-r--r--src/scope.h97
-rw-r--r--src/xact.cc15
11 files changed, 367 insertions, 152 deletions
diff --git a/Makefile.am b/Makefile.am
index b73bf853..f40166bc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -37,6 +37,7 @@ libledger_expr_la_SOURCES = \
src/format.cc \
src/predicate.cc \
src/scope.cc \
+ src/interactive.cc \
src/expr.cc \
src/op.cc \
src/parser.cc \
@@ -96,6 +97,7 @@ pkginclude_HEADERS = \
src/op.h \
src/expr.h \
src/scope.h \
+ src/interactive.h \
src/predicate.h \
src/format.h \
src/option.h \
diff --git a/src/account.cc b/src/account.cc
index 741cc2f9..ad94e48a 100644
--- a/src/account.cc
+++ b/src/account.cc
@@ -30,6 +30,7 @@
*/
#include "account.h"
+#include "interactive.h"
namespace ledger {
@@ -152,11 +153,9 @@ std::ostream& operator<<(std::ostream& out, const account_t& account)
namespace {
value_t get_partial_name(call_scope_t& scope)
{
- account_t& account(find_scope<account_t>(scope));
-
- var_t<bool> flatten(scope, 0);
-
- return string_value(account.partial_name(flatten ? *flatten : false));
+ in_context_t<account_t> env(scope, "&b");
+ return string_value(env->partial_name(env.has(0) ?
+ env.get<bool>(0) : false));
}
value_t get_account(account_t& account) { // this gets the name
diff --git a/src/interactive.cc b/src/interactive.cc
new file mode 100644
index 00000000..3e2d6d5e
--- /dev/null
+++ b/src/interactive.cc
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2003-2009, 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 "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++) {
+ 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();
+ 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 't':
+ label = "a date or time";
+ wrong_arg = (! next_arg->is_date() &&
+ ! next_arg->is_datetime());
+ break;
+ case 'v':
+ label = "any value";
+ wrong_arg = false;
+ break;
+ case 'P':
+ label = "a pointer";
+ wrong_arg = ! next_arg->is_pointer();
+ break;
+ case 'S':
+ label = "a sequence";
+ wrong_arg = ! next_arg->is_sequence();
+ break;
+ case '&':
+ optional = true;
+ dont_skip = true;
+ break;
+ case '*':
+ optional = true;
+ exit_loop = true;
+ dont_skip = true;
+ break;
+ }
+
+ if (wrong_arg)
+ vlabel = next_arg->label();
+
+ 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;
+
+ if (wrong_arg) {
+ throw_(std::logic_error,
+ "Expected " << label << " for argument " << offset
+ << ", but received " << vlabel);
+ }
+ else if (! optional && ! next_arg) {
+ throw_(std::logic_error, "Too few arguments to function");
+ }
+ else if (! *p && next_arg) {
+ throw_(std::logic_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) {
+ buf << args[i];
+ first = false;
+ } else {
+ buf << ' ' << args[i];
+ }
+ }
+
+ return buf.str();
+}
+
+} // namespace ledger
diff --git a/src/interactive.h b/src/interactive.h
new file mode 100644
index 00000000..766953ec
--- /dev/null
+++ b/src/interactive.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2003-2009, 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
+ *
+ * @brief Brief
+ *
+ * Long.
+ */
+#ifndef _INTERACTIVE_H
+#define _INTERACTIVE_H
+
+#include "scope.h"
+
+namespace ledger {
+
+/**
+ * @brief Brief
+ *
+ * Long.
+ */
+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())
+ return true;
+ return false;
+ }
+
+ const value_t& value_at(std::size_t index) const {
+ assert(has(index));
+ return args[index];
+ }
+
+ template <typename T>
+ T get(std::size_t index) const;
+};
+
+template <>
+inline bool interactive_t::get<bool>(std::size_t index) const {
+ return value_at(index).to_boolean();
+}
+template <>
+inline long interactive_t::get<long>(std::size_t index) const {
+ return value_at(index).to_long();
+}
+template <>
+inline string interactive_t::get<string>(std::size_t index) const {
+ return value_at(index).to_string();
+}
+template <>
+inline mask_t interactive_t::get<mask_t>(std::size_t index) const {
+ return value_at(index).to_mask();
+}
+template <>
+inline date_t interactive_t::get<date_t>(std::size_t index) const {
+ return value_at(index).to_date();
+}
+template <>
+inline datetime_t interactive_t::get<datetime_t>(std::size_t index) const {
+ return value_at(index).to_datetime();
+}
+
+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/precmd.cc b/src/precmd.cc
index c02be263..4b623904 100644
--- a/src/precmd.cc
+++ b/src/precmd.cc
@@ -30,6 +30,7 @@
*/
#include "precmd.h"
+#include "interactive.h"
#include "report.h"
namespace ledger {
diff --git a/src/precmd.h b/src/precmd.h
index d489b1af..b36d33e1 100644
--- a/src/precmd.h
+++ b/src/precmd.h
@@ -46,10 +46,12 @@
#ifndef _PRECMD_H
#define _PRECMD_H
-#include "scope.h"
+#include "value.h"
namespace ledger {
+class call_scope_t;
+
value_t parse_command(call_scope_t& args);
value_t eval_command(call_scope_t& args);
value_t format_command(call_scope_t& args);
diff --git a/src/report.cc b/src/report.cc
index 1da4699b..a9c930b0 100644
--- a/src/report.cc
+++ b/src/report.cc
@@ -30,6 +30,7 @@
*/
#include "report.h"
+#include "interactive.h"
#include "iterators.h"
#include "filters.h"
#include "chain.h"
@@ -121,19 +122,20 @@ value_t report_t::fn_display_total(call_scope_t& scope)
value_t report_t::fn_market_value(call_scope_t& args)
{
- var_t<datetime_t> date(args, 1);
- var_t<string> in_terms_of(args, 2);
+ interactive_t env(args, "a&ts");
commodity_t * commodity = NULL;
- if (in_terms_of)
- commodity = amount_t::current_pool->find_or_create(*in_terms_of);
+ if (env.has(2))
+ commodity = amount_t::current_pool->find_or_create(env.get<string>(2));
- DEBUG("report.market", "getting market value of: " << args[0]);
+ DEBUG("report.market", "getting market value of: " << env.value_at(0));
value_t result =
- args[0].value(date ? optional<datetime_t>(*date) : optional<datetime_t>(),
- commodity ? optional<commodity_t&>(*commodity) :
- optional<commodity_t&>());
+ env.value_at(0).value(env.has(1) ?
+ env.get<datetime_t>(1) : optional<datetime_t>(),
+ commodity ?
+ optional<commodity_t&>(*commodity) :
+ optional<commodity_t&>());
DEBUG("report.market", "result is: " << result);
return result;
@@ -160,28 +162,24 @@ value_t report_t::fn_quantity(call_scope_t& args)
value_t report_t::fn_truncate(call_scope_t& args)
{
- var_t<long> width(args, 1);
- var_t<long> account_abbrev(args, 2);
-
- return string_value(format_t::truncate(args[0].as_string(),
- width && *width > 0 ? *width : 0,
- account_abbrev ? *account_abbrev : -1));
+ interactive_t env(args, "v&ll");
+ return string_value(format_t::truncate
+ (env.get<string>(0),
+ env.has(1) && env.get<long>(1) > 0 ? env.get<long>(1) : 0,
+ env.has(2) ? env.get<long>(2) : -1));
}
value_t report_t::fn_print(call_scope_t& args)
{
- var_t<long> first_width(args, 1);
- var_t<long> latter_width(args, 2);
- var_t<string> date_format(args, 3);
-
+ interactive_t env(args, "vl&ls");
std::ostringstream out;
-
- args[0].strip_annotations(what_to_keep())
- .print(out, *first_width, latter_width ? *latter_width : -1,
- date_format ? *date_format :
+ env.value_at(0)
+ .strip_annotations(what_to_keep())
+ .print(out, env.get<long>(1),
+ env.has(2) ? env.get<long>(2) : -1,
+ env.has(3) ? env.get<string>(3) :
(HANDLED(date_format_) ?
HANDLER(date_format_).str() : optional<string>()));
-
return string_value(out.str());
}
diff --git a/src/report.h b/src/report.h
index a4020af8..f0408e89 100644
--- a/src/report.h
+++ b/src/report.h
@@ -502,13 +502,13 @@ public:
"3 + date_width + payee_width + account_width + amount_width))"
" %(print(strip(display_total), total_width, "
"4 + date_width + payee_width + account_width + amount_width "
- "+ total_width, true))\n%/"
+ "+ total_width))\n%/"
"%(print(\" \", 2 + date_width + payee_width))"
"%(print(truncate(account, account_width, abbrev_len), account_width))"
" %(print(strip(display_amount), amount_width, 3 + date_width "
"+ payee_width + account_width + amount_width))"
" %(print(strip(display_total), total_width, 4 + date_width "
- "+ payee_width + account_width + amount_width + total_width, true))\n");
+ "+ payee_width + account_width + amount_width + total_width))\n");
});
OPTION(report_t, related); // -r
diff --git a/src/scope.cc b/src/scope.cc
index 660f1af2..f4b2dfab 100644
--- a/src/scope.cc
+++ b/src/scope.cc
@@ -60,21 +60,4 @@ expr_t::ptr_op_t symbol_scope_t::lookup(const string& name)
return child_scope_t::lookup(name);
}
-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) {
- buf << args[i];
- first = false;
- } else {
- buf << ' ' << args[i];
- }
- }
-
- return buf.str();
-}
-
} // namespace ledger
diff --git a/src/scope.h b/src/scope.h
index b49e3ebe..1cc2858e 100644
--- a/src/scope.h
+++ b/src/scope.h
@@ -158,13 +158,9 @@ public:
}
void set_args(const value_t& _args) {
- if (_args.is_sequence())
- args = _args;
- else
- args = _args.to_sequence();
+ args = _args;
}
value_t& value() {
- assert(args.is_null() || args.is_sequence());
return args;
}
@@ -291,97 +287,6 @@ public:
T * operator->() { return value; }
};
-/**
- * @brief Brief
- *
- * Long.
- */
-template <typename T>
-class var_t : public noncopyable
-{
- optional<value_t> value;
-
- var_t();
-
-public:
- var_t(scope_t& scope, const string& name)
- {
- TRACE_CTOR(var_t, "scope_t&, const string&");
-
- try {
- value = scope.resolve(name);
- }
- catch (...) {
- DEBUG("scope.var_t", "Failed lookup var_t(\"" << name << "\")");
- value = none;
- }
- }
-
- var_t(call_scope_t& scope, const std::size_t idx)
- {
- TRACE_CTOR(var_t, "call_scope_t&, const std::size_t");
-
- if (idx < scope.size())
- value = scope[idx];
- else
- value = none;
- }
-
- ~var_t() throw() {
- TRACE_DTOR(var_t);
- }
-
- operator bool() { return value; }
-
- T operator *();
- T operator *() const;
-
- T * operator->() {
- return &**this;
- }
- const T * operator->() const {
- return &**this;
- }
-};
-
-template <>
-inline bool var_t<bool>::operator *() {
- return value->to_boolean();
-}
-template <>
-inline bool var_t<bool>::operator *() const {
- return value->to_boolean();
-}
-
-template <>
-inline long var_t<long>::operator *() {
- return value->to_long();
-}
-template <>
-inline long var_t<long>::operator *() const {
- return value->to_long();
-}
-
-template <>
-inline string var_t<string>::operator *() {
- return value->to_string();
-}
-template <>
-inline string var_t<string>::operator *() const {
- return value->to_string();
-}
-
-template <>
-inline datetime_t var_t<datetime_t>::operator *() {
- return value->to_datetime();
-}
-template <>
-inline datetime_t var_t<datetime_t>::operator *() const {
- return value->to_datetime();
-}
-
-string join_args(call_scope_t& args);
-
} // namespace ledger
#endif // _SCOPE_H
diff --git a/src/xact.cc b/src/xact.cc
index 71fba7a7..ca0b9baf 100644
--- a/src/xact.cc
+++ b/src/xact.cc
@@ -32,6 +32,7 @@
#include "xact.h"
#include "journal.h"
#include "account.h"
+#include "interactive.h"
#include "format.h"
namespace ledger {
@@ -186,17 +187,15 @@ namespace {
value_t get_account(call_scope_t& scope)
{
- xact_t& xact(find_scope<xact_t>(scope));
+ in_context_t<xact_t> env(scope, "&l");
- var_t<long> max_width(scope, 0);
+ string name = env->reported_account()->fullname();
- string name = xact.reported_account()->fullname();
+ if (env.has(0) && env.get<long>(0) > 2)
+ name = format_t::truncate(name, env.get<long>(0) - 2, true);
- if (max_width && *max_width > 2)
- name = format_t::truncate(name, *max_width - 2, true);
-
- if (xact.has_flags(XACT_VIRTUAL)) {
- if (xact.must_balance())
+ if (env->has_flags(XACT_VIRTUAL)) {
+ if (env->must_balance())
name = string("[") + name + "]";
else
name = string("(") + name + ")";