ADD: naive and simple closures.
parent
9591d6c176
commit
22131c2cf0
|
@ -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))
|
|
@ -9,9 +9,18 @@ namespace fkstd
|
||||||
{
|
{
|
||||||
auto ident = node->child(1)->repr();
|
auto ident = node->child(1)->repr();
|
||||||
compiler.compile_prog(node->child(2), program);
|
compiler.compile_prog(node->child(2), program);
|
||||||
|
std::cout << "push " << node->child(2)->string() << std::endl;
|
||||||
auto entry = compiler.sym()->find(ident);
|
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,
|
void assert_static_fail(Compiler& compiler,
|
||||||
|
|
|
@ -146,6 +146,17 @@ namespace fk
|
||||||
case NODE_IDENT: {
|
case NODE_IDENT: {
|
||||||
auto entry = m_sym->find(node->repr());
|
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)
|
if (!entry)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
|
@ -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
|
std::string Constant::string() const
|
||||||
{
|
{
|
||||||
switch (m_type)
|
switch (m_type)
|
||||||
|
@ -23,6 +29,7 @@ namespace fk
|
||||||
case TYPE_BOOL: return std::get<bool>(m_value) ? "true" : "false";
|
case TYPE_BOOL: return std::get<bool>(m_value) ? "true" : "false";
|
||||||
case TYPE_STRING: return std::get<std::string>(m_value);
|
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_REF: return std::to_string(std::get<size_t>(m_value));
|
||||||
|
case TYPE_PROGRAM: return "<program>";
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
|
@ -25,6 +25,8 @@ namespace fk
|
||||||
explicit Constant(Type type, constant_t value, Loc const& loc);
|
explicit Constant(Type type, constant_t value, Loc const& loc);
|
||||||
virtual ~Constant();
|
virtual ~Constant();
|
||||||
|
|
||||||
|
std::shared_ptr<Constant> clone();
|
||||||
|
|
||||||
Type type() const { return m_type; }
|
Type type() const { return m_type; }
|
||||||
constant_t value() const { return m_value; }
|
constant_t value() const { return m_value; }
|
||||||
Loc loc() const { return m_loc; }
|
Loc loc() const { return m_loc; }
|
||||||
|
|
|
@ -11,4 +11,23 @@ namespace fk
|
||||||
/*virtual*/ Lambda::~Lambda()
|
/*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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "commons.hpp"
|
#include "commons.hpp"
|
||||||
#include "SymTable.hpp"
|
#include "SymTable.hpp"
|
||||||
#include "Program.hpp"
|
#include "Program.hpp"
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace fk
|
namespace fk
|
||||||
{
|
{
|
||||||
|
@ -18,8 +19,13 @@ namespace fk
|
||||||
std::shared_ptr<Program> program() const { return m_program; }
|
std::shared_ptr<Program> program() const { return m_program; }
|
||||||
std::shared_ptr<SymTable> sym() const { return m_sym; }
|
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:
|
private:
|
||||||
std::shared_ptr<Program> m_program;
|
std::shared_ptr<Program> m_program;
|
||||||
|
std::unordered_map<addr_t, std::shared_ptr<Constant>> m_env;
|
||||||
size_t m_arity;
|
size_t m_arity;
|
||||||
std::shared_ptr<SymTable> m_sym = std::make_shared<SymTable>();
|
std::shared_ptr<SymTable> m_sym = std::make_shared<SymTable>();
|
||||||
};
|
};
|
||||||
|
|
|
@ -89,6 +89,43 @@ namespace fk
|
||||||
return idx;
|
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)
|
void SymTable::set(std::string const& name, addr_t addr)
|
||||||
{
|
{
|
||||||
if (auto idx = find_idx(name);
|
if (auto idx = find_idx(name);
|
||||||
|
|
|
@ -14,6 +14,8 @@ namespace fk
|
||||||
explicit SymTable();
|
explicit SymTable();
|
||||||
virtual ~SymTable();
|
virtual ~SymTable();
|
||||||
|
|
||||||
|
int scope() const { return m_scope; }
|
||||||
|
|
||||||
SymEntry& declare_local(std::string const& name,
|
SymEntry& declare_local(std::string const& name,
|
||||||
addr_t addr,
|
addr_t addr,
|
||||||
Loc const& loc);
|
Loc const& loc);
|
||||||
|
@ -24,6 +26,10 @@ namespace fk
|
||||||
|
|
||||||
std::optional<SymEntry> find(std::string const& name);
|
std::optional<SymEntry> find(std::string const& name);
|
||||||
std::optional<size_t> find_idx(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);
|
void set(std::string const& name, addr_t addr);
|
||||||
|
|
||||||
std::string string() const;
|
std::string string() const;
|
||||||
|
|
35
src/VM.cpp
35
src/VM.cpp
|
@ -29,6 +29,27 @@ namespace fk
|
||||||
|
|
||||||
switch (instr.opcode)
|
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: {
|
case OP_BR: {
|
||||||
m_pc = instr.param;
|
m_pc = instr.param;
|
||||||
} break;
|
} break;
|
||||||
|
@ -56,6 +77,14 @@ namespace fk
|
||||||
addr_t addr = store_global(lambda);
|
addr_t addr = store_global(lambda);
|
||||||
auto ref = std::make_shared<Constant>(TYPE_REF, addr, p->loc());
|
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));
|
push(frame().program->add(ref));
|
||||||
|
|
||||||
m_pc++;
|
m_pc++;
|
||||||
|
@ -114,6 +143,7 @@ namespace fk
|
||||||
ref_val->loc());
|
ref_val->loc());
|
||||||
|
|
||||||
Frame frame;
|
Frame frame;
|
||||||
|
frame.lambda = lambda;
|
||||||
frame.program = lambda->program();
|
frame.program = lambda->program();
|
||||||
frame.ret_addr = m_pc;
|
frame.ret_addr = m_pc;
|
||||||
frame.stack_sz = m_stack.size();
|
frame.stack_sz = m_stack.size();
|
||||||
|
@ -139,7 +169,9 @@ namespace fk
|
||||||
args.insert(std::begin(args),
|
args.insert(std::begin(args),
|
||||||
frame().program->get_const(addr));
|
frame().program->get_const(addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ref_val = frame().program->get_const(pop());
|
auto ref_val = frame().program->get_const(pop());
|
||||||
|
|
||||||
Loc loc = ref_val->loc();
|
Loc loc = ref_val->loc();
|
||||||
|
|
||||||
if (instr.param > 0)
|
if (instr.param > 0)
|
||||||
|
@ -148,6 +180,7 @@ namespace fk
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ref = std::get<size_t>(ref_val->value());
|
auto ref = std::get<size_t>(ref_val->value());
|
||||||
|
|
||||||
auto fun = std::get<std::shared_ptr<NativeFunction>>
|
auto fun = std::get<std::shared_ptr<NativeFunction>>
|
||||||
(load_global(ref));
|
(load_global(ref));
|
||||||
|
|
||||||
|
@ -214,6 +247,7 @@ namespace fk
|
||||||
Loc const& loc)
|
Loc const& loc)
|
||||||
{
|
{
|
||||||
Frame frame;
|
Frame frame;
|
||||||
|
frame.lambda = lambda;
|
||||||
frame.program = lambda->program();
|
frame.program = lambda->program();
|
||||||
frame.ret_addr = m_pc;
|
frame.ret_addr = m_pc;
|
||||||
frame.stack_sz = m_stack.size();
|
frame.stack_sz = m_stack.size();
|
||||||
|
@ -315,6 +349,7 @@ namespace fk
|
||||||
static_cast<size_t>(ref),
|
static_cast<size_t>(ref),
|
||||||
loc);
|
loc);
|
||||||
Frame frame;
|
Frame frame;
|
||||||
|
frame.lambda = lambda;
|
||||||
frame.program = lambda->program();
|
frame.program = lambda->program();
|
||||||
frame.ret_addr = m_pc;
|
frame.ret_addr = m_pc;
|
||||||
frame.stack_sz = m_stack.size();
|
frame.stack_sz = m_stack.size();
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace fk
|
||||||
|
|
||||||
struct Frame {
|
struct Frame {
|
||||||
std::shared_ptr<Program> program;
|
std::shared_ptr<Program> program;
|
||||||
|
std::shared_ptr<Lambda> lambda;
|
||||||
addr_t ret_addr;
|
addr_t ret_addr;
|
||||||
size_t stack_sz;
|
size_t stack_sz;
|
||||||
std::unordered_map<addr_t, std::shared_ptr<Constant>> locals;
|
std::unordered_map<addr_t, std::shared_ptr<Constant>> locals;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#define OPCODES(G) G(OP_LOAD_CONST), G(OP_POP), G(OP_CALL_NATIVE), \
|
#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_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_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"
|
#include "commons.hpp"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue