From 8b5b243cab74cc3c930ed58ff7f44e4b375ecc62 Mon Sep 17 00:00:00 2001 From: bog Date: Tue, 12 Sep 2023 21:11:29 +0200 Subject: [PATCH] ADD: function capture env (closure). --- examples/block.gri | 6 ++- examples/fun.gri | 23 +++++++++- lib/core.cpp | 10 +---- src/Compiler.cpp | 5 --- src/Function.cpp | 5 +++ src/Function.hpp | 1 + src/VM.cpp | 108 +++++++++++++++++++++++++++++++++++++++------ src/opcodes.hpp | 2 - 8 files changed, 128 insertions(+), 32 deletions(-) diff --git a/examples/block.gri b/examples/block.gri index b1dae9f..9ac4189 100644 --- a/examples/block.gri +++ b/examples/block.gri @@ -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) ) \ No newline at end of file diff --git a/examples/fun.gri b/examples/fun.gri index ce3b68e..feee774 100644 --- a/examples/fun.gri +++ b/examples/fun.gri @@ -71,4 +71,25 @@ (assert-eq? 3 (j)) (assert-eq? 4 (j)) (assert-eq? 5 (j)) -(assert-eq? 20 (k)) \ No newline at end of file +(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) \ No newline at end of file diff --git a/lib/core.cpp b/lib/core.cpp index ac1a613..e67810e 100644 --- a/lib/core.cpp +++ b/lib/core.cpp @@ -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())); diff --git a/src/Compiler.cpp b/src/Compiler.cpp index f7dfedc..69e92e1 100644 --- a/src/Compiler.cpp +++ b/src/Compiler.cpp @@ -160,11 +160,6 @@ namespace grino ss << "undefined variable '" << ident << "'"; m_logger.log(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); diff --git a/src/Function.cpp b/src/Function.cpp index 27931cc..577fb09 100644 --- a/src/Function.cpp +++ b/src/Function.cpp @@ -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 Function::env(size_t addr) const { return m_env.at(addr); diff --git a/src/Function.hpp b/src/Function.hpp index bceaf66..36b6fee 100644 --- a/src/Function.hpp +++ b/src/Function.hpp @@ -25,6 +25,7 @@ namespace grino std::shared_ptr program() const; value_t call(args_t args); + bool has_env(size_t addr) const; std::shared_ptr env(size_t addr) const; void set_env(size_t addr, std::shared_ptr value); diff --git a/src/VM.cpp b/src/VM.cpp index ec2673c..395eb91 100644 --- a/src/VM.cpp +++ b/src/VM.cpp @@ -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; iset_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; isecond)); + + 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; diff --git a/src/opcodes.hpp b/src/opcodes.hpp index 6548762..d852cae 100644 --- a/src/opcodes.hpp +++ b/src/opcodes.hpp @@ -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), \