ADD: high order functions.
parent
7a792274f6
commit
70d0ba241c
|
@ -0,0 +1,4 @@
|
||||||
|
($ add (-> (x) (+ 1 x)))
|
||||||
|
($ twice (-> (f x) (f (f x))))
|
||||||
|
|
||||||
|
(assert= 6 (twice add 4))
|
|
@ -2,8 +2,11 @@
|
||||||
#include "fun.hpp"
|
#include "fun.hpp"
|
||||||
#include "macro.hpp"
|
#include "macro.hpp"
|
||||||
|
|
||||||
|
Module* glob_mod;
|
||||||
|
|
||||||
extern "C" void lib(Module& mod)
|
extern "C" void lib(Module& mod)
|
||||||
{
|
{
|
||||||
|
glob_mod = &mod;
|
||||||
mod.register_function("assert=", fkstd::assert_eq);
|
mod.register_function("assert=", fkstd::assert_eq);
|
||||||
mod.register_function("println", fkstd::println);
|
mod.register_function("println", fkstd::println);
|
||||||
mod.register_function("+", fkstd::add_int);
|
mod.register_function("+", fkstd::add_int);
|
||||||
|
|
|
@ -18,6 +18,8 @@ namespace fk
|
||||||
explicit Module(std::filesystem::path source_path);
|
explicit Module(std::filesystem::path source_path);
|
||||||
virtual ~Module();
|
virtual ~Module();
|
||||||
|
|
||||||
|
std::shared_ptr<VM> vm() const { return m_vm; }
|
||||||
|
|
||||||
void build();
|
void build();
|
||||||
|
|
||||||
void import_std();
|
void import_std();
|
||||||
|
|
|
@ -36,6 +36,7 @@ namespace fk
|
||||||
|
|
||||||
size_t Program::add(std::shared_ptr<Constant> constant)
|
size_t Program::add(std::shared_ptr<Constant> constant)
|
||||||
{
|
{
|
||||||
|
assert(constant);
|
||||||
for (size_t i=0; i<m_consts.size(); i++)
|
for (size_t i=0; i<m_consts.size(); i++)
|
||||||
{
|
{
|
||||||
if (m_consts[i]->equals(*constant)
|
if (m_consts[i]->equals(*constant)
|
||||||
|
|
103
src/VM.cpp
103
src/VM.cpp
|
@ -21,7 +21,8 @@ namespace fk
|
||||||
|
|
||||||
void VM::run()
|
void VM::run()
|
||||||
{
|
{
|
||||||
while (m_pc < frame().program->size())
|
while (m_frames.empty() == false
|
||||||
|
&& m_pc < frame().program->size())
|
||||||
{
|
{
|
||||||
Instr instr = frame().program->instr(m_pc);
|
Instr instr = frame().program->instr(m_pc);
|
||||||
|
|
||||||
|
@ -75,10 +76,19 @@ namespace fk
|
||||||
pop();
|
pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto value = m_frames.back().program->get_const(*ret);
|
auto value = m_frames.back().program->get_const(*ret);
|
||||||
|
|
||||||
m_frames.pop_back();
|
m_frames.pop_back();
|
||||||
push(frame().program->add(value));
|
|
||||||
|
if (m_frames.empty() == false)
|
||||||
|
{
|
||||||
|
push(frame().program->add(value));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_return_const = value;
|
||||||
|
}
|
||||||
|
|
||||||
m_pc++;
|
m_pc++;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -92,10 +102,16 @@ namespace fk
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ref_val = frame().program->get_const(pop());
|
auto ref_val = frame().program->get_const(pop());
|
||||||
|
|
||||||
addr_t ref = std::get<addr_t>(ref_val->value());
|
addr_t ref = std::get<addr_t>(ref_val->value());
|
||||||
|
|
||||||
auto lambda = std::get<std::shared_ptr<Lambda>>(load_global(ref));
|
auto lambda = std::get<std::shared_ptr<Lambda>>(load_global(ref));
|
||||||
|
|
||||||
|
|
||||||
|
auto self = std::make_shared<Constant>(TYPE_REF,
|
||||||
|
static_cast<size_t>(ref),
|
||||||
|
ref_val->loc());
|
||||||
|
|
||||||
Frame frame;
|
Frame frame;
|
||||||
frame.program = lambda->program();
|
frame.program = lambda->program();
|
||||||
frame.ret_addr = m_pc;
|
frame.ret_addr = m_pc;
|
||||||
|
@ -107,9 +123,6 @@ namespace fk
|
||||||
store_local(i, args[i]);
|
store_local(i, args[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto self = std::make_shared<Constant>(TYPE_REF,
|
|
||||||
static_cast<size_t>(ref),
|
|
||||||
ref_val->loc());
|
|
||||||
store_local(args.size(), self);
|
store_local(args.size(), self);
|
||||||
|
|
||||||
m_pc = 0;
|
m_pc = 0;
|
||||||
|
@ -144,7 +157,15 @@ namespace fk
|
||||||
|
|
||||||
case OP_LOAD_LOCAL: {
|
case OP_LOAD_LOCAL: {
|
||||||
auto value = frame().locals[instr.param];
|
auto value = frame().locals[instr.param];
|
||||||
assert(value);
|
|
||||||
|
if (!value)
|
||||||
|
{
|
||||||
|
std::cerr << "cannot find value with ref '"
|
||||||
|
<< instr.param
|
||||||
|
<< "'" << std::endl;
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
push(frame().program->add(value));
|
push(frame().program->add(value));
|
||||||
|
|
||||||
m_pc++;
|
m_pc++;
|
||||||
|
@ -185,8 +206,41 @@ namespace fk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Constant>
|
||||||
|
VM::call(std::shared_ptr<Lambda> lambda,
|
||||||
|
size_t ref,
|
||||||
|
std::vector<std::shared_ptr<Constant>> const& args,
|
||||||
|
Loc const& loc)
|
||||||
|
{
|
||||||
|
Frame frame;
|
||||||
|
frame.program = lambda->program();
|
||||||
|
frame.ret_addr = m_pc;
|
||||||
|
frame.stack_sz = m_stack.size();
|
||||||
|
m_frames.push_back(frame);
|
||||||
|
|
||||||
|
for (size_t i=0; i<args.size(); i++)
|
||||||
|
{
|
||||||
|
store_local(i, args[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto self = std::make_shared<Constant>(TYPE_REF,
|
||||||
|
static_cast<size_t>(ref),
|
||||||
|
loc);
|
||||||
|
store_local(args.size(), self);
|
||||||
|
|
||||||
|
m_pc = 0;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
global_t VM::load_global(addr_t addr) const
|
global_t VM::load_global(addr_t addr) const
|
||||||
{
|
{
|
||||||
|
if (m_globals.find(addr) == std::end(m_globals))
|
||||||
|
{
|
||||||
|
std::cerr << "cannot find global " << addr << std::endl;
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
return m_globals.at(addr);
|
return m_globals.at(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,4 +297,39 @@ namespace fk
|
||||||
m_stack.pop_back();
|
m_stack.pop_back();
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Constant>
|
||||||
|
VM::run_lambda(VM const& parent,
|
||||||
|
std::shared_ptr<Lambda> lambda,
|
||||||
|
std::vector<std::shared_ptr<Constant>> args,
|
||||||
|
size_t ref,
|
||||||
|
Loc const& loc)
|
||||||
|
{
|
||||||
|
for (auto entry: parent.m_globals)
|
||||||
|
{
|
||||||
|
store_global(entry.first, entry.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto self = std::make_shared<Constant>(TYPE_REF,
|
||||||
|
static_cast<size_t>(ref),
|
||||||
|
loc);
|
||||||
|
Frame frame;
|
||||||
|
frame.program = lambda->program();
|
||||||
|
frame.ret_addr = m_pc;
|
||||||
|
frame.stack_sz = m_stack.size();
|
||||||
|
m_frames.push_back(frame);
|
||||||
|
|
||||||
|
for (size_t i=0; i<args.size(); i++)
|
||||||
|
{
|
||||||
|
store_local(i, args[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
store_local(args.size(), self);
|
||||||
|
|
||||||
|
m_pc = 0;
|
||||||
|
|
||||||
|
run();
|
||||||
|
|
||||||
|
return m_return_const;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
22
src/VM.hpp
22
src/VM.hpp
|
@ -30,6 +30,12 @@ namespace fk
|
||||||
void mount(std::shared_ptr<Program> program);
|
void mount(std::shared_ptr<Program> program);
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
|
std::shared_ptr<Constant>
|
||||||
|
call(std::shared_ptr<Lambda> lambda,
|
||||||
|
size_t ref,
|
||||||
|
std::vector<std::shared_ptr<Constant>> const& args,
|
||||||
|
Loc const& loc);
|
||||||
|
|
||||||
global_t load_global(addr_t addr) const;
|
global_t load_global(addr_t addr) const;
|
||||||
void store_global(addr_t addr, global_t value);
|
void store_global(addr_t addr, global_t value);
|
||||||
size_t store_global(global_t value);
|
size_t store_global(global_t value);
|
||||||
|
@ -39,15 +45,23 @@ namespace fk
|
||||||
|
|
||||||
std::string string() const;
|
std::string string() const;
|
||||||
|
|
||||||
|
void push(addr_t addr);
|
||||||
|
addr_t top();
|
||||||
|
addr_t pop();
|
||||||
|
|
||||||
|
std::shared_ptr<Constant>
|
||||||
|
run_lambda(VM const& parent,
|
||||||
|
std::shared_ptr<Lambda> lambda,
|
||||||
|
std::vector<std::shared_ptr<Constant>> args,
|
||||||
|
size_t ref,
|
||||||
|
Loc const& loc);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
addr_t m_pc = 0;
|
addr_t m_pc = 0;
|
||||||
std::vector<Frame> m_frames;
|
std::vector<Frame> m_frames;
|
||||||
std::vector<addr_t> m_stack;
|
std::vector<addr_t> m_stack;
|
||||||
std::unordered_map<addr_t, global_t> m_globals;
|
std::unordered_map<addr_t, global_t> m_globals;
|
||||||
|
std::shared_ptr<Constant> m_return_const;
|
||||||
void push(addr_t addr);
|
|
||||||
addr_t top();
|
|
||||||
addr_t pop();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
int opt_index = 0;
|
int opt_index = 0;
|
||||||
|
|
||||||
int c = getopt_long(argc, argv, "h", options, &opt_index);
|
int c = getopt_long(argc, argv, "hd", options, &opt_index);
|
||||||
|
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue