summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2010-06-12 22:18:16 -0400
committerJohn Wiegley <johnw@newartisans.com>2010-06-13 01:03:48 -0400
commit1bc5b894dfd9412a60c4db16e9a4e49ddddad5fd (patch)
tree482c6d0143b56c61b43fadb141384fb89184279e /src
parent536e3e73228b6168437704ede89499406b87391d (diff)
downloadfork-ledger-1bc5b894dfd9412a60c4db16e9a4e49ddddad5fd.tar.gz
fork-ledger-1bc5b894dfd9412a60c4db16e9a4e49ddddad5fd.tar.bz2
fork-ledger-1bc5b894dfd9412a60c4db16e9a4e49ddddad5fd.zip
Expression evaluations now have a "type context"
Thus, an expression can know if the context in which it's being evaluated requires a string, and if so, determine it's output accordingly. For example: account ; returns the full name of the posting's account account.total ; here the context is SCOPE, so account is an obj
Diffstat (limited to 'src')
-rw-r--r--src/account.cc6
-rw-r--r--src/op.cc15
-rw-r--r--src/post.cc40
-rw-r--r--src/scope.h31
4 files changed, 54 insertions, 38 deletions
diff --git a/src/account.cc b/src/account.cc
index 606562b8..f26b7913 100644
--- a/src/account.cc
+++ b/src/account.cc
@@ -208,7 +208,11 @@ namespace {
return scope_value(acct->find_account_re(args.get<mask_t>(0).str()));
else
return NULL_VALUE;
- } else {
+ }
+ else if (scope.type_context() == value_t::SCOPE) {
+ return scope_value(&account);
+ }
+ else {
return string_value(account.fullname());
}
}
diff --git a/src/op.cc b/src/op.cc
index 9497e068..8f73493d 100644
--- a/src/op.cc
+++ b/src/op.cc
@@ -39,7 +39,8 @@
namespace ledger {
namespace {
- value_t split_cons_expr(expr_t::ptr_op_t op, scope_t& scope,
+ value_t split_cons_expr(expr_t::ptr_op_t op,
+ scope_t& scope,
std::vector<expr_t>& exprs)
{
value_t seq;
@@ -150,7 +151,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);
+ call_scope_t call_args(scope, scope.type_context());
result = left()->compile(call_args, depth + 1)
->calc(call_args, locus, depth + 1);
break;
@@ -160,7 +161,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);
+ call_scope_t call_args(scope, scope.type_context());
result = as_function()(call_args);
#if defined(DEBUG_ON)
skip_debug = true;
@@ -200,8 +201,9 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
break;
}
- case O_LOOKUP:
- if (value_t obj = left()->calc(scope, locus, depth + 1)) {
+ case O_LOOKUP: {
+ context_scope_t context_scope(scope, value_t::SCOPE);
+ if (value_t obj = left()->calc(context_scope, locus, depth + 1)) {
if (obj.is_scope()) {
if (obj.as_scope() == NULL) {
throw_(calc_error, _("Left operand of . operator is NULL"));
@@ -222,10 +224,11 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
throw_(calc_error,
_("Failed to lookup member '%1'") << right()->as_ident());
break;
+ }
case O_CALL:
case O_EXPAND: {
- call_scope_t call_args(scope);
+ 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;
diff --git a/src/post.cc b/src/post.cc
index da892062..d4a16122 100644
--- a/src/post.cc
+++ b/src/post.cc
@@ -254,20 +254,20 @@ namespace {
return 1L;
}
- value_t account_name(call_scope_t& scope)
+ value_t get_account(call_scope_t& scope)
{
in_context_t<post_t> env(scope, "&v");
-
- string name;
+ account_t& account(*env->reported_account());
+ string name;
if (env.has(0)) {
if (env.value_at(0).is_long()) {
if (env.get<long>(0) > 2)
- name = format_t::truncate(env->reported_account()->fullname(),
+ name = format_t::truncate(account.fullname(),
env.get<long>(0) - 2,
2 /* account_abbrev_length */);
else
- name = env->reported_account()->fullname();
+ name = account.fullname();
} else {
account_t * account = NULL;
account_t * master = env->account;
@@ -294,8 +294,12 @@ namespace {
else
return value_t(static_cast<scope_t *>(account));
}
- } else {
- name = env->reported_account()->fullname();
+ }
+ else if (scope.type_context() == value_t::SCOPE) {
+ return scope_value(&account);
+ }
+ else {
+ name = account.fullname();
}
return string_value(name);
}
@@ -304,7 +308,7 @@ namespace {
{
in_context_t<post_t> env(scope, "&v");
- value_t acct = account_name(scope);
+ value_t acct = get_account(scope);
if (acct.is_string()) {
if (env->has_flags(POST_VIRTUAL)) {
if (env->must_balance())
@@ -316,26 +320,6 @@ namespace {
return acct;
}
- value_t get_account(call_scope_t& scope)
- {
- interactive_t args(scope, "&v");
- account_t& account(*find_scope<post_t>(scope).account);
- if (args.has(0)) {
- account_t * acct = account.parent;
- for (; acct && acct->parent; acct = acct->parent) ;
- if (scope[0].is_string())
- return value_t(static_cast<scope_t *>
- (acct->find_account(args.get<string>(0), false)));
- else if (scope[0].is_mask())
- return value_t(static_cast<scope_t *>
- (acct->find_account_re(args.get<mask_t>(0).str())));
- else
- return NULL_VALUE;
- } else {
- return account_name(scope);
- }
- }
-
value_t get_account_id(post_t& post) {
return static_cast<long>(post.account_id());
}
diff --git a/src/scope.h b/src/scope.h
index e3dd3e3f..1b10d7a6 100644
--- a/src/scope.h
+++ b/src/scope.h
@@ -114,6 +114,10 @@ public:
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind,
const string& name) = 0;
+ virtual value_t::type_t type_context() const {
+ return value_t::VOID;
+ }
+
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
@@ -205,13 +209,34 @@ private:
#endif // HAVE_BOOST_SERIALIZATION
};
-class call_scope_t : public child_scope_t
+class context_scope_t : public child_scope_t
+{
+ value_t::type_t value_type_context;
+
+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");
+ }
+ virtual ~context_scope_t() {
+ TRACE_DTOR(context_scope_t);
+ }
+
+ virtual value_t::type_t type_context() const {
+ return value_type_context;
+ }
+};
+
+class call_scope_t : public context_scope_t
{
value_t args;
public:
- explicit call_scope_t(scope_t& _parent) : child_scope_t(_parent) {
- TRACE_CTOR(call_scope_t, "scope_t&");
+ 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");
}
virtual ~call_scope_t() {
TRACE_DTOR(call_scope_t);