diff --git a/examples/high_order.fk b/examples/high_order.fk new file mode 100644 index 0000000..717cdef --- /dev/null +++ b/examples/high_order.fk @@ -0,0 +1,4 @@ +($ add (-> (x) (+ 1 x))) +($ twice (-> (f x) (f (f x)))) + +(assert= 6 (twice add 4)) \ No newline at end of file diff --git a/libstd/lib.cpp b/libstd/lib.cpp index ae5ca5d..50a4b6c 100644 --- a/libstd/lib.cpp +++ b/libstd/lib.cpp @@ -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); diff --git a/src/Module.hpp b/src/Module.hpp index 63f5907..bc5ae48 100644 --- a/src/Module.hpp +++ b/src/Module.hpp @@ -18,6 +18,8 @@ namespace fk explicit Module(std::filesystem::path source_path); virtual ~Module(); + std::shared_ptr vm() const { return m_vm; } + void build(); void import_std(); diff --git a/src/Program.cpp b/src/Program.cpp index 4824b14..d16b38b 100644 --- a/src/Program.cpp +++ b/src/Program.cpp @@ -36,6 +36,7 @@ namespace fk size_t Program::add(std::shared_ptr constant) { + assert(constant); for (size_t i=0; iequals(*constant) diff --git a/src/VM.cpp b/src/VM.cpp index 7c07da8..25c162c 100644 --- a/src/VM.cpp +++ b/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(); - push(frame().program->add(value)); + + 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(ref_val->value()); auto lambda = std::get>(load_global(ref)); + + auto self = std::make_shared(TYPE_REF, + static_cast(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(TYPE_REF, - static_cast(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 + VM::call(std::shared_ptr lambda, + size_t ref, + std::vector> 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(TYPE_REF, + static_cast(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 + VM::run_lambda(VM const& parent, + std::shared_ptr lambda, + std::vector> args, + size_t ref, + Loc const& loc) + { + for (auto entry: parent.m_globals) + { + store_global(entry.first, entry.second); + } + + auto self = std::make_shared(TYPE_REF, + static_cast(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 program); void run(); + std::shared_ptr + call(std::shared_ptr lambda, + size_t ref, + std::vector> 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 + run_lambda(VM const& parent, + std::shared_ptr lambda, + std::vector> args, + size_t ref, + Loc const& loc); + private: addr_t m_pc = 0; std::vector m_frames; std::vector m_stack; std::unordered_map m_globals; - - void push(addr_t addr); - addr_t top(); - addr_t pop(); + std::shared_ptr m_return_const; }; } diff --git a/src/main.cpp b/src/main.cpp index 36e5adc..fe9a645 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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) {