diff options
author | John Wiegley <johnw@newartisans.com> | 2010-06-12 22:18:16 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2010-06-13 01:03:48 -0400 |
commit | 1bc5b894dfd9412a60c4db16e9a4e49ddddad5fd (patch) | |
tree | 482c6d0143b56c61b43fadb141384fb89184279e /src | |
parent | 536e3e73228b6168437704ede89499406b87391d (diff) | |
download | fork-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.cc | 6 | ||||
-rw-r--r-- | src/op.cc | 15 | ||||
-rw-r--r-- | src/post.cc | 40 | ||||
-rw-r--r-- | src/scope.h | 31 |
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()); } } @@ -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); |