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)
|
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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
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