ADD: function capture env (closure).

main
bog 2023-09-12 21:11:29 +02:00
parent 83f1cc97b9
commit 8b5b243cab
8 changed files with 128 additions and 32 deletions

View File

@ -4,11 +4,15 @@
(:
($ a 4)
(assert-eq? 4 a)
(set! a 42)
(assert-eq? 42 a)
(:
($ a 7)
(assert-eq? 7 a)
(set! a 32)
(assert-eq? 32 a)
)
(assert-eq? 4 a)
(assert-eq? 42 a)
)

View File

@ -71,4 +71,25 @@
(assert-eq? 3 (j))
(assert-eq? 4 (j))
(assert-eq? 5 (j))
(assert-eq? 20 (k))
(assert-eq? 20 (k))
($ m 1)
($ (n)
($ counter 0)
(-> ()
(set! counter (* 2 m))
(set! m (+ 1 m))
counter))
($ o (n))
($ p (n))
(assert-eq? 2 (o))
(assert-eq? 4 (o))
(assert-eq? 6 (o))
(assert-eq? 2 (p))
(assert-eq? 4 (p))
(assert-eq? 6 (p))
(assert-eq? 1 m)

View File

@ -358,15 +358,7 @@ extern "C" void lib(grino::Loader& loader)
if (entry)
{
compiler.compile(expr, program, sym);
if (entry->scope == compiler.scope()-1)
{
program.push_instr(grino::OPCODE_STORE_CLOSURE, entry->addr);
}
else
{
program.push_instr(grino::OPCODE_STORE_LOCAL, entry->addr);
}
program.push_instr(grino::OPCODE_STORE_LOCAL, entry->addr);
}
program.push_value(grino::Value::make_nil(node->loc()));

View File

@ -160,11 +160,6 @@ namespace grino
ss << "undefined variable '" << ident << "'";
m_logger.log<compile_error>(LOG_ERROR, node->loc(), ss.str());
}
else if (entry->is_object == false
&& entry->scope < scope())
{
program.push_instr(OPCODE_LOAD_CLOSURE, entry->addr);
}
else if (entry->is_object)
{
program.push_instr(OPCODE_LOAD_OBJ, entry->addr);

View File

@ -36,6 +36,11 @@ namespace grino
return m_native(args);
}
bool Function::has_env(size_t addr) const
{
return m_env.find(addr) != std::end(m_env);
}
std::shared_ptr<Value> Function::env(size_t addr) const
{
return m_env.at(addr);

View File

@ -25,6 +25,7 @@ namespace grino
std::shared_ptr<Program> program() const;
value_t call(args_t args);
bool has_env(size_t addr) const;
std::shared_ptr<Value> env(size_t addr) const;
void set_env(size_t addr, std::shared_ptr<Value> value);

View File

@ -31,18 +31,6 @@ namespace grino
switch (instr.opcode)
{
case OPCODE_LOAD_CLOSURE: {
auto val = m_frames.back().function->env(*instr.param);
push(program().push_constant(val));
m_pc++;
} break;
case OPCODE_STORE_CLOSURE: {
auto val = program().constant(pop());
m_frames.back().function->set_env(*instr.param, val);
m_pc++;
} break;
case OPCODE_MK_FUN: {
auto prog_val = program().constant(pop());
auto prog = prog_val->as_program();
@ -109,13 +97,105 @@ namespace grino
case OPCODE_STORE_LOCAL: {
size_t addr = *instr.param;
auto value = program().constant(top());
set_local(addr, value);
bool found = false;
if (auto itr=m_frames.back().locals.find(addr);
itr != std::end(m_frames.back().locals))
{
m_frames.back().locals[addr] = value;
found = true;
}
else
{
auto fun = m_frames.back().function;
if (fun && fun->has_env(addr))
{
fun->set_env(addr, Value::make_copy(value->loc(), value));
found = true;
}
else
{
for (size_t i=0; i<m_frames.size(); i++)
{
size_t j = m_frames.size() - 1 - i;
if (auto itr=m_frames[j].locals.find(addr);
itr != std::end(m_frames[j].locals))
{
if (fun)
{
std::cout << "store INIT" << std::endl;
fun->set_env(itr->first,
Value::make_copy(itr->second->loc(),
itr->second));
}
found = true;
break;
}
}
}
}
if (!found)
{
m_frames.back().locals[addr] = value;
}
m_pc++;
} break;
case OPCODE_LOAD_LOCAL: {
size_t addr = *instr.param;
push(program().push_constant(local(addr)));
bool found = false;
if (auto itr=m_frames.back().locals.find(addr);
itr != std::end(m_frames.back().locals))
{
push(program().push_constant(itr->second));
found = true;
}
else
{
auto fun = m_frames.back().function;
if (fun && fun->has_env(addr))
{
push(program().push_constant(fun->env(addr)));
found = true;
}
else
{
for (size_t i=0; i<m_frames.size(); i++)
{
size_t j = m_frames.size() - 1 - i;
if (auto itr2=m_frames[j].locals.find(addr);
itr2 != std::end(m_frames[j].locals))
{
push(program().push_constant(itr2->second));
if (fun)
{
fun->set_env(itr2->first,
Value::make_copy(itr2->second->loc(),
itr2->second));
}
found = true;
break;
}
}
}
}
if (!found)
{
}
assert(found);
m_pc++;
} break;

View File

@ -11,8 +11,6 @@
G(OPCODE_STORE_LOCAL), \
G(OPCODE_LOAD_OBJ), \
G(OPCODE_STORE_OBJ), \
G(OPCODE_LOAD_CLOSURE), \
G(OPCODE_STORE_CLOSURE), \
G(OPCODE_CALL), \
G(OPCODE_BRF), \
G(OPCODE_BR), \