Corrected handling of nested definitions
This commit is contained in:
parent
36922c5945
commit
c47350dce9
5 changed files with 65 additions and 26 deletions
73
src/op.cc
73
src/op.cc
|
|
@ -78,11 +78,19 @@ namespace {
|
|||
|
||||
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()) {
|
||||
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));
|
||||
ptr_op_t rhs(kind > UNARY_OPERATORS && has_right() ?
|
||||
(kind == O_LOOKUP ? right() :
|
||||
right()->compile(*scope_ptr, depth)) : NULL);
|
||||
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 + 1)) : NULL);
|
||||
|
||||
if (lhs == left() && (! rhs || rhs == right()))
|
||||
return this;
|
||||
if (lhs == left() && (! rhs || rhs == right())) {
|
||||
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 ((! lhs || lhs->is_value()) && (! rhs || rhs->is_value()))
|
||||
return wrap_value(intermediate->calc(*scope_ptr, NULL, depth + 1));
|
||||
#if defined(DEBUG_ON)
|
||||
if (SHOW_DEBUG("expr.compile")) {
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
3
test/baseline/cmd-script.test
Normal file
3
test/baseline/cmd-script.test
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
test eval 'foo(w, u)=(z=w+u;z*2); (a=1 + 1; foo(10, 15))'
|
||||
50
|
||||
end test
|
||||
3
test/baseline/cmd-script_2.test
Normal file
3
test/baseline/cmd-script_2.test
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
test eval 'x=total_expr;x=x/count;x=amount_expr-x*count;x'
|
||||
0
|
||||
end test
|
||||
Loading…
Add table
Reference in a new issue