ADD: naive and simple closures.

main
bog 2023-09-22 22:04:57 +02:00
parent 9591d6c176
commit 22131c2cf0
12 changed files with 152 additions and 3 deletions

16
examples/closure.fk Normal file
View File

@ -0,0 +1,16 @@
($ mk-counter
(-> (init)
($ counter (- init 1))
(-> ()
(! counter (+ counter 1))
counter)))
($ a (mk-counter 5))
($ b (mk-counter 32))
(assert= 5 (a))
(assert= 32 (b))
(assert= 33 (b))
(assert= 6 (a))
(assert= 7 (a))
(assert= 34 (b))

View File

@ -9,9 +9,18 @@ namespace fkstd
{
auto ident = node->child(1)->repr();
compiler.compile_prog(node->child(2), program);
std::cout << "push " << node->child(2)->string() << std::endl;
auto entry = compiler.sym()->find(ident);
program->add(OP_STORE_LOCAL, entry->addr());
if (entry)
{
program->add(OP_STORE_LOCAL, entry->addr());
}
else
{
auto entry = compiler.sym()->find_global(ident);
program->add(OP_STORE_CLOSURE, entry->addr());
}
}
void assert_static_fail(Compiler& compiler,

View File

@ -146,6 +146,17 @@ namespace fk
case NODE_IDENT: {
auto entry = m_sym->find(node->repr());
if (!entry)
{
auto entry = m_sym->find_global(node->repr());
if (entry)
{
prog->add(OP_LOAD_CLOSURE, entry->addr());
break;
}
}
if (!entry)
{
std::stringstream ss;

View File

@ -14,6 +14,12 @@ namespace fk
{
}
std::shared_ptr<Constant> Constant::clone()
{
auto res = std::make_shared<Constant>(m_type, m_value, m_loc);
return res;
}
std::string Constant::string() const
{
switch (m_type)
@ -23,6 +29,7 @@ namespace fk
case TYPE_BOOL: return std::get<bool>(m_value) ? "true" : "false";
case TYPE_STRING: return std::get<std::string>(m_value);
case TYPE_REF: return std::to_string(std::get<size_t>(m_value));
case TYPE_PROGRAM: return "<program>";
default: {
std::stringstream ss;

View File

@ -25,6 +25,8 @@ namespace fk
explicit Constant(Type type, constant_t value, Loc const& loc);
virtual ~Constant();
std::shared_ptr<Constant> clone();
Type type() const { return m_type; }
constant_t value() const { return m_value; }
Loc loc() const { return m_loc; }

View File

@ -11,4 +11,23 @@ namespace fk
/*virtual*/ Lambda::~Lambda()
{
}
bool Lambda::has_env(addr_t addr) const
{
return m_env.find(addr) != std::end(m_env);
}
std::shared_ptr<Constant>
Lambda::get_env(addr_t addr) const
{
assert(has_env(addr));
return m_env.at(addr);
}
void
Lambda::add_env(addr_t addr, std::shared_ptr<Constant> constant)
{
m_env[addr] = constant;
}
}

View File

@ -4,6 +4,7 @@
#include "commons.hpp"
#include "SymTable.hpp"
#include "Program.hpp"
#include <unordered_map>
namespace fk
{
@ -18,8 +19,13 @@ namespace fk
std::shared_ptr<Program> program() const { return m_program; }
std::shared_ptr<SymTable> sym() const { return m_sym; }
bool has_env(addr_t addr) const;
std::shared_ptr<Constant> get_env(addr_t addr) const;
void add_env(addr_t addr, std::shared_ptr<Constant> constant);
private:
std::shared_ptr<Program> m_program;
std::unordered_map<addr_t, std::shared_ptr<Constant>> m_env;
size_t m_arity;
std::shared_ptr<SymTable> m_sym = std::make_shared<SymTable>();
};

View File

@ -89,6 +89,43 @@ namespace fk
return idx;
}
std::optional<SymEntry> SymTable::find_global(std::string const& name)
{
auto idx = find_idx_global(name);
if (!idx) { return std::nullopt; }
return m_entries[*idx];
}
std::optional<size_t> SymTable::find_idx_global(std::string const& name)
{
std::optional<SymEntry> result;
size_t i=0;
std::optional<size_t> idx;
for (auto& entry: m_entries)
{
if (entry.name() == name && entry.is_global())
{
result = entry;
idx = i;
}
else if (entry.name() == name
&& entry.scope() <= m_scope
&& (result == std::nullopt ||
entry.scope() > result->scope()))
{
result = entry;
idx = i;
}
i++;
}
return idx;
}
void SymTable::set(std::string const& name, addr_t addr)
{
if (auto idx = find_idx(name);

View File

@ -14,6 +14,8 @@ namespace fk
explicit SymTable();
virtual ~SymTable();
int scope() const { return m_scope; }
SymEntry& declare_local(std::string const& name,
addr_t addr,
Loc const& loc);
@ -24,6 +26,10 @@ namespace fk
std::optional<SymEntry> find(std::string const& name);
std::optional<size_t> find_idx(std::string const& name);
std::optional<SymEntry> find_global(std::string const& name);
std::optional<size_t> find_idx_global(std::string const& name);
void set(std::string const& name, addr_t addr);
std::string string() const;

View File

@ -29,6 +29,27 @@ namespace fk
switch (instr.opcode)
{
case OP_STORE_CLOSURE: {
auto val = frame().program->get_const(top());
auto lambda = frame().lambda;
lambda->add_env(instr.param, val);
m_pc++;
} break;
case OP_LOAD_CLOSURE: {
if (frame().lambda && frame().lambda->has_env(instr.param))
{
auto val = frame().lambda->get_env(instr.param);
addr_t addr = frame().program->add(val);
push(addr);
m_pc++;
break;
}
m_pc++;
} break;
case OP_BR: {
m_pc = instr.param;
} break;
@ -56,6 +77,14 @@ namespace fk
addr_t addr = store_global(lambda);
auto ref = std::make_shared<Constant>(TYPE_REF, addr, p->loc());
if (m_frames.size() > 1)
{
for (auto e: m_frames.back().locals)
{
lambda->add_env(e.first, e.second);
}
}
push(frame().program->add(ref));
m_pc++;
@ -114,6 +143,7 @@ namespace fk
ref_val->loc());
Frame frame;
frame.lambda = lambda;
frame.program = lambda->program();
frame.ret_addr = m_pc;
frame.stack_sz = m_stack.size();
@ -139,7 +169,9 @@ namespace fk
args.insert(std::begin(args),
frame().program->get_const(addr));
}
auto ref_val = frame().program->get_const(pop());
Loc loc = ref_val->loc();
if (instr.param > 0)
@ -148,6 +180,7 @@ namespace fk
}
auto ref = std::get<size_t>(ref_val->value());
auto fun = std::get<std::shared_ptr<NativeFunction>>
(load_global(ref));
@ -214,6 +247,7 @@ namespace fk
Loc const& loc)
{
Frame frame;
frame.lambda = lambda;
frame.program = lambda->program();
frame.ret_addr = m_pc;
frame.stack_sz = m_stack.size();
@ -315,6 +349,7 @@ namespace fk
static_cast<size_t>(ref),
loc);
Frame frame;
frame.lambda = lambda;
frame.program = lambda->program();
frame.ret_addr = m_pc;
frame.stack_sz = m_stack.size();

View File

@ -14,6 +14,7 @@ namespace fk
struct Frame {
std::shared_ptr<Program> program;
std::shared_ptr<Lambda> lambda;
addr_t ret_addr;
size_t stack_sz;
std::unordered_map<addr_t, std::shared_ptr<Constant>> locals;

View File

@ -4,7 +4,7 @@
#define OPCODES(G) G(OP_LOAD_CONST), G(OP_POP), G(OP_CALL_NATIVE), \
G(OP_LOAD_GLOBAL), G(OP_LOAD_LOCAL), G(OP_STORE_LOCAL), \
G(OP_MAKE_FUNCTION), G(OP_CALL_REF), G(OP_RET), G(OP_BNE), \
G(OP_BR)
G(OP_BR), G(OP_LOAD_CLOSURE), G(OP_STORE_CLOSURE)
#include "commons.hpp"