summaryrefslogtreecommitdiff
path: root/src/op.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/op.cc')
-rw-r--r--src/op.cc68
1 files changed, 33 insertions, 35 deletions
diff --git a/src/op.cc b/src/op.cc
index 9497e068..c2001ec3 100644
--- a/src/op.cc
+++ b/src/op.cc
@@ -39,14 +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) {
@@ -58,14 +55,24 @@ 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);
+ }
+ }
+
+ inline void check_type_context(scope_t& scope, value_t& result)
+ {
+ 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")
+ << result.label(scope.type_context())
+ << result.label());
}
- return seq;
}
}
@@ -150,9 +157,10 @@ 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(), scope.type_required());
result = left()->compile(call_args, depth + 1)
->calc(call_args, locus, depth + 1);
+ check_type_context(scope, result);
break;
}
@@ -160,8 +168,9 @@ 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(), scope.type_required());
result = as_function()(call_args);
+ check_type_context(scope, result);
#if defined(DEBUG_ON)
skip_debug = true;
#endif
@@ -200,8 +209,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,25 +232,13 @@ 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);
- // 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());
@@ -253,6 +251,8 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
result = func->as_function()(call_args);
else
result = func->calc(call_args, locus, depth + 1);
+
+ check_type_context(scope, result);
break;
}
@@ -638,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()) {
@@ -710,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;