diff --git a/example.vli b/example.vli index e98ca98..2dcb876 100644 --- a/example.vli +++ b/example.vli @@ -1,12 +1,14 @@ -;; Check that lambdas can be passed as arguments +;;((fn (f y) (f y)) + ;;(fn (x) (* x x)) + ;;2) -((fn (f y) (f y)) - (fn (x) (* x x)) - 2) +;;(((fn (x) + ;;(fn () (* x x 2))) + ;;2)) -(((fn (x) - (fn () (* x x 2))) - 2)) +(fn fact (n) + (if (<= n 0) + 1 + (* n (fact (- n 1))))) - -(fn foo (x y) (* x y)) +(fact 12) diff --git a/src/arena.cpp b/src/arena.cpp index 6000574..d1a5835 100644 --- a/src/arena.cpp +++ b/src/arena.cpp @@ -83,6 +83,8 @@ Result Arena::gc_pod(PodObject* obj) { return gc_opcode((PodOpcode*)obj); case Tag::Function: return gc_function((PodFunction*)obj); + case Tag::Module: + return gc_module((PodModule*)obj); case Tag::Stack: return gc_stack((PodStack*)obj); } @@ -208,6 +210,16 @@ Result Arena::gc_function(PodFunction* obj) { return nobj; } +Result Arena::gc_module(PodModule* obj) { + auto nobj = TRY(alloc()); + nobj->header.tag = Tag::Function; + nobj->name = TRY(gc_pod(obj->name.get())); + nobj->globals = TRY(gc_pod(obj->globals.get())); + nobj->fun = TRY(gc_pod(obj->fun.get())); + + return nobj; +} + Result Arena::gc_stack(PodStack* obj) { auto nobj = TRY(alloc(sizeof(OffPtr) * obj->size)); nobj->header.tag = Tag::Stack; diff --git a/src/arena.hpp b/src/arena.hpp index c67f4c3..d9a51f9 100644 --- a/src/arena.hpp +++ b/src/arena.hpp @@ -20,7 +20,7 @@ class GcRootBase { public: friend class Arena; - GcRootBase() : _ptr(0), _node(0){}; + GcRootBase() : _ptr(0), _node(0) {}; GcRootBase(PodObject* ptr, GcRootList* node); ~GcRootBase(); @@ -156,6 +156,7 @@ class Arena { Result gc_dict(PodDict* obj); Result gc_opcode(PodOpcode* obj); Result gc_function(PodFunction* obj); + Result gc_module(PodModule* obj); Result gc_stack(PodStack* obj); void add_root(GcRootList* node) { _gcroot.insert(node); } diff --git a/src/common.cpp b/src/common.cpp index bc23705..0d3075e 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -40,6 +40,8 @@ Result Value::create(PodObject* obj) { return Value(TRY(Opcode::create((PodOpcode*)obj))); case Tag::Function: return Value(TRY(Function::create((PodFunction*)obj))); + case Tag::Module: + return Value(TRY(Module::create((PodModule*)obj))); case Tag::Stack: return Value(TRY(Stack::create((PodStack*)obj))); }; @@ -160,6 +162,28 @@ Result Function::cmp(const Function& rhs) const { return res; } +Result Module::copy_value() const { + return Value(Module(TRY(_value.copy()))); +} +Result Module::copy() const { return Module(TRY(_value.copy())); } + +Result Module::cmp(const Module& rhs) const { + auto lhs_name = TRY(name()); + auto rhs_name = TRY(rhs.name()); + short res = TRY(lhs_name.cmp(rhs_name)); + if (res != 0) return res; + + auto lhs_fun = TRY(fun()); + auto rhs_fun = TRY(rhs.fun()); + res = TRY(lhs_fun.cmp(rhs_fun)); + if (res != 0) return res; + + auto lhs_globals = TRY(globals()); + auto rhs_globals = TRY(rhs.globals()); + res = TRY(lhs_globals.cmp(rhs_globals)); + return res; +} + Result Stack::copy_value() const { return Value(Stack(TRY(_value.copy()))); } @@ -252,6 +276,27 @@ Result Function::closure() const { return Array::create((PodArray*)_value->closure.get()); } +Result Module::create(const Value& name, const Function& fun, + const Dict& globals) { + auto pod = TRY(arena_alloc()); + pod->header.tag = Tag::Module; + pod->name = name.pod(); + pod->fun = fun.pod(); + pod->globals = globals.pod(); + + return Module(TRY(MkGcRoot(pod))); +} + +Result Module::name() const { return Value::create(_value->name.get()); } + +Result Module::fun() const { + return Function::create((PodFunction*)_value->fun.get()); +} + +Result Module::globals() const { + return Dict::create((PodDict*)_value->globals.get()); +} + Result reverse(Value& val) { if (val.is()) return Value(TRY(Nil::create())); if (!val.is()) return ERROR(TypeMismatch); diff --git a/src/common.hpp b/src/common.hpp index d4efe0c..8663510 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -29,6 +29,7 @@ class Writer; class Opcode; class Stack; class Function; +class Module; short cmp_tag(Tag lhs, Tag rhs); @@ -77,6 +78,9 @@ class Object { virtual Result cmp(const Function& rhs) const { return cmp_tag(tag(), Tag::Function); } + virtual Result cmp(const Module& rhs) const { + return cmp_tag(tag(), Tag::Module); + } virtual Result cmp(const char* rhs) const { return ERROR(NotImplemented); } @@ -888,6 +892,44 @@ class Function : public Object { GcRoot _value; }; +class Module : public Object { + public: + Module() {} + Module(Module&& rhs) : _value(std::move(rhs._value)) {} + Module(GcRoot&& val) : _value(std::move(val)) {} + + Module& operator=(Module&& rhs) { + _value = std::move(rhs._value); + return *this; + } + + virtual Tag tag() const final { return Tag::Module; } + virtual PodObject* pod() const final { return _value.get(); } + virtual Result cmp(const Object& rhs) const final { + return -TRY(rhs.cmp(*this)); + } + virtual Result cmp(const Module& rhs) const final; + + virtual void move(Object* obj) final { new (obj) Module(std::move(_value)); } + + static Result create(PodModule* obj) { + return Module(TRY(MkGcRoot(obj))); + } + + static Result create(const Value& name, const Function& fun, + const Dict& globals); + + Result name() const; + Result fun() const; + Result globals() const; + + virtual Result copy_value() const final; + Result copy() const; + + private: + GcRoot _value; +}; + class Stack : public Object { public: Stack() {} diff --git a/src/compiler.cpp b/src/compiler.cpp index ede6204..8d77813 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -7,15 +7,17 @@ struct Context { Context(Value&& env, Array&& constants, Dict&& constants_dict, Dict&& variables_dict, Array&& closures, Dict&& closures_dict, - Context* parent, bool toplevel) + Dict&& globals_dict, Context* parent, bool toplevel) : env(std::move(env)), constants(std::move(constants)), constants_dict(std::move(constants_dict)), variables_dict(std::move(variables_dict)), closures(std::move(closures)), closures_dict(std::move(closures_dict)), + globals_dict(std::move(globals_dict)), maxreg(0), - parent(parent) {} + parent(parent), + toplevel(toplevel) {} static Result create() { auto env = TRY(Nil::create()); @@ -24,10 +26,12 @@ struct Context { auto variables_dict = TRY(Dict::create()); auto closures = TRY(Array::create()); auto closures_dict = TRY(Dict::create()); + auto globals_dict = TRY(Dict::create()); return Context(std::move(env), std::move(constants), std::move(constants_dict), std::move(variables_dict), - std::move(closures), std::move(closures_dict), 0, true); + std::move(closures), std::move(closures_dict), + std::move(globals_dict), 0, true); } static Result create(Context& parent) { @@ -37,11 +41,12 @@ struct Context { auto variables_dict = TRY(Dict::create()); auto closures = TRY(Array::create()); auto closures_dict = TRY(Dict::create()); + auto globals_dict = TRY(Dict::create()); return Context(std::move(env), std::move(constants), std::move(constants_dict), std::move(variables_dict), - std::move(closures), std::move(closures_dict), &parent, - false); + std::move(closures), std::move(closures_dict), + std::move(globals_dict), &parent, false); } uint64_t alloc_reg() { @@ -112,12 +117,18 @@ struct Context { return i; } + Result add_global(const Value& name, const Value& value) { + globals_dict = TRY(globals_dict.insert(name, value)); + return Result(); + } + Value env; Array constants; Dict constants_dict; Dict variables_dict; Array closures; Dict closures_dict; + Dict globals_dict; uint64_t maxreg; Context* parent; bool toplevel; @@ -161,7 +172,10 @@ Result Compiler::compile(Value& expr) { auto fun = TRY(Function::create(name, 0, context.constants, ex.code, TRY(Array::create()))); - return Value(std::move(fun)); + + auto mod = TRY(Module::create(name, fun, context.globals_dict)); + + return Value(std::move(mod)); } Result Compiler::compile_expr(Context& context, Value& expr) { @@ -183,6 +197,7 @@ Result Compiler::compile_expr(Context& context, Value& expr) { case Tag::Dict: case Tag::Opcode: case Tag::Function: + case Tag::Module: case Tag::Stack: return ERROR(TypeMismatch); } @@ -462,11 +477,16 @@ Result Compiler::compile_fn(Context& context, Symbol& op, // std::cout << "--------------- LAMBDA " << arity << "\n"; // TRY(debug_print(TRY(expr.copy_value()))); + // TRY(debug_print(TRY(ctx.constants.copy()))); // TRY(debug_print(TRY(ex.code.copy()))); Expression ex_res = TRY(Expression::create()); if (ctx.closures.size() == 0) { + if (context.toplevel && !name.is()) { + context.add_global(name, TRY(fun.copy_value())); + } + int64_t c = TRY(context.add_const(TRY(fun.copy_value()))); uint64_t reg = context.alloc_reg(); @@ -615,15 +635,24 @@ Result Compiler::compile_symbol(Context& context, Symbol& value) { auto maybe_closure = context.get_closure(TRY(value.copy_value())); - if (maybe_closure.has_error()) { - return ERROR(CompilationError); + if (!maybe_closure.has_error()) { + auto var_closure = maybe_closure.value(); + + uint64_t reg = context.alloc_reg(); + TRY(ex.add_opcode(Oc::ClosureLoad, {0, (int64_t)reg}, + {0, (int64_t)var_closure})); + + ex.reg = reg; + return std::move(ex); } - auto var_closure = maybe_closure.value(); + // Otherwise treat unknown symbol as a global and try to load it from the + // global scope + + int64_t c = TRY(context.add_const(TRY(value.copy_value()))); uint64_t reg = context.alloc_reg(); - TRY(ex.add_opcode(Oc::ClosureLoad, {0, (int64_t)reg}, - {0, (int64_t)var_closure})); + TRY(ex.add_opcode(Oc::GlobalLoad, {0, (int64_t)reg}, {1, (int64_t)c})); ex.reg = reg; return std::move(ex); diff --git a/src/opcode.cpp b/src/opcode.cpp index 1757c9b..e987291 100644 --- a/src/opcode.cpp +++ b/src/opcode.cpp @@ -75,10 +75,9 @@ op_t get_op(Oc op) { return op_t{"make-dict", OpcodeType::Reg1}; case Oc::SetJump: return op_t{"setjump", OpcodeType::Reg1I}; - case Oc::SetGlobal: return op_t{"setglobal", OpcodeType::Reg2}; - case Oc::GetGlobal: - return op_t{"getglobal", OpcodeType::Reg2}; + case Oc::GlobalLoad: + return op_t{"global-load", OpcodeType::Reg2}; case Oc::MakeClosure: return op_t{"make-closure", OpcodeType::Reg2}; case Oc::ClosureLoad: diff --git a/src/opcode.hpp b/src/opcode.hpp index 96a3c41..e2b970c 100644 --- a/src/opcode.hpp +++ b/src/opcode.hpp @@ -59,8 +59,7 @@ enum class Oc : uint8_t { MakeDict, SetJump, // Globals - SetGlobal, - GetGlobal, + GlobalLoad, // Closures MakeClosure, ClosureLoad, diff --git a/src/pod.hpp b/src/pod.hpp index c1450b9..1c23702 100644 --- a/src/pod.hpp +++ b/src/pod.hpp @@ -20,6 +20,7 @@ enum class Tag : uint8_t { Dict, Opcode, Function, + Module, Stack, }; @@ -168,6 +169,15 @@ class PodFunction final : public PodObject { OffPtr closure; }; +class PodModule final : public PodObject { + public: + PodModule() : PodObject(Tag::Module) {}; + + OffPtr name; + OffPtr fun; + OffPtr globals; +}; + class PodStack final : public PodObject { public: PodStack() : PodObject(Tag::Stack) {}; diff --git a/src/vli.cpp b/src/vli.cpp index db0cd91..19fbe60 100644 --- a/src/vli.cpp +++ b/src/vli.cpp @@ -34,14 +34,13 @@ Result run(int argc, const char* argv[]) { TRY(debug_print(code_str_written)); auto compiled = TRY(compile(parsed)); - Function& fun = *compiled.to(); + Module& mod = *compiled.to(); - TRY(debug_print(TRY(fun.constants()))); - TRY(debug_print(TRY(fun.code()))); + TRY(debug_print(TRY(mod.globals()))); auto vm = TRY(VM::create()); - auto res = TRY(vm.run(fun)); + auto res = TRY(vm.run(mod)); TRY(debug_print(res)); diff --git a/src/vm.cpp b/src/vm.cpp index 3233285..15b20e3 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -1,5 +1,7 @@ #include "vm.hpp" +#include "common.hpp" + Result VM::getreg(uint64_t idx) { return _stack.get(_base + idx); } Result VM::setreg(uint64_t idx, const Value& value) { @@ -124,7 +126,7 @@ Result VM::vm_call(Opcode& oc) { _closure = TRY(fun.closure()); _fun = std::move(fun); _pc = 0; - _base = reg_start; + _base = _base + reg_start; return Result(); } @@ -190,6 +192,15 @@ Result VM::vm_closure_load(Opcode& oc) { return Result(); } +Result VM::vm_global_load(Opcode& oc) { + uint64_t acc = (uint64_t)oc.arg1().arg; + Value sym = TRY(get(oc.arg2().is_const, (uint64_t)oc.arg2().arg)); + Value val = TRY(_globals.get(sym)); + setreg(acc, val); + _pc++; + return Result(); +} + Result VM::step() { auto opcode = TRY(_code.get(_pc)); if (!opcode.is()) return ERROR(TypeMismatch); @@ -237,6 +248,9 @@ Result VM::step() { case Oc::ClosureLoad: TRY(vm_closure_load(oc)); break; + case Oc::GlobalLoad: + TRY(vm_global_load(oc)); + break; default: return ERROR(NotImplemented); } @@ -246,13 +260,14 @@ Result VM::step() { // Result Int64::copy() const { return Value(Int64(TRY(_value.copy()))); // } -Result VM::run(const Function& fun) { - _fun = TRY(fun.copy()); +Result VM::run(const Module& mod) { + _fun = TRY(mod.fun()); _pc = 0; _base = 0; - _code = TRY(fun.code()); - _constants = TRY(fun.constants()); - _closure = TRY(fun.closure()); + _code = TRY(_fun.code()); + _constants = TRY(_fun.constants()); + _closure = TRY(_fun.closure()); + _globals = TRY(mod.globals()); while (true) { auto rc = step(); diff --git a/src/vm.hpp b/src/vm.hpp index db17ea4..d029ee7 100644 --- a/src/vm.hpp +++ b/src/vm.hpp @@ -17,7 +17,7 @@ class VM { return VM(std::move(stack), std::move(callstack)); } - Result run(const Function& fun); + Result run(const Module& mod); Result step(); Result vm_mov(Opcode& oc); @@ -36,6 +36,8 @@ class VM { Result vm_make_closure(Opcode& oc); Result vm_closure_load(Opcode& oc); + Result vm_global_load(Opcode& oc); + Result get(bool is_const, uint64_t idx); Result getconst(uint64_t idx); Result getreg(uint64_t idx); @@ -48,6 +50,7 @@ class VM { Array _code; Array _constants; Array _closure; + Dict _globals; uint64_t _pc; uint64_t _base; Value _res; diff --git a/src/writer.cpp b/src/writer.cpp index bea8bf3..c43000c 100644 --- a/src/writer.cpp +++ b/src/writer.cpp @@ -31,6 +31,8 @@ Result Writer::write_one(const Value& obj) { return write_opcode(*obj.to()); case Tag::Function: return write_function(*obj.to()); + case Tag::Module: + return write_module(*obj.to()); case Tag::Stack: return write_stack(*obj.to()); }; @@ -64,7 +66,7 @@ Result Writer::write_multiple(const Value& val) { Result Writer::write_int64(const Int64& val) { char tmp[32]; - sprintf(tmp, "%lu", val.value()); + sprintf(tmp, "%ld", val.value()); size_t len = strlen(tmp); return String::create(tmp); @@ -318,6 +320,21 @@ Result Writer::write_function(const Function& val) { return res; } +Result Writer::write_module(const Module& val) { + auto name = TRY(val.name()); + if (name.is()) { + return TRY(String::create("#")); + } + + if (!name.is()) return ERROR(TypeMismatch); + String name_str = TRY(write_symbol(*name.to())); + + String res = TRY(String::create("#")); + return res; +} + Result Writer::write_stack(const Stack& val) { return TRY(String::create("#")); } diff --git a/src/writer.hpp b/src/writer.hpp index 4ba941d..3db39fd 100644 --- a/src/writer.hpp +++ b/src/writer.hpp @@ -5,7 +5,7 @@ class Writer { public: - Writer(){}; + Writer() {}; Result write_one(const Value& obj); Result write_multiple(const Value& obj); @@ -24,6 +24,7 @@ class Writer { Result write_syntax(const Syntax& val); Result write_opcode(const Opcode& val); Result write_function(const Function& val); + Result write_module(const Module& val); Result write_stack(const Stack& val); };