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,10 +9,19 @@ 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);
|
||||
|
||||
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,
|
||||
std::shared_ptr<Node> node,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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>();
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
35
src/VM.cpp
35
src/VM.cpp
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
Loading…
Reference in New Issue