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 "macro.hpp"
|
||||
|
||||
Module* glob_mod;
|
||||
|
||||
extern "C" void lib(Module& mod)
|
||||
{
|
||||
glob_mod = &mod;
|
||||
mod.register_function("assert=", fkstd::assert_eq);
|
||||
mod.register_function("println", fkstd::println);
|
||||
mod.register_function("+", fkstd::add_int);
|
||||
|
|
|
@ -18,6 +18,8 @@ namespace fk
|
|||
explicit Module(std::filesystem::path source_path);
|
||||
virtual ~Module();
|
||||
|
||||
std::shared_ptr<VM> vm() const { return m_vm; }
|
||||
|
||||
void build();
|
||||
|
||||
void import_std();
|
||||
|
|
|
@ -36,6 +36,7 @@ namespace fk
|
|||
|
||||
size_t Program::add(std::shared_ptr<Constant> constant)
|
||||
{
|
||||
assert(constant);
|
||||
for (size_t i=0; i<m_consts.size(); i++)
|
||||
{
|
||||
if (m_consts[i]->equals(*constant)
|
||||
|
|
101
src/VM.cpp
101
src/VM.cpp
|
@ -21,7 +21,8 @@ namespace fk
|
|||
|
||||
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);
|
||||
|
||||
|
@ -75,10 +76,19 @@ namespace fk
|
|||
pop();
|
||||
}
|
||||
}
|
||||
|
||||
auto value = m_frames.back().program->get_const(*ret);
|
||||
|
||||
m_frames.pop_back();
|
||||
|
||||
if (m_frames.empty() == false)
|
||||
{
|
||||
push(frame().program->add(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_return_const = value;
|
||||
}
|
||||
|
||||
m_pc++;
|
||||
} break;
|
||||
|
||||
|
@ -92,10 +102,16 @@ namespace fk
|
|||
}
|
||||
|
||||
auto ref_val = frame().program->get_const(pop());
|
||||
|
||||
addr_t ref = std::get<addr_t>(ref_val->value());
|
||||
|
||||
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.program = lambda->program();
|
||||
frame.ret_addr = m_pc;
|
||||
|
@ -107,9 +123,6 @@ namespace fk
|
|||
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);
|
||||
|
||||
m_pc = 0;
|
||||
|
@ -144,7 +157,15 @@ namespace fk
|
|||
|
||||
case OP_LOAD_LOCAL: {
|
||||
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));
|
||||
|
||||
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
|
||||
{
|
||||
if (m_globals.find(addr) == std::end(m_globals))
|
||||
{
|
||||
std::cerr << "cannot find global " << addr << std::endl;
|
||||
abort();
|
||||
}
|
||||
|
||||
return m_globals.at(addr);
|
||||
}
|
||||
|
||||
|
@ -243,4 +297,39 @@ namespace fk
|
|||
m_stack.pop_back();
|
||||
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 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;
|
||||
void store_global(addr_t addr, global_t value);
|
||||
size_t store_global(global_t value);
|
||||
|
@ -39,15 +45,23 @@ namespace fk
|
|||
|
||||
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:
|
||||
addr_t m_pc = 0;
|
||||
std::vector<Frame> m_frames;
|
||||
std::vector<addr_t> m_stack;
|
||||
std::unordered_map<addr_t, global_t> m_globals;
|
||||
|
||||
void push(addr_t addr);
|
||||
addr_t top();
|
||||
addr_t pop();
|
||||
std::shared_ptr<Constant> m_return_const;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ int main(int argc, char** argv)
|
|||
|
||||
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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue