Corrected handling of nested definitions

This commit is contained in:
John Wiegley 2012-02-21 03:53:00 -06:00
parent 36922c5945
commit c47350dce9
5 changed files with 65 additions and 26 deletions

View file

@ -79,10 +79,18 @@ namespace {
expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope, const int depth)
{
scope_t * scope_ptr = &scope;
expr_t::ptr_op_t result;
#if defined(DEBUG_ON)
if (SHOW_DEBUG("expr.compile")) {
for (int i = 0; i < depth; i++)
ledger::_log_buffer << '.';
DEBUG("expr.compile", "");
}
#endif
if (is_ident()) {
DEBUG("expr.compile", "Lookup: " << as_ident());
DEBUG("expr.compile", "Lookup: " << as_ident() << " in " << scope_ptr);
if (ptr_op_t def = scope_ptr->lookup(symbol_t::FUNCTION, as_ident())) {
// Identifier references are first looked up at the point of
// definition, and then at the point of every use if they could
@ -93,12 +101,14 @@ 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);
result = copy(def);
}
else if (left()) {
return copy();
result = copy();
}
else {
result = this;
}
return this;
}
else if (is_scope()) {
shared_ptr<scope_t> subscope(new symbol_scope_t(scope));
@ -106,19 +116,28 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope, const int depth)
scope_ptr = subscope.get();
}
else if (kind < TERMINALS) {
return this;
result = this;
}
else if (kind == O_DEFINE) {
switch (left()->kind) {
case IDENT:
scope_ptr->define(symbol_t::FUNCTION, left()->as_ident(), right());
case IDENT: {
ptr_op_t node(right()->compile(*scope_ptr, depth + 1));
DEBUG("expr.compile",
"Defining " << left()->as_ident() << " in " << scope_ptr);
scope_ptr->define(symbol_t::FUNCTION, left()->as_ident(), node);
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());
node = node->compile(*scope_ptr, depth + 1);
DEBUG("expr.compile",
"Defining " << left()->left()->as_ident() << " in " << scope_ptr);
scope_ptr->define(symbol_t::FUNCTION, left()->left()->as_ident(),
node);
break;
@ -128,23 +147,37 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope, const int depth)
default:
throw_(compile_error, _("Invalid function definition"));
}
result = wrap_value(NULL_VALUE);
}
ptr_op_t lhs(left()->compile(*scope_ptr, depth));
if (! result) {
ptr_op_t lhs(left()->compile(*scope_ptr, depth + 1));
ptr_op_t rhs(kind > UNARY_OPERATORS && has_right() ?
(kind == O_LOOKUP ? right() :
right()->compile(*scope_ptr, depth)) : NULL);
if (lhs == left() && (! rhs || rhs == right()))
return this;
right()->compile(*scope_ptr, depth + 1)) : NULL);
if (lhs == left() && (! rhs || rhs == right())) {
result = this;
} else {
ptr_op_t intermediate(copy(lhs, rhs));
// Reduce constants immediately if possible
if ((! lhs || lhs->is_value()) && (! rhs || rhs->is_value()))
return wrap_value(intermediate->calc(*scope_ptr, NULL, depth + 1));
result = wrap_value(intermediate->calc(*scope_ptr, NULL, depth + 1));
else
result = intermediate;
}
}
return intermediate;
#if defined(DEBUG_ON)
if (SHOW_DEBUG("expr.compile")) {
for (int i = 0; i < depth; i++)
ledger::_log_buffer << '.';
DEBUG("expr.compile", "");
}
#endif
return result;
}
value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)

View file

@ -517,14 +517,10 @@ expr_t::parser_t::parse_value_expr(std::istream& in,
ptr_op_t seq(new op_t(op_t::O_SEQ));
if (! chain) {
seq->set_left(node);
ptr_op_t scope(new op_t(op_t::SCOPE));
scope->set_left(seq);
node = scope;
node = seq;
} else {
seq->set_left(chain->right());
ptr_op_t scope(new op_t(op_t::SCOPE));
scope->set_left(seq);
chain->set_right(scope);
chain->set_right(seq);
}
seq->set_right(parse_assign_expr(in, tflags));
chain = seq;

View file

@ -1559,6 +1559,10 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
if (is_eq(p, "query"))
return WRAP_FUNCTOR(query_command);
break;
case 's':
if (is_eq(p, "script"))
return WRAP_FUNCTOR(source_command);
break;
case 't':
if (is_eq(p, "template"))
return WRAP_FUNCTOR(template_command);

View file

@ -0,0 +1,3 @@
test eval 'foo(w, u)=(z=w+u;z*2); (a=1 + 1; foo(10, 15))'
50
end test

View file

@ -0,0 +1,3 @@
test eval 'x=total_expr;x=x/count;x=amount_expr-x*count;x'
0
end test