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

@ -78,11 +78,19 @@ namespace {
expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope, const int depth) expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope, const int depth)
{ {
scope_t * scope_ptr = &scope; 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()) { 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())) { if (ptr_op_t def = scope_ptr->lookup(symbol_t::FUNCTION, as_ident())) {
// Identifier references are first looked up at the point of // Identifier references are first looked up at the point of
// definition, and then at the point of every use if they could // 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); def->dump(*_log_stream, 0);
} }
#endif // defined(DEBUG_ON) #endif // defined(DEBUG_ON)
return copy(def); result = copy(def);
} }
else if (left()) { else if (left()) {
return copy(); result = copy();
}
else {
result = this;
} }
return this;
} }
else if (is_scope()) { else if (is_scope()) {
shared_ptr<scope_t> subscope(new symbol_scope_t(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(); scope_ptr = subscope.get();
} }
else if (kind < TERMINALS) { else if (kind < TERMINALS) {
return this; result = this;
} }
else if (kind == O_DEFINE) { else if (kind == O_DEFINE) {
switch (left()->kind) { switch (left()->kind) {
case IDENT: case IDENT: {
scope_ptr->define(symbol_t::FUNCTION, left()->as_ident(), right()); 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; break;
}
case O_CALL: case O_CALL:
if (left()->left()->is_ident()) { if (left()->left()->is_ident()) {
ptr_op_t node(new op_t(op_t::O_LAMBDA)); ptr_op_t node(new op_t(op_t::O_LAMBDA));
node->set_left(left()->right()); node->set_left(left()->right());
node->set_right(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(), scope_ptr->define(symbol_t::FUNCTION, left()->left()->as_ident(),
node); node);
break; break;
@ -128,23 +147,37 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope, const int depth)
default: default:
throw_(compile_error, _("Invalid function definition")); 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 rhs(kind > UNARY_OPERATORS && has_right() ? ptr_op_t lhs(left()->compile(*scope_ptr, depth + 1));
(kind == O_LOOKUP ? right() : ptr_op_t rhs(kind > UNARY_OPERATORS && has_right() ?
right()->compile(*scope_ptr, depth)) : NULL); (kind == O_LOOKUP ? right() :
right()->compile(*scope_ptr, depth + 1)) : NULL);
if (lhs == left() && (! rhs || rhs == right())) if (lhs == left() && (! rhs || rhs == right())) {
return this; result = this;
} else {
ptr_op_t intermediate(copy(lhs, rhs));
ptr_op_t intermediate(copy(lhs, rhs)); // Reduce constants immediately if possible
if ((! lhs || lhs->is_value()) && (! rhs || rhs->is_value()))
result = wrap_value(intermediate->calc(*scope_ptr, NULL, depth + 1));
else
result = intermediate;
}
}
// Reduce constants immediately if possible #if defined(DEBUG_ON)
if ((! lhs || lhs->is_value()) && (! rhs || rhs->is_value())) if (SHOW_DEBUG("expr.compile")) {
return wrap_value(intermediate->calc(*scope_ptr, NULL, depth + 1)); for (int i = 0; i < depth; i++)
ledger::_log_buffer << '.';
DEBUG("expr.compile", "");
}
#endif
return intermediate; return result;
} }
value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth) 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)); ptr_op_t seq(new op_t(op_t::O_SEQ));
if (! chain) { if (! chain) {
seq->set_left(node); seq->set_left(node);
ptr_op_t scope(new op_t(op_t::SCOPE)); node = seq;
scope->set_left(seq);
node = scope;
} else { } else {
seq->set_left(chain->right()); seq->set_left(chain->right());
ptr_op_t scope(new op_t(op_t::SCOPE)); chain->set_right(seq);
scope->set_left(seq);
chain->set_right(scope);
} }
seq->set_right(parse_assign_expr(in, tflags)); seq->set_right(parse_assign_expr(in, tflags));
chain = seq; 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")) if (is_eq(p, "query"))
return WRAP_FUNCTOR(query_command); return WRAP_FUNCTOR(query_command);
break; break;
case 's':
if (is_eq(p, "script"))
return WRAP_FUNCTOR(source_command);
break;
case 't': case 't':
if (is_eq(p, "template")) if (is_eq(p, "template"))
return WRAP_FUNCTOR(template_command); 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