diff options
author | John Wiegley <johnw@newartisans.com> | 2012-02-21 01:45:26 -0600 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2012-02-21 01:45:26 -0600 |
commit | 1837e323916c7479623bb61e479407b85edee562 (patch) | |
tree | e44cd8458af9f8e81a04f3effe8e3885d17b1900 /src/op.cc | |
parent | bc9ff7095fbfa1812e4f47dbf8531dec76cd0d00 (diff) | |
download | fork-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.cc | 139 |
1 files changed, 57 insertions, 82 deletions
@@ -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()) |