First working implementation of closures
This commit is contained in:
parent
6fcd231694
commit
5948bfa973
6 changed files with 51 additions and 4 deletions
|
@ -1,3 +1,9 @@
|
||||||
;; Check that lambdas can be passed as arguments
|
;; Check that lambdas can be passed as arguments
|
||||||
|
|
||||||
((lambda (f y) (f y)) (lambda (x) (* x x)) 2)
|
((lambda (f y) (f y))
|
||||||
|
(lambda (x) (* x x))
|
||||||
|
2)
|
||||||
|
|
||||||
|
(((lambda (x)
|
||||||
|
(lambda () (* x x 2)))
|
||||||
|
2))
|
||||||
|
|
|
@ -448,6 +448,27 @@ Result<short> Dict::cmp(const Dict& rhs) const {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<short> Array::cmp(const Array& rhs) const {
|
||||||
|
auto lsize = size();
|
||||||
|
auto rsize = rhs.size();
|
||||||
|
uint64_t i = 0;
|
||||||
|
uint64_t j = 0;
|
||||||
|
while (1) {
|
||||||
|
if (i == lsize && j == lsize) return 0;
|
||||||
|
|
||||||
|
short cmp = short(i == lsize) - short(j == rsize);
|
||||||
|
if (cmp != 0) return cmp;
|
||||||
|
|
||||||
|
Value lc = TRY(Value::create(_value->data[i].get()));
|
||||||
|
Value rc = TRY(Value::create(rhs._value->data[j].get()));
|
||||||
|
cmp = TRY(lc.cmp(rc));
|
||||||
|
if (cmp != 0) return cmp;
|
||||||
|
i++;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Result<Value> Object::get(const Value& key) const {
|
Result<Value> Object::get(const Value& key) const {
|
||||||
return ERROR(TypeMismatch);
|
return ERROR(TypeMismatch);
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ class Object {
|
||||||
return cmp_tag(tag(), Tag::Opcode);
|
return cmp_tag(tag(), Tag::Opcode);
|
||||||
}
|
}
|
||||||
virtual Result<short> cmp(const Function& rhs) const {
|
virtual Result<short> cmp(const Function& rhs) const {
|
||||||
return cmp_tag(tag(), Tag::Opcode);
|
return cmp_tag(tag(), Tag::Function);
|
||||||
}
|
}
|
||||||
virtual Result<short> cmp(const char* rhs) const {
|
virtual Result<short> cmp(const char* rhs) const {
|
||||||
return ERROR(NotImplemented);
|
return ERROR(NotImplemented);
|
||||||
|
@ -150,7 +150,7 @@ class Array : public Object {
|
||||||
virtual Result<short> cmp(const Object& rhs) const final {
|
virtual Result<short> cmp(const Object& rhs) const final {
|
||||||
return -TRY(rhs.cmp(*this));
|
return -TRY(rhs.cmp(*this));
|
||||||
}
|
}
|
||||||
virtual Result<short> cmp(const Array& rhs) const final { return 0; }
|
virtual Result<short> cmp(const Array& rhs) const final;
|
||||||
|
|
||||||
virtual void move(Object* obj) final { new (obj) Array(std::move(_value)); }
|
virtual void move(Object* obj) final { new (obj) Array(std::move(_value)); }
|
||||||
|
|
||||||
|
|
|
@ -373,6 +373,7 @@ Result<Expression> Compiler::compile_lambda(Context& context, Symbol& op,
|
||||||
uint64_t reg = context.alloc_reg();
|
uint64_t reg = context.alloc_reg();
|
||||||
TRY(ex_res.add_opcode(Oc::Mov, {0, (int64_t)reg}, {1, (int64_t)c}));
|
TRY(ex_res.add_opcode(Oc::Mov, {0, (int64_t)reg}, {1, (int64_t)c}));
|
||||||
|
|
||||||
|
context.maxreg = reg + 1;
|
||||||
ex_res.reg = reg;
|
ex_res.reg = reg;
|
||||||
|
|
||||||
return ex_res;
|
return ex_res;
|
||||||
|
@ -393,7 +394,7 @@ Result<Expression> Compiler::compile_lambda(Context& context, Symbol& op,
|
||||||
TRY(ex_res.add_opcode(Oc::MakeClosure, {0, (int64_t)reg},
|
TRY(ex_res.add_opcode(Oc::MakeClosure, {0, (int64_t)reg},
|
||||||
{0, (int64_t)reg + (int64_t)ctx.closures.size() + 1}));
|
{0, (int64_t)reg + (int64_t)ctx.closures.size() + 1}));
|
||||||
|
|
||||||
context.maxreg = reg;
|
context.maxreg = reg + 1;
|
||||||
ex_res.reg = reg;
|
ex_res.reg = reg;
|
||||||
|
|
||||||
return ex_res;
|
return ex_res;
|
||||||
|
@ -459,6 +460,7 @@ Result<Expression> Compiler::compile_function_call(Context& context,
|
||||||
{0, (int64_t)context.maxreg}));
|
{0, (int64_t)context.maxreg}));
|
||||||
|
|
||||||
ex.reg = fun_ex.reg;
|
ex.reg = fun_ex.reg;
|
||||||
|
context.maxreg = maxreg;
|
||||||
return ex;
|
return ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
16
src/vm.cpp
16
src/vm.cpp
|
@ -96,6 +96,7 @@ Result<void> VM::vm_call(Opcode& oc) {
|
||||||
|
|
||||||
_code = TRY(fun.code());
|
_code = TRY(fun.code());
|
||||||
_constants = TRY(fun.constants());
|
_constants = TRY(fun.constants());
|
||||||
|
_closure = TRY(fun.closure());
|
||||||
_fun = std::move(fun);
|
_fun = std::move(fun);
|
||||||
_pc = 0;
|
_pc = 0;
|
||||||
_base = reg_start;
|
_base = reg_start;
|
||||||
|
@ -123,6 +124,7 @@ Result<void> VM::vm_ret(Opcode& oc) {
|
||||||
|
|
||||||
_code = TRY(fun.code());
|
_code = TRY(fun.code());
|
||||||
_constants = TRY(fun.constants());
|
_constants = TRY(fun.constants());
|
||||||
|
_closure = TRY(fun.closure());
|
||||||
_fun = std::move(fun);
|
_fun = std::move(fun);
|
||||||
_pc = pc + 1;
|
_pc = pc + 1;
|
||||||
_base = oldbase;
|
_base = oldbase;
|
||||||
|
@ -155,11 +157,21 @@ Result<void> VM::vm_make_closure(Opcode& oc) {
|
||||||
return Result<void>();
|
return Result<void>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<void> VM::vm_closure_load(Opcode& oc) {
|
||||||
|
uint64_t acc = (uint64_t)oc.arg1().arg;
|
||||||
|
Value val = TRY(_closure.get((uint64_t)oc.arg2().arg));
|
||||||
|
setreg(acc, val);
|
||||||
|
_pc++;
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
Result<void> VM::step() {
|
Result<void> VM::step() {
|
||||||
auto opcode = TRY(_code.get(_pc));
|
auto opcode = TRY(_code.get(_pc));
|
||||||
if (!opcode.is<Opcode>()) return ERROR(TypeMismatch);
|
if (!opcode.is<Opcode>()) return ERROR(TypeMismatch);
|
||||||
Opcode& oc = *opcode.to<Opcode>();
|
Opcode& oc = *opcode.to<Opcode>();
|
||||||
|
|
||||||
|
// TRY(debug_print(TRY(oc.copy_value())));
|
||||||
|
|
||||||
switch (oc.opcode()) {
|
switch (oc.opcode()) {
|
||||||
case Oc::Mov:
|
case Oc::Mov:
|
||||||
TRY(vm_mov(oc));
|
TRY(vm_mov(oc));
|
||||||
|
@ -191,6 +203,9 @@ Result<void> VM::step() {
|
||||||
case Oc::MakeClosure:
|
case Oc::MakeClosure:
|
||||||
TRY(vm_make_closure(oc));
|
TRY(vm_make_closure(oc));
|
||||||
break;
|
break;
|
||||||
|
case Oc::ClosureLoad:
|
||||||
|
TRY(vm_closure_load(oc));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return ERROR(NotImplemented);
|
return ERROR(NotImplemented);
|
||||||
}
|
}
|
||||||
|
@ -206,6 +221,7 @@ Result<Value> VM::run(const Function& fun) {
|
||||||
_base = 0;
|
_base = 0;
|
||||||
_code = TRY(fun.code());
|
_code = TRY(fun.code());
|
||||||
_constants = TRY(fun.constants());
|
_constants = TRY(fun.constants());
|
||||||
|
_closure = TRY(fun.closure());
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
auto rc = step();
|
auto rc = step();
|
||||||
|
|
|
@ -32,6 +32,7 @@ class VM {
|
||||||
Result<void> vm_jump(Opcode& oc);
|
Result<void> vm_jump(Opcode& oc);
|
||||||
|
|
||||||
Result<void> vm_make_closure(Opcode& oc);
|
Result<void> vm_make_closure(Opcode& oc);
|
||||||
|
Result<void> vm_closure_load(Opcode& oc);
|
||||||
|
|
||||||
Result<Value> get(bool is_const, uint64_t idx);
|
Result<Value> get(bool is_const, uint64_t idx);
|
||||||
Result<Value> getconst(uint64_t idx);
|
Result<Value> getconst(uint64_t idx);
|
||||||
|
@ -44,6 +45,7 @@ class VM {
|
||||||
Function _fun;
|
Function _fun;
|
||||||
Array _code;
|
Array _code;
|
||||||
Array _constants;
|
Array _constants;
|
||||||
|
Array _closure;
|
||||||
uint64_t _pc;
|
uint64_t _pc;
|
||||||
uint64_t _base;
|
uint64_t _base;
|
||||||
Value _res;
|
Value _res;
|
||||||
|
|
Loading…
Reference in a new issue