summaryrefslogtreecommitdiff
path: root/src/op.cc
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2012-02-21 01:45:26 -0600
committerJohn Wiegley <johnw@newartisans.com>2012-02-21 01:45:26 -0600
commit1837e323916c7479623bb61e479407b85edee562 (patch)
treee44cd8458af9f8e81a04f3effe8e3885d17b1900 /src/op.cc
parentbc9ff7095fbfa1812e4f47dbf8531dec76cd0d00 (diff)
downloadfork-ledger-1837e323916c7479623bb61e479407b85edee562.tar.gz
fork-ledger-1837e323916c7479623bb61e479407b85edee562.tar.bz2
fork-ledger-1837e323916c7479623bb61e479407b85edee562.zip
The new SCOPE mechanism is working
Diffstat (limited to 'src/op.cc')
-rw-r--r--src/op.cc139
1 files changed, 57 insertions, 82 deletions
diff --git a/src/op.cc b/src/op.cc
index d5a589c8..bf6fa543 100644
--- a/src/op.cc
+++ b/src/op.cc
@@ -81,7 +81,7 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope, const int depth)
scope_t * scope_ptr = &scope;
if (is_ident()) {
- DEBUG("expr.compile", "lookup: " << as_ident());
+ DEBUG("expr.compile", "Lookup: " << as_ident());
if (ptr_op_t def = scope_ptr->lookup(symbol_t::FUNCTION, as_ident())) {
// Identifier references are first looked up at the point of
@@ -93,7 +93,7 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope, const int depth)
def->dump(*_log_stream, 0);
}
#endif // defined(DEBUG_ON)
- return copy(def);
+ return copy(def);
}
else if (left()) {
return copy();
@@ -102,7 +102,6 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope, const int depth)
}
else if (is_scope()) {
shared_ptr<scope_t> subscope(new symbol_scope_t(scope));
- DEBUG("expr.compile", "creating scope");
set_scope(subscope);
scope_ptr = subscope.get();
}
@@ -114,22 +113,21 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope, const int depth)
case IDENT:
scope_ptr->define(symbol_t::FUNCTION, left()->as_ident(), right());
break;
+
case O_CALL:
if (left()->left()->is_ident()) {
ptr_op_t node(new op_t(op_t::O_LAMBDA));
node->set_left(left()->right());
node->set_right(right());
-
scope_ptr->define(symbol_t::FUNCTION, left()->left()->as_ident(),
node);
- } else {
- throw_(compile_error, _("Invalid function definition"));
+ break;
}
- break;
+ // fall through...
+
default:
throw_(compile_error, _("Invalid function definition"));
}
- return wrap_value(NULL_VALUE);
}
ptr_op_t lhs(left()->compile(*scope_ptr, depth));
@@ -144,7 +142,7 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope, const int depth)
// Reduce constants immediately if possible
if ((! lhs || lhs->is_value()) && (! rhs || rhs->is_value()))
- return wrap_value(intermediate->calc(*scope_ptr, NULL, depth));
+ return wrap_value(intermediate->calc(*scope_ptr, NULL, depth + 1));
return intermediate;
}
@@ -159,7 +157,7 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
if (SHOW_DEBUG("expr.calc")) {
for (int i = 0; i < depth; i++)
ledger::_log_buffer << '.';
- ledger::_log_buffer << op_context(this) << " => ...";
+ ledger::_log_buffer << op_context(this) << " => ...";
DEBUG("expr.calc", "");
}
#endif
@@ -170,84 +168,48 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
break;
case O_DEFINE:
- //result = left()->calc(scope, locus, depth + 1);
result = NULL_VALUE;
break;
case IDENT: {
ptr_op_t definition = left();
+ // If no definition was pre-compiled for this identifier, look it up
+ // in the current scope.
if (! definition) {
- // If no definition was pre-compiled for this identifier, look it
- // up in the current scope.
+ DEBUG("scope.symbols", "Looking for IDENT '" << as_ident() << "'");
definition = scope.lookup(symbol_t::FUNCTION, as_ident());
}
if (! definition)
throw_(calc_error, _("Unknown identifier '%1'") << as_ident());
// 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, locus, depth);
- result = definition->compile(call_args, depth + 1)
- ->calc(call_args, locus, depth + 1);
+ // directly
+ result = definition->calc(scope, locus, depth + 1);
check_type_context(scope, result);
break;
}
case FUNCTION: {
- // 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, locus, 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, locus, depth + 1);
result = as_function()(call_args);
check_type_context(scope, result);
break;
}
case SCOPE:
+ assert(! is_scope_unset());
if (is_scope_unset()) {
symbol_scope_t subscope(scope);
result = left()->calc(subscope, locus, depth + 1);
} else {
- result = left()->calc(*as_scope(), locus, depth + 1);
+ bind_scope_t bound_scope(scope, *as_scope());
+ result = left()->calc(bound_scope, locus, depth + 1);
}
break;
- case O_LAMBDA: {
- call_scope_t& call_args(downcast<call_scope_t>(scope));
- std::size_t args_count(call_args.size());
- std::size_t args_index(0);
- symbol_scope_t call_scope(call_args);
- ptr_op_t sym(left());
-
- for (; sym; sym = sym->has_right() ? sym->right() : NULL) {
- ptr_op_t varname = sym;
- if (sym->kind == O_CONS)
- varname = sym->left();
-
- if (! varname->is_ident()) {
- throw_(calc_error, _("Invalid function definition"));
- }
- else if (args_index == args_count) {
- call_scope.define(symbol_t::FUNCTION, varname->as_ident(),
- wrap_value(NULL_VALUE));
- }
- else {
- DEBUG("expr.compile",
- "Defining function parameter " << varname->as_ident());
- call_scope.define(symbol_t::FUNCTION, varname->as_ident(),
- wrap_value(call_args[args_index++]));
- }
- }
-
- if (args_index < args_count)
- throw_(calc_error,
- _("Too few arguments in function call (saw %1)") << args_count);
-
- result = right()->calc(call_scope, locus, depth + 1);
- break;
- }
-
case O_LOOKUP: {
context_scope_t context_scope(scope, value_t::SCOPE);
bool scope_error = true;
@@ -264,10 +226,6 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
}
case O_CALL: {
- call_scope_t call_args(scope, locus, depth);
- if (has_right())
- call_args.set_args(split_cons_expr(right()));
-
ptr_op_t func = left();
const string& name(func->as_ident());
@@ -277,20 +235,9 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
if (! func)
throw_(calc_error, _("Calling unknown function '%1'") << name);
-#if defined(DEBUG_ON)
- if (SHOW_DEBUG("expr.calc")) {
- for (int i = 0; i < depth; i++)
- ledger::_log_buffer << '.';
- ledger::_log_buffer << " args: ";
- if (call_args.args.is_sequence()) {
- foreach (value_t& arg, call_args)
- ledger::_log_buffer << arg << " ";
- } else {
- ledger::_log_buffer << call_args.args[0] << " ";
- }
- DEBUG("expr.calc", "");
- }
-#endif
+ call_scope_t call_args(scope, locus, depth + 1);
+ if (has_right())
+ call_args.set_args(split_cons_expr(right()));
if (func->is_function())
result = func->as_function()(call_args);
@@ -301,6 +248,39 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
break;
}
+ case O_LAMBDA: {
+ call_scope_t& call_args(downcast<call_scope_t>(scope));
+ std::size_t args_count(call_args.size());
+ std::size_t args_index(0);
+ symbol_scope_t call_scope(call_args);
+
+ for (ptr_op_t sym = left();
+ sym;
+ sym = sym->has_right() ? sym->right() : NULL) {
+ ptr_op_t varname = sym->kind == O_CONS ? sym->left() : sym;
+ if (! varname->is_ident()) {
+ throw_(calc_error, _("Invalid function definition"));
+ }
+ else if (args_index == args_count) {
+ call_scope.define(symbol_t::FUNCTION, varname->as_ident(),
+ wrap_value(NULL_VALUE));
+ }
+ else {
+ DEBUG("expr.compile",
+ "Defining function parameter " << varname->as_ident());
+ call_scope.define(symbol_t::FUNCTION, varname->as_ident(),
+ wrap_value(call_args[args_index++]));
+ }
+ }
+
+ if (args_index < args_count)
+ throw_(calc_error,
+ _("Too few arguments in function call (saw %1)") << args_count);
+
+ result = right()->calc(call_scope, locus, depth + 1);
+ break;
+ }
+
case O_MATCH:
result = (right()->calc(scope, locus, depth + 1).as_mask()
.match(left()->calc(scope, locus, depth + 1).to_string()));
@@ -369,7 +349,6 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
case O_QUERY:
assert(right());
assert(right()->kind == O_COLON);
-
if (value_t temp = left()->calc(scope, locus, depth + 1))
result = right()->left()->calc(scope, locus, depth + 1);
else
@@ -382,8 +361,6 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
case O_CONS:
result = left()->calc(scope, locus, depth + 1);
- DEBUG("op.cons", "car = " << result);
-
if (has_right()) {
value_t temp;
temp.push_back(result);
@@ -399,7 +376,6 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
next = NULL;
}
temp.push_back(value_op->calc(scope, locus, depth + 1));
- DEBUG("op.cons", "temp now = " << temp);
}
result = temp;
}
@@ -413,7 +389,6 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
// onto the stack. We evaluate the left side here to catch any
// side-effects, such as definitions in the case of 'x = 1; x'.
result = left()->calc(scope, locus, depth + 1);
-
if (has_right()) {
ptr_op_t next = right();
while (next) {
@@ -786,7 +761,7 @@ void expr_t::op_t::dump(std::ostream& out, const int depth) const
// An identifier is a special non-terminal, in that its left() can
// hold the compiled definition of the identifier.
- if (kind > TERMINALS || is_ident() || is_scope()) {
+ if (kind > TERMINALS || is_scope()) {
if (left()) {
left()->dump(out, depth + 1);
if (kind > UNARY_OPERATORS && has_right())