Implement exception guards and serialization/deserialization
This commit is contained in:
parent
2e3032ad26
commit
be4224a22b
19 changed files with 940 additions and 89 deletions
|
@ -23,6 +23,7 @@ target_sources(vm_lib
|
||||||
src/fio.cpp
|
src/fio.cpp
|
||||||
src/stdlib.cpp
|
src/stdlib.cpp
|
||||||
src/lineedit.cpp
|
src/lineedit.cpp
|
||||||
|
src/serialize.cpp
|
||||||
|
|
||||||
PUBLIC
|
PUBLIC
|
||||||
FILE_SET HEADERS
|
FILE_SET HEADERS
|
||||||
|
@ -43,6 +44,7 @@ target_sources(vm_lib
|
||||||
src/fio.hpp
|
src/fio.hpp
|
||||||
src/stdlib.hpp
|
src/stdlib.hpp
|
||||||
src/lineedit.hpp
|
src/lineedit.hpp
|
||||||
|
src/serialize.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(valeri src/valeri.cpp)
|
add_executable(valeri src/valeri.cpp)
|
||||||
|
@ -67,6 +69,8 @@ set(LISP_TESTS
|
||||||
dict
|
dict
|
||||||
function
|
function
|
||||||
collections
|
collections
|
||||||
|
continuations
|
||||||
|
serialize
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -265,6 +265,7 @@ Result<PodObject*> Arena::gc_stack(PodStackFrame* obj) {
|
||||||
nobj->header.tag = Tag::StackFrame;
|
nobj->header.tag = Tag::StackFrame;
|
||||||
nobj->parent = TRY(gc_pod(obj->parent.get()));
|
nobj->parent = TRY(gc_pod(obj->parent.get()));
|
||||||
nobj->fun = TRY(gc_pod(obj->fun.get()));
|
nobj->fun = TRY(gc_pod(obj->fun.get()));
|
||||||
|
nobj->guard = obj->guard;
|
||||||
nobj->pc = obj->pc;
|
nobj->pc = obj->pc;
|
||||||
nobj->size = obj->size;
|
nobj->size = obj->size;
|
||||||
for (uint64_t i = 0; i < obj->size; i++) {
|
for (uint64_t i = 0; i < obj->size; i++) {
|
||||||
|
|
|
@ -16,6 +16,10 @@ class GcRootList;
|
||||||
Arena& get_arena();
|
Arena& get_arena();
|
||||||
void set_arena(Arena& arena);
|
void set_arena(Arena& arena);
|
||||||
|
|
||||||
|
static uint64_t round_up(uint64_t number, uint64_t to) {
|
||||||
|
return ((number + to - 1) / to) * to;
|
||||||
|
}
|
||||||
|
|
||||||
class GcRootBase {
|
class GcRootBase {
|
||||||
public:
|
public:
|
||||||
friend class Arena;
|
friend class Arena;
|
||||||
|
@ -131,11 +135,29 @@ class Arena {
|
||||||
uint64_t objsize = sizeof(T) + extra;
|
uint64_t objsize = sizeof(T) + extra;
|
||||||
auto ptr = _first->alloc(objsize);
|
auto ptr = _first->alloc(objsize);
|
||||||
|
|
||||||
if (ptr.has_value()) return (T*)ptr.value();
|
if (ptr.has_value()) {
|
||||||
|
new (ptr.value()) T();
|
||||||
|
return (T*)ptr.value();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: trigger GC
|
TRY(gc());
|
||||||
|
|
||||||
return (T*)TRY(_first->alloc(objsize));
|
T* res = (T*)TRY(_first->alloc(objsize));
|
||||||
|
new (res) T();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
Result<T*> alloc_bytes(uint64_t size = 0) {
|
||||||
|
auto ptr = _first->alloc(size);
|
||||||
|
|
||||||
|
if (ptr.has_value()) {
|
||||||
|
return (T*)ptr.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
TRY(gc());
|
||||||
|
|
||||||
|
return (T*)TRY(_first->alloc(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<void> gc();
|
Result<void> gc();
|
||||||
|
@ -205,6 +227,11 @@ Result<T*> arena_alloc(uint64_t extra = 0) {
|
||||||
return get_arena().alloc<T>(extra);
|
return get_arena().alloc<T>(extra);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
Result<T*> arena_alloc_bytes(uint64_t size = 0) {
|
||||||
|
return get_arena().alloc_bytes<T>(size);
|
||||||
|
}
|
||||||
|
|
||||||
Result<void> arena_gc();
|
Result<void> arena_gc();
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
|
|
264
src/common.cpp
264
src/common.cpp
|
@ -61,7 +61,6 @@ Result<Symbol> Symbol::create(String& rhs) {
|
||||||
uint64_t res_size = rhs_size;
|
uint64_t res_size = rhs_size;
|
||||||
|
|
||||||
auto pod = TRY(arena_alloc<PodSymbol>(res_size * sizeof(char32_t)));
|
auto pod = TRY(arena_alloc<PodSymbol>(res_size * sizeof(char32_t)));
|
||||||
pod->header.tag = Tag::Symbol;
|
|
||||||
pod->size = res_size;
|
pod->size = res_size;
|
||||||
memcpy(pod->data, rhs._value->data, sizeof(char32_t) * rhs_size);
|
memcpy(pod->data, rhs._value->data, sizeof(char32_t) * rhs_size);
|
||||||
|
|
||||||
|
@ -73,7 +72,6 @@ Result<String> String::create(const Symbol& rhs) {
|
||||||
uint64_t res_size = rhs_size;
|
uint64_t res_size = rhs_size;
|
||||||
|
|
||||||
auto pod = TRY(arena_alloc<PodString>(res_size * sizeof(char32_t)));
|
auto pod = TRY(arena_alloc<PodString>(res_size * sizeof(char32_t)));
|
||||||
pod->header.tag = Tag::String;
|
|
||||||
pod->size = res_size;
|
pod->size = res_size;
|
||||||
memcpy(pod->data, rhs._value->data, sizeof(char32_t) * rhs_size);
|
memcpy(pod->data, rhs._value->data, sizeof(char32_t) * rhs_size);
|
||||||
|
|
||||||
|
@ -87,7 +85,6 @@ Result<ByteArray> ByteArray::create(const String& str) {
|
||||||
size += utf8_codepoint_size(TRY(str[i]));
|
size += utf8_codepoint_size(TRY(str[i]));
|
||||||
}
|
}
|
||||||
auto pod = TRY(arena_alloc<PodByteArray>(size * sizeof(char)));
|
auto pod = TRY(arena_alloc<PodByteArray>(size * sizeof(char)));
|
||||||
pod->header.tag = Tag::ByteArray;
|
|
||||||
pod->size = size;
|
pod->size = size;
|
||||||
|
|
||||||
char* res = pod->data;
|
char* res = pod->data;
|
||||||
|
@ -100,9 +97,106 @@ Result<ByteArray> ByteArray::create(const String& str) {
|
||||||
return ByteArray(TRY(MkGcRoot(pod)));
|
return ByteArray(TRY(MkGcRoot(pod)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<String> ByteArray::hex() const {
|
||||||
|
auto size = _value->size * 2;
|
||||||
|
auto pod = TRY(arena_alloc<PodString>(size * sizeof(char32_t)));
|
||||||
|
pod->size = size;
|
||||||
|
|
||||||
|
const char* hexa = "0123456789ABCDEF";
|
||||||
|
for (uint64_t i = 0; i < _value->size; i++) {
|
||||||
|
auto b = (uint8_t)_value->data[i];
|
||||||
|
pod->data[i * 2] = hexa[(b >> 4) & 0xF];
|
||||||
|
pod->data[i * 2 + 1] = hexa[b & 0xF];
|
||||||
|
}
|
||||||
|
|
||||||
|
return String(TRY(MkGcRoot(pod)));
|
||||||
|
}
|
||||||
|
Result<ByteArray> ByteArray::to_rle() const {
|
||||||
|
auto size = _value->size;
|
||||||
|
|
||||||
|
auto compressed_size = 0;
|
||||||
|
for (uint64_t i = 0; i < size; ++i) {
|
||||||
|
auto b = _value->data[i];
|
||||||
|
if (b == 0) {
|
||||||
|
uint64_t rl = 0;
|
||||||
|
for (uint64_t j = 0; j < 255 && i + j < size && _value->data[i + j] == 0;
|
||||||
|
j++) {
|
||||||
|
rl++;
|
||||||
|
}
|
||||||
|
i += rl - 1;
|
||||||
|
compressed_size += 2;
|
||||||
|
} else {
|
||||||
|
++compressed_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pod = TRY(arena_alloc<PodByteArray>(compressed_size));
|
||||||
|
pod->size = compressed_size;
|
||||||
|
|
||||||
|
auto pos = 0;
|
||||||
|
for (uint64_t i = 0; i < size; ++i) {
|
||||||
|
auto b = _value->data[i];
|
||||||
|
if (b == 0) {
|
||||||
|
uint64_t rl = 0;
|
||||||
|
for (uint64_t j = 0; j < 255 && i + j < size && _value->data[i + j] == 0;
|
||||||
|
j++) {
|
||||||
|
rl++;
|
||||||
|
}
|
||||||
|
i += rl - 1;
|
||||||
|
pod->data[pos] = 0;
|
||||||
|
pod->data[pos + 1] = rl;
|
||||||
|
pos += 2;
|
||||||
|
} else {
|
||||||
|
pod->data[pos] = _value->data[i];
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ByteArray(TRY(MkGcRoot(pod)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<ByteArray> ByteArray::from_rle() const {
|
||||||
|
uint64_t size = _value->size;
|
||||||
|
uint64_t decompressed_size = 0;
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i < size; ++i) {
|
||||||
|
auto b = _value->data[i];
|
||||||
|
if (b == 0) {
|
||||||
|
if (i + 1 >= size) {
|
||||||
|
return ERROR(KeyError);
|
||||||
|
}
|
||||||
|
decompressed_size += _value->data[i + 1];
|
||||||
|
i += 1;
|
||||||
|
} else {
|
||||||
|
++decompressed_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pod = TRY(arena_alloc<PodByteArray>(decompressed_size));
|
||||||
|
pod->size = decompressed_size;
|
||||||
|
|
||||||
|
uint64_t pos = 0;
|
||||||
|
for (uint64_t i = 0; i < size; ++i) {
|
||||||
|
auto b = _value->data[i];
|
||||||
|
if (b == 0) {
|
||||||
|
uint64_t run_size = _value->data[i + 1];
|
||||||
|
|
||||||
|
for (uint64_t j = 0; j < run_size; j++) {
|
||||||
|
pod->data[pos + j] = 0;
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
pos += run_size;
|
||||||
|
} else {
|
||||||
|
pod->data[pos] = _value->data[i];
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ByteArray(TRY(MkGcRoot(pod)));
|
||||||
|
}
|
||||||
|
|
||||||
Result<SrcLoc> SrcLoc::create(const SourceRange& sourcerange) {
|
Result<SrcLoc> SrcLoc::create(const SourceRange& sourcerange) {
|
||||||
auto pod = TRY(arena_alloc<PodSrcLoc>());
|
auto pod = TRY(arena_alloc<PodSrcLoc>());
|
||||||
pod->header.tag = Tag::SrcLoc;
|
|
||||||
pod->sourcerange = sourcerange;
|
pod->sourcerange = sourcerange;
|
||||||
|
|
||||||
return SrcLoc(TRY(MkGcRoot(pod)));
|
return SrcLoc(TRY(MkGcRoot(pod)));
|
||||||
|
@ -134,7 +228,6 @@ Result<short> SrcLoc::cmp(const SrcLoc& rhs) const {
|
||||||
Result<Syntax> Syntax::create(const String& filename, const SrcLoc& srcloc,
|
Result<Syntax> Syntax::create(const String& filename, const SrcLoc& srcloc,
|
||||||
const Value& expression) {
|
const Value& expression) {
|
||||||
auto pod = TRY(arena_alloc<PodSyntax>());
|
auto pod = TRY(arena_alloc<PodSyntax>());
|
||||||
pod->header.tag = Tag::Syntax;
|
|
||||||
pod->filename = filename.pod();
|
pod->filename = filename.pod();
|
||||||
pod->srcloc = srcloc.pod();
|
pod->srcloc = srcloc.pod();
|
||||||
pod->expression = expression.pod();
|
pod->expression = expression.pod();
|
||||||
|
@ -342,12 +435,13 @@ Result<short> Module::cmp(const Module& rhs) const {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<StackFrame> StackFrame::create(const Value& parent, const Value& fun) {
|
Result<StackFrame> StackFrame::create(const Value& parent, const Value& fun,
|
||||||
|
bool guard) {
|
||||||
auto pod = TRY(arena_alloc<PodStackFrame>());
|
auto pod = TRY(arena_alloc<PodStackFrame>());
|
||||||
pod->header.tag = Tag::StackFrame;
|
|
||||||
|
|
||||||
pod->parent = parent.pod();
|
pod->parent = parent.pod();
|
||||||
pod->fun = fun.pod();
|
pod->fun = fun.pod();
|
||||||
|
pod->guard = guard;
|
||||||
pod->pc = 0;
|
pod->pc = 0;
|
||||||
pod->size = 0;
|
pod->size = 0;
|
||||||
|
|
||||||
|
@ -371,11 +465,11 @@ Result<Value> StackFrame::get(uint64_t idx) const {
|
||||||
Result<StackFrame> StackFrame::set(uint64_t idx, const Value& val) const {
|
Result<StackFrame> StackFrame::set(uint64_t idx, const Value& val) const {
|
||||||
uint64_t size = std::max(_value->size, idx + 1);
|
uint64_t size = std::max(_value->size, idx + 1);
|
||||||
auto pod = TRY(arena_alloc<PodStackFrame>(sizeof(OffPtr<PodObject>) * size));
|
auto pod = TRY(arena_alloc<PodStackFrame>(sizeof(OffPtr<PodObject>) * size));
|
||||||
pod->header.tag = Tag::StackFrame;
|
|
||||||
|
|
||||||
pod->parent = _value->parent;
|
pod->parent = _value->parent;
|
||||||
pod->fun = _value->fun;
|
pod->fun = _value->fun;
|
||||||
pod->pc = _value->pc;
|
pod->pc = _value->pc;
|
||||||
|
pod->guard = _value->guard;
|
||||||
pod->size = size;
|
pod->size = size;
|
||||||
|
|
||||||
for (uint64_t i = 0; i < _value->size; i++) {
|
for (uint64_t i = 0; i < _value->size; i++) {
|
||||||
|
@ -394,10 +488,10 @@ Result<StackFrame> StackFrame::set(uint64_t idx, const Value& val) const {
|
||||||
|
|
||||||
Result<StackFrame> StackFrame::settop(uint64_t idx) const {
|
Result<StackFrame> StackFrame::settop(uint64_t idx) const {
|
||||||
auto pod = TRY(arena_alloc<PodStackFrame>(sizeof(OffPtr<PodObject>) * idx));
|
auto pod = TRY(arena_alloc<PodStackFrame>(sizeof(OffPtr<PodObject>) * idx));
|
||||||
pod->header.tag = Tag::StackFrame;
|
|
||||||
|
|
||||||
pod->parent = _value->parent;
|
pod->parent = _value->parent;
|
||||||
pod->fun = _value->fun;
|
pod->fun = _value->fun;
|
||||||
|
pod->guard = _value->guard;
|
||||||
pod->pc = _value->pc;
|
pod->pc = _value->pc;
|
||||||
pod->size = idx;
|
pod->size = idx;
|
||||||
|
|
||||||
|
@ -427,10 +521,10 @@ uint64_t StackFrame::pc() const { return _value->pc; }
|
||||||
Result<StackFrame> StackFrame::setpc(uint64_t pc) {
|
Result<StackFrame> StackFrame::setpc(uint64_t pc) {
|
||||||
auto pod =
|
auto pod =
|
||||||
TRY(arena_alloc<PodStackFrame>(sizeof(OffPtr<PodObject>) * _value->size));
|
TRY(arena_alloc<PodStackFrame>(sizeof(OffPtr<PodObject>) * _value->size));
|
||||||
pod->header.tag = Tag::StackFrame;
|
|
||||||
|
|
||||||
pod->parent = _value->parent;
|
pod->parent = _value->parent;
|
||||||
pod->fun = _value->fun;
|
pod->fun = _value->fun;
|
||||||
|
pod->guard = _value->guard;
|
||||||
pod->pc = pc;
|
pod->pc = pc;
|
||||||
pod->size = _value->size;
|
pod->size = _value->size;
|
||||||
|
|
||||||
|
@ -476,6 +570,105 @@ Result<StackFrame> StackFrame::ret(uint64_t regnum) const {
|
||||||
return std::move(parent_stack);
|
return std::move(parent_stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<StackFrame> StackFrame::detach(uint64_t depth) const {
|
||||||
|
if (depth == 0) {
|
||||||
|
uint64_t size = _value->size;
|
||||||
|
auto pod =
|
||||||
|
TRY(arena_alloc<PodStackFrame>(sizeof(OffPtr<PodObject>) * size));
|
||||||
|
|
||||||
|
pod->parent = TRY(Nil::create()).pod();
|
||||||
|
pod->fun = _value->fun;
|
||||||
|
pod->guard = _value->guard;
|
||||||
|
pod->pc = _value->pc;
|
||||||
|
pod->size = size;
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i < _value->size; i++) {
|
||||||
|
pod->data[i] = _value->data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return StackFrame(TRY(MkGcRoot(pod)));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto par = TRY(parent());
|
||||||
|
if (par.is<Nil>()) return ERROR(KeyError);
|
||||||
|
|
||||||
|
StackFrame& par_frame = *par.to<StackFrame>();
|
||||||
|
|
||||||
|
auto par_frame_new = TRY(par_frame.detach(depth - 1));
|
||||||
|
|
||||||
|
uint64_t size = _value->size;
|
||||||
|
auto pod = TRY(arena_alloc<PodStackFrame>(sizeof(OffPtr<PodObject>) * size));
|
||||||
|
|
||||||
|
pod->parent = par_frame_new.pod();
|
||||||
|
pod->fun = _value->fun;
|
||||||
|
pod->guard = _value->guard;
|
||||||
|
pod->pc = _value->pc;
|
||||||
|
pod->size = size;
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i < _value->size; i++) {
|
||||||
|
pod->data[i] = _value->data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return StackFrame(TRY(MkGcRoot(pod)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<StackFrame> StackFrame::attach(const StackFrame& frame) const {
|
||||||
|
auto par = TRY(parent());
|
||||||
|
if (par.is<Nil>()) {
|
||||||
|
uint64_t size = _value->size;
|
||||||
|
auto pod =
|
||||||
|
TRY(arena_alloc<PodStackFrame>(sizeof(OffPtr<PodObject>) * size));
|
||||||
|
|
||||||
|
pod->parent = frame.pod();
|
||||||
|
pod->fun = _value->fun;
|
||||||
|
pod->guard = _value->guard;
|
||||||
|
pod->pc = _value->pc;
|
||||||
|
pod->size = size;
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i < _value->size; i++) {
|
||||||
|
pod->data[i] = _value->data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return StackFrame(TRY(MkGcRoot(pod)));
|
||||||
|
}
|
||||||
|
|
||||||
|
StackFrame& par_frame = *par.to<StackFrame>();
|
||||||
|
|
||||||
|
auto par_frame_new = TRY(par_frame.attach(frame));
|
||||||
|
|
||||||
|
uint64_t size = _value->size;
|
||||||
|
auto pod = TRY(arena_alloc<PodStackFrame>(sizeof(OffPtr<PodObject>) * size));
|
||||||
|
|
||||||
|
pod->parent = par_frame_new.pod();
|
||||||
|
pod->fun = _value->fun;
|
||||||
|
pod->guard = _value->guard;
|
||||||
|
pod->pc = _value->pc;
|
||||||
|
pod->size = size;
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i < _value->size; i++) {
|
||||||
|
pod->data[i] = _value->data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return StackFrame(TRY(MkGcRoot(pod)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<StackFrame> StackFrame::set_guard(bool guard) const {
|
||||||
|
uint64_t size = _value->size;
|
||||||
|
auto pod = TRY(arena_alloc<PodStackFrame>(sizeof(OffPtr<PodObject>) * size));
|
||||||
|
|
||||||
|
pod->parent = _value->parent;
|
||||||
|
pod->fun = _value->fun;
|
||||||
|
pod->guard = guard;
|
||||||
|
pod->pc = _value->pc;
|
||||||
|
pod->size = size;
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i < _value->size; i++) {
|
||||||
|
pod->data[i] = _value->data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return StackFrame(TRY(MkGcRoot(pod)));
|
||||||
|
}
|
||||||
|
|
||||||
Result<String> StackFrame::backtrace(uint64_t indent) const {
|
Result<String> StackFrame::backtrace(uint64_t indent) const {
|
||||||
String res = TRY(String::create(""));
|
String res = TRY(String::create(""));
|
||||||
|
|
||||||
|
@ -483,34 +676,36 @@ Result<String> StackFrame::backtrace(uint64_t indent) const {
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
Value par = TRY(cur.parent());
|
Value par = TRY(cur.parent());
|
||||||
// If parent frame is empty - we are at the top-level. Top-level is always
|
|
||||||
// <unnamed>, so let's just skip it
|
|
||||||
if (par.is<Nil>()) break;
|
|
||||||
|
|
||||||
auto fun = TRY(cur.fun());
|
auto fun = TRY(cur.fun());
|
||||||
|
|
||||||
for (uint64_t i = 0; i < indent; i++) {
|
for (uint64_t i = 0; i < indent; i++) {
|
||||||
res = TRY(res.concat(" "));
|
res = TRY(res.concat(" "));
|
||||||
}
|
}
|
||||||
|
|
||||||
res = TRY(res.concat("Function "));
|
if (cur.guard()) {
|
||||||
if (fun.is<Function>()) {
|
res = TRY(res.concat("guard"));
|
||||||
Function& f = *fun.to<Function>();
|
} else {
|
||||||
auto name = TRY(f.name());
|
res = TRY(res.concat("Function "));
|
||||||
if (!name.is<Symbol>()) {
|
if (fun.is<Function>()) {
|
||||||
name = Value(TRY(String::create("<unnamed>")));
|
Function& f = *fun.to<Function>();
|
||||||
} else {
|
auto name = TRY(f.name());
|
||||||
name = Value(TRY(String::create(*name.to<Symbol>())));
|
if (!name.is<Symbol>()) {
|
||||||
|
name = Value(TRY(String::create("<unnamed>")));
|
||||||
|
} else {
|
||||||
|
name = Value(TRY(String::create(*name.to<Symbol>())));
|
||||||
|
}
|
||||||
|
res = TRY(res.concat(*name.to<String>()));
|
||||||
|
} else if (fun.is<StdlibFunction>()) {
|
||||||
|
StdlibFunction& f = *fun.to<StdlibFunction>();
|
||||||
|
auto name = TRY(String::create(TRY(f.name())));
|
||||||
|
res = TRY(res.concat(name));
|
||||||
}
|
}
|
||||||
res = TRY(res.concat(*name.to<String>()));
|
|
||||||
} else if (fun.is<StdlibFunction>()) {
|
|
||||||
StdlibFunction& f = *fun.to<StdlibFunction>();
|
|
||||||
auto name = TRY(String::create(TRY(f.name())));
|
|
||||||
res = TRY(res.concat(name));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
res = TRY(res.concat("\n"));
|
res = TRY(res.concat("\n"));
|
||||||
|
|
||||||
|
if (par.is<Nil>()) break;
|
||||||
|
|
||||||
cur = TRY(par.to<StackFrame>()->copy());
|
cur = TRY(par.to<StackFrame>()->copy());
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
@ -541,7 +736,6 @@ Result<short> Error::cmp(const Error& rhs) const {
|
||||||
Result<Continuation> Continuation::create(const Value& value,
|
Result<Continuation> Continuation::create(const Value& value,
|
||||||
const StackFrame& frame) {
|
const StackFrame& frame) {
|
||||||
auto pod = TRY(arena_alloc<PodContinuation>());
|
auto pod = TRY(arena_alloc<PodContinuation>());
|
||||||
pod->header.tag = Tag::Continuation;
|
|
||||||
|
|
||||||
pod->value = value.pod();
|
pod->value = value.pod();
|
||||||
pod->frame = frame.pod();
|
pod->frame = frame.pod();
|
||||||
|
@ -577,7 +771,6 @@ Result<short> Continuation::cmp(const Continuation& rhs) const {
|
||||||
|
|
||||||
Result<Task> Task::create(uint64_t task_id, const Array& params) {
|
Result<Task> Task::create(uint64_t task_id, const Array& params) {
|
||||||
auto pod = TRY(arena_alloc<PodTask>());
|
auto pod = TRY(arena_alloc<PodTask>());
|
||||||
pod->header.tag = Tag::Task;
|
|
||||||
|
|
||||||
pod->task_id = task_id;
|
pod->task_id = task_id;
|
||||||
pod->params = params.pod();
|
pod->params = params.pod();
|
||||||
|
@ -614,7 +807,6 @@ Result<short> Task::cmp(const Task& rhs) const {
|
||||||
|
|
||||||
Result<TaskResult> TaskResult::create(const Value& result, const Value& error) {
|
Result<TaskResult> TaskResult::create(const Value& result, const Value& error) {
|
||||||
auto pod = TRY(arena_alloc<PodTaskResult>());
|
auto pod = TRY(arena_alloc<PodTaskResult>());
|
||||||
pod->header.tag = Tag::TaskResult;
|
|
||||||
|
|
||||||
pod->result = result.pod();
|
pod->result = result.pod();
|
||||||
pod->error = error.pod();
|
pod->error = error.pod();
|
||||||
|
@ -650,7 +842,6 @@ Result<short> TaskResult::cmp(const TaskResult& rhs) const {
|
||||||
|
|
||||||
Result<Pair> Pair::create(const Value& first, const Value& rest) {
|
Result<Pair> Pair::create(const Value& first, const Value& rest) {
|
||||||
auto pod = TRY(arena_alloc<PodPair>());
|
auto pod = TRY(arena_alloc<PodPair>());
|
||||||
pod->header.tag = Tag::Pair;
|
|
||||||
pod->first = first.pod();
|
pod->first = first.pod();
|
||||||
pod->rest = rest.pod();
|
pod->rest = rest.pod();
|
||||||
|
|
||||||
|
@ -719,7 +910,6 @@ Result<Function> Function::create(const Value& name, uint64_t arity,
|
||||||
const Array& constants, const Array& code,
|
const Array& constants, const Array& code,
|
||||||
const Array& closure) {
|
const Array& closure) {
|
||||||
auto pod = TRY(arena_alloc<PodFunction>());
|
auto pod = TRY(arena_alloc<PodFunction>());
|
||||||
pod->header.tag = Tag::Function;
|
|
||||||
pod->arity = arity;
|
pod->arity = arity;
|
||||||
pod->name = name.pod();
|
pod->name = name.pod();
|
||||||
pod->constants = constants.pod();
|
pod->constants = constants.pod();
|
||||||
|
@ -732,7 +922,6 @@ Result<Function> Function::create(const Value& name, uint64_t arity,
|
||||||
Result<Function> Function::create(const Function& prototype,
|
Result<Function> Function::create(const Function& prototype,
|
||||||
const Array& closure) {
|
const Array& closure) {
|
||||||
auto pod = TRY(arena_alloc<PodFunction>());
|
auto pod = TRY(arena_alloc<PodFunction>());
|
||||||
pod->header.tag = Tag::Function;
|
|
||||||
pod->arity = prototype._value->arity;
|
pod->arity = prototype._value->arity;
|
||||||
pod->name = prototype._value->name;
|
pod->name = prototype._value->name;
|
||||||
pod->constants = prototype._value->constants;
|
pod->constants = prototype._value->constants;
|
||||||
|
@ -760,7 +949,6 @@ Result<Array> Function::closure() const {
|
||||||
|
|
||||||
Result<StdlibFunction> StdlibFunction::create(StdlibFunctionId fun_id) {
|
Result<StdlibFunction> StdlibFunction::create(StdlibFunctionId fun_id) {
|
||||||
auto pod = TRY(arena_alloc<PodStdlibFunction>());
|
auto pod = TRY(arena_alloc<PodStdlibFunction>());
|
||||||
pod->header.tag = Tag::StdlibFunction;
|
|
||||||
pod->fun_id = (uint64_t)fun_id;
|
pod->fun_id = (uint64_t)fun_id;
|
||||||
|
|
||||||
return StdlibFunction(TRY(MkGcRoot(pod)));
|
return StdlibFunction(TRY(MkGcRoot(pod)));
|
||||||
|
@ -778,7 +966,6 @@ StdlibFunctionId StdlibFunction::fun_id() const {
|
||||||
|
|
||||||
Result<Module> Module::create(const Value& name, const Function& fun) {
|
Result<Module> Module::create(const Value& name, const Function& fun) {
|
||||||
auto pod = TRY(arena_alloc<PodModule>());
|
auto pod = TRY(arena_alloc<PodModule>());
|
||||||
pod->header.tag = Tag::Module;
|
|
||||||
pod->name = name.pod();
|
pod->name = name.pod();
|
||||||
pod->fun = fun.pod();
|
pod->fun = fun.pod();
|
||||||
|
|
||||||
|
@ -847,7 +1034,6 @@ Result<Array> Array::set(uint64_t idx, const Value& value) const {
|
||||||
if (idx >= res_size) return ERROR(IndexOutOfRange);
|
if (idx >= res_size) return ERROR(IndexOutOfRange);
|
||||||
|
|
||||||
auto pod = TRY(arena_alloc<PodArray>(res_size * sizeof(OffPtr<PodObject>)));
|
auto pod = TRY(arena_alloc<PodArray>(res_size * sizeof(OffPtr<PodObject>)));
|
||||||
pod->header.tag = Tag::Array;
|
|
||||||
pod->size = res_size;
|
pod->size = res_size;
|
||||||
for (uint64_t i = 0; i < res_size; i++) {
|
for (uint64_t i = 0; i < res_size; i++) {
|
||||||
pod->data[i] = _value->data[i].get();
|
pod->data[i] = _value->data[i].get();
|
||||||
|
@ -872,7 +1058,6 @@ Result<Array> Array::append(const Value& rhs) const {
|
||||||
auto size = TRY(this->size());
|
auto size = TRY(this->size());
|
||||||
|
|
||||||
auto pod = TRY(arena_alloc<PodArray>(res_size * sizeof(OffPtr<PodObject>)));
|
auto pod = TRY(arena_alloc<PodArray>(res_size * sizeof(OffPtr<PodObject>)));
|
||||||
pod->header.tag = Tag::Array;
|
|
||||||
pod->size = res_size;
|
pod->size = res_size;
|
||||||
for (uint64_t i = 0; i < size; i++) {
|
for (uint64_t i = 0; i < size; i++) {
|
||||||
pod->data[i] = _value->data[i].get();
|
pod->data[i] = _value->data[i].get();
|
||||||
|
@ -930,7 +1115,6 @@ Result<Dict> Dict::set(const Value& key, const Value& value) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pod = TRY(arena_alloc<PodDict>(2 * s * sizeof(OffPtr<PodObject>)));
|
auto pod = TRY(arena_alloc<PodDict>(2 * s * sizeof(OffPtr<PodObject>)));
|
||||||
pod->header.tag = Tag::Dict;
|
|
||||||
pod->size = s;
|
pod->size = s;
|
||||||
|
|
||||||
auto vpod = _value.get();
|
auto vpod = _value.get();
|
||||||
|
@ -1092,7 +1276,7 @@ Result<short> Dict::cmp(const Dict& rhs) const {
|
||||||
uint64_t i = 0;
|
uint64_t i = 0;
|
||||||
uint64_t j = 0;
|
uint64_t j = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
if (i == lsize && j == lsize) return 0;
|
if (i == lsize && j == rsize) return 0;
|
||||||
|
|
||||||
short cmp = short(i == lsize) - short(j == rsize);
|
short cmp = short(i == lsize) - short(j == rsize);
|
||||||
if (cmp != 0) return cmp;
|
if (cmp != 0) return cmp;
|
||||||
|
@ -1113,7 +1297,7 @@ Result<short> Array::cmp(const Array& rhs) const {
|
||||||
uint64_t i = 0;
|
uint64_t i = 0;
|
||||||
uint64_t j = 0;
|
uint64_t j = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
if (i == lsize && j == lsize) return 0;
|
if (i == lsize && j == rsize) return 0;
|
||||||
|
|
||||||
short cmp = short(i == lsize) - short(j == rsize);
|
short cmp = short(i == lsize) - short(j == rsize);
|
||||||
if (cmp != 0) return cmp;
|
if (cmp != 0) return cmp;
|
||||||
|
|
|
@ -166,7 +166,6 @@ class Nil : public Object {
|
||||||
|
|
||||||
static Result<Nil> create() {
|
static Result<Nil> create() {
|
||||||
auto pod = TRY(arena_alloc<PodNil>());
|
auto pod = TRY(arena_alloc<PodNil>());
|
||||||
pod->header.tag = Tag::Nil;
|
|
||||||
|
|
||||||
return Nil(TRY(MkGcRoot(pod)));
|
return Nil(TRY(MkGcRoot(pod)));
|
||||||
}
|
}
|
||||||
|
@ -209,7 +208,6 @@ class Array : public Object {
|
||||||
|
|
||||||
static Result<Array> create() {
|
static Result<Array> create() {
|
||||||
auto pod = TRY(arena_alloc<PodArray>());
|
auto pod = TRY(arena_alloc<PodArray>());
|
||||||
pod->header.tag = Tag::Array;
|
|
||||||
|
|
||||||
pod->size = 0;
|
pod->size = 0;
|
||||||
|
|
||||||
|
@ -237,7 +235,6 @@ class Array : public Object {
|
||||||
uint64_t res_size = lhs_size + rhs_size;
|
uint64_t res_size = lhs_size + rhs_size;
|
||||||
|
|
||||||
auto pod = TRY(arena_alloc<PodArray>(res_size * sizeof(PodObject*)));
|
auto pod = TRY(arena_alloc<PodArray>(res_size * sizeof(PodObject*)));
|
||||||
pod->header.tag = Tag::Array;
|
|
||||||
pod->size = res_size;
|
pod->size = res_size;
|
||||||
for (uint64_t i = 0; i < lhs_size; i++) {
|
for (uint64_t i = 0; i < lhs_size; i++) {
|
||||||
pod->data[i] = _value->data[i].get();
|
pod->data[i] = _value->data[i].get();
|
||||||
|
@ -253,7 +250,6 @@ class Array : public Object {
|
||||||
if (start > end) return ERROR(IndexOutOfRange);
|
if (start > end) return ERROR(IndexOutOfRange);
|
||||||
uint64_t res_size = end - start;
|
uint64_t res_size = end - start;
|
||||||
auto pod = TRY(arena_alloc<PodArray>(res_size * sizeof(PodObject*)));
|
auto pod = TRY(arena_alloc<PodArray>(res_size * sizeof(PodObject*)));
|
||||||
pod->header.tag = Tag::Array;
|
|
||||||
pod->size = res_size;
|
pod->size = res_size;
|
||||||
for (uint64_t i = 0; i < end - start; i++) {
|
for (uint64_t i = 0; i < end - start; i++) {
|
||||||
pod->data[i] = _value->data[start + i];
|
pod->data[i] = _value->data[start + i];
|
||||||
|
@ -293,7 +289,6 @@ class ByteArray : public Object {
|
||||||
}
|
}
|
||||||
static Result<ByteArray> create(char* chars, int64_t size) {
|
static Result<ByteArray> create(char* chars, int64_t size) {
|
||||||
auto pod = TRY(arena_alloc<PodByteArray>(size * sizeof(char)));
|
auto pod = TRY(arena_alloc<PodByteArray>(size * sizeof(char)));
|
||||||
pod->header.tag = Tag::ByteArray;
|
|
||||||
|
|
||||||
memcpy(pod->data, chars, size * sizeof(char32_t));
|
memcpy(pod->data, chars, size * sizeof(char32_t));
|
||||||
pod->size = size;
|
pod->size = size;
|
||||||
|
@ -304,7 +299,6 @@ class ByteArray : public Object {
|
||||||
static Result<ByteArray> create(const char* str) {
|
static Result<ByteArray> create(const char* str) {
|
||||||
uint64_t size = strlen(str);
|
uint64_t size = strlen(str);
|
||||||
auto pod = TRY(arena_alloc<PodByteArray>(size * sizeof(char32_t)));
|
auto pod = TRY(arena_alloc<PodByteArray>(size * sizeof(char32_t)));
|
||||||
pod->header.tag = Tag::ByteArray;
|
|
||||||
|
|
||||||
memcpy(pod->data, str, size);
|
memcpy(pod->data, str, size);
|
||||||
pod->size = size;
|
pod->size = size;
|
||||||
|
@ -331,7 +325,6 @@ class ByteArray : public Object {
|
||||||
uint64_t res_size = lhs_size + rhs_size;
|
uint64_t res_size = lhs_size + rhs_size;
|
||||||
|
|
||||||
auto pod = TRY(arena_alloc<PodByteArray>(res_size * sizeof(char)));
|
auto pod = TRY(arena_alloc<PodByteArray>(res_size * sizeof(char)));
|
||||||
pod->header.tag = Tag::ByteArray;
|
|
||||||
pod->size = res_size;
|
pod->size = res_size;
|
||||||
memcpy(pod->data, _value->data, sizeof(char) * lhs_size);
|
memcpy(pod->data, _value->data, sizeof(char) * lhs_size);
|
||||||
memcpy(pod->data, rhs + lhs_size, sizeof(char) * rhs_size);
|
memcpy(pod->data, rhs + lhs_size, sizeof(char) * rhs_size);
|
||||||
|
@ -344,10 +337,9 @@ class ByteArray : public Object {
|
||||||
uint64_t res_size = lhs_size + rhs_size;
|
uint64_t res_size = lhs_size + rhs_size;
|
||||||
|
|
||||||
auto pod = TRY(arena_alloc<PodByteArray>(res_size * sizeof(char)));
|
auto pod = TRY(arena_alloc<PodByteArray>(res_size * sizeof(char)));
|
||||||
pod->header.tag = Tag::ByteArray;
|
|
||||||
pod->size = res_size;
|
pod->size = res_size;
|
||||||
memcpy(pod->data, _value->data, sizeof(char) * lhs_size);
|
memcpy(pod->data, _value->data, sizeof(char) * lhs_size);
|
||||||
memcpy(pod->data, rhs + lhs_size, sizeof(char) * rhs_size);
|
memcpy(pod->data + lhs_size, rhs, sizeof(char) * rhs_size);
|
||||||
|
|
||||||
return ByteArray(TRY(MkGcRoot(pod)));
|
return ByteArray(TRY(MkGcRoot(pod)));
|
||||||
}
|
}
|
||||||
|
@ -358,7 +350,6 @@ class ByteArray : public Object {
|
||||||
uint64_t res_size = lhs_size + rhs_size;
|
uint64_t res_size = lhs_size + rhs_size;
|
||||||
|
|
||||||
auto pod = TRY(arena_alloc<PodByteArray>(res_size * sizeof(char)));
|
auto pod = TRY(arena_alloc<PodByteArray>(res_size * sizeof(char)));
|
||||||
pod->header.tag = Tag::ByteArray;
|
|
||||||
pod->size = res_size;
|
pod->size = res_size;
|
||||||
memcpy(pod->data, _value->data, sizeof(char) * lhs_size);
|
memcpy(pod->data, _value->data, sizeof(char) * lhs_size);
|
||||||
memcpy(pod->data + lhs_size, rhs._value->data, sizeof(char) * rhs_size);
|
memcpy(pod->data + lhs_size, rhs._value->data, sizeof(char) * rhs_size);
|
||||||
|
@ -370,13 +361,16 @@ class ByteArray : public Object {
|
||||||
if (start > end) return ERROR(IndexOutOfRange);
|
if (start > end) return ERROR(IndexOutOfRange);
|
||||||
uint64_t res_size = end - start;
|
uint64_t res_size = end - start;
|
||||||
auto pod = TRY(arena_alloc<PodByteArray>(res_size * sizeof(char)));
|
auto pod = TRY(arena_alloc<PodByteArray>(res_size * sizeof(char)));
|
||||||
pod->header.tag = Tag::ByteArray;
|
|
||||||
pod->size = res_size;
|
pod->size = res_size;
|
||||||
memcpy(pod->data, _value->data + start, sizeof(char) * res_size);
|
memcpy(pod->data, _value->data + start, sizeof(char) * res_size);
|
||||||
|
|
||||||
return ByteArray(TRY(MkGcRoot(pod)));
|
return ByteArray(TRY(MkGcRoot(pod)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<String> hex() const;
|
||||||
|
Result<ByteArray> to_rle() const;
|
||||||
|
Result<ByteArray> from_rle() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GcRoot<PodByteArray> _value;
|
GcRoot<PodByteArray> _value;
|
||||||
};
|
};
|
||||||
|
@ -410,7 +404,6 @@ class Dict : public Object {
|
||||||
|
|
||||||
static Result<Dict> create() {
|
static Result<Dict> create() {
|
||||||
auto pod = TRY(arena_alloc<PodDict>());
|
auto pod = TRY(arena_alloc<PodDict>());
|
||||||
pod->header.tag = Tag::Dict;
|
|
||||||
|
|
||||||
pod->size = 0;
|
pod->size = 0;
|
||||||
|
|
||||||
|
@ -476,7 +469,7 @@ class String : public Object {
|
||||||
uint64_t i = 0;
|
uint64_t i = 0;
|
||||||
uint64_t j = 0;
|
uint64_t j = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
if (i == lsize && j == lsize) return 0;
|
if (i == lsize && j == rsize) return 0;
|
||||||
|
|
||||||
short cmp = short(i == lsize) - short(j == rsize);
|
short cmp = short(i == lsize) - short(j == rsize);
|
||||||
if (cmp != 0) return cmp;
|
if (cmp != 0) return cmp;
|
||||||
|
@ -498,7 +491,6 @@ class String : public Object {
|
||||||
}
|
}
|
||||||
static Result<String> create(char32_t* chars, int64_t size) {
|
static Result<String> create(char32_t* chars, int64_t size) {
|
||||||
auto pod = TRY(arena_alloc<PodString>(size * sizeof(char32_t)));
|
auto pod = TRY(arena_alloc<PodString>(size * sizeof(char32_t)));
|
||||||
pod->header.tag = Tag::String;
|
|
||||||
|
|
||||||
memcpy(pod->data, chars, size * sizeof(char32_t));
|
memcpy(pod->data, chars, size * sizeof(char32_t));
|
||||||
pod->size = size;
|
pod->size = size;
|
||||||
|
@ -510,7 +502,6 @@ class String : public Object {
|
||||||
auto size = TRY(bytes.size());
|
auto size = TRY(bytes.size());
|
||||||
|
|
||||||
auto pod = TRY(arena_alloc<PodString>(size * sizeof(char32_t)));
|
auto pod = TRY(arena_alloc<PodString>(size * sizeof(char32_t)));
|
||||||
pod->header.tag = Tag::String;
|
|
||||||
|
|
||||||
for (uint64_t i = 0; i < size; i++) pod->data[i] = TRY(bytes[i]);
|
for (uint64_t i = 0; i < size; i++) pod->data[i] = TRY(bytes[i]);
|
||||||
pod->size = size;
|
pod->size = size;
|
||||||
|
@ -523,7 +514,6 @@ class String : public Object {
|
||||||
static Result<String> create(const char* str) {
|
static Result<String> create(const char* str) {
|
||||||
uint64_t size = strlen(str);
|
uint64_t size = strlen(str);
|
||||||
auto pod = TRY(arena_alloc<PodString>(size * sizeof(char32_t)));
|
auto pod = TRY(arena_alloc<PodString>(size * sizeof(char32_t)));
|
||||||
pod->header.tag = Tag::String;
|
|
||||||
|
|
||||||
for (uint64_t i = 0; i < size; i++) pod->data[i] = str[i];
|
for (uint64_t i = 0; i < size; i++) pod->data[i] = str[i];
|
||||||
pod->size = size;
|
pod->size = size;
|
||||||
|
@ -548,7 +538,6 @@ class String : public Object {
|
||||||
uint64_t res_size = lhs_size + rhs_size;
|
uint64_t res_size = lhs_size + rhs_size;
|
||||||
|
|
||||||
auto pod = TRY(arena_alloc<PodString>(res_size * sizeof(char32_t)));
|
auto pod = TRY(arena_alloc<PodString>(res_size * sizeof(char32_t)));
|
||||||
pod->header.tag = Tag::String;
|
|
||||||
pod->size = res_size;
|
pod->size = res_size;
|
||||||
memcpy(pod->data, _value->data, sizeof(char32_t) * lhs_size);
|
memcpy(pod->data, _value->data, sizeof(char32_t) * lhs_size);
|
||||||
for (uint64_t i = 0; i < rhs_size; i++) pod->data[lhs_size + i] = rhs[i];
|
for (uint64_t i = 0; i < rhs_size; i++) pod->data[lhs_size + i] = rhs[i];
|
||||||
|
@ -563,7 +552,6 @@ class String : public Object {
|
||||||
uint64_t res_size = lhs_size + rhs_size;
|
uint64_t res_size = lhs_size + rhs_size;
|
||||||
|
|
||||||
auto pod = TRY(arena_alloc<PodString>(res_size * sizeof(char32_t)));
|
auto pod = TRY(arena_alloc<PodString>(res_size * sizeof(char32_t)));
|
||||||
pod->header.tag = Tag::String;
|
|
||||||
pod->size = res_size;
|
pod->size = res_size;
|
||||||
memcpy(pod->data, _value->data, sizeof(char32_t) * lhs_size);
|
memcpy(pod->data, _value->data, sizeof(char32_t) * lhs_size);
|
||||||
for (uint64_t i = 0; i < rhs_size; i++) pod->data[lhs_size + i] = rhs[i];
|
for (uint64_t i = 0; i < rhs_size; i++) pod->data[lhs_size + i] = rhs[i];
|
||||||
|
@ -577,7 +565,6 @@ class String : public Object {
|
||||||
uint64_t res_size = lhs_size + rhs_size;
|
uint64_t res_size = lhs_size + rhs_size;
|
||||||
|
|
||||||
auto pod = TRY(arena_alloc<PodString>(res_size * sizeof(char32_t)));
|
auto pod = TRY(arena_alloc<PodString>(res_size * sizeof(char32_t)));
|
||||||
pod->header.tag = Tag::String;
|
|
||||||
pod->size = res_size;
|
pod->size = res_size;
|
||||||
memcpy(pod->data, _value->data, sizeof(char32_t) * lhs_size);
|
memcpy(pod->data, _value->data, sizeof(char32_t) * lhs_size);
|
||||||
memcpy(pod->data + lhs_size, rhs._value->data, sizeof(char32_t) * rhs_size);
|
memcpy(pod->data + lhs_size, rhs._value->data, sizeof(char32_t) * rhs_size);
|
||||||
|
@ -589,7 +576,6 @@ class String : public Object {
|
||||||
if (start > end) return ERROR(IndexOutOfRange);
|
if (start > end) return ERROR(IndexOutOfRange);
|
||||||
uint64_t res_size = end - start;
|
uint64_t res_size = end - start;
|
||||||
auto pod = TRY(arena_alloc<PodString>(res_size * sizeof(char32_t)));
|
auto pod = TRY(arena_alloc<PodString>(res_size * sizeof(char32_t)));
|
||||||
pod->header.tag = Tag::String;
|
|
||||||
pod->size = res_size;
|
pod->size = res_size;
|
||||||
memcpy(pod->data, _value->data + start, sizeof(char32_t) * res_size);
|
memcpy(pod->data, _value->data + start, sizeof(char32_t) * res_size);
|
||||||
|
|
||||||
|
@ -620,7 +606,7 @@ class Symbol : public Object {
|
||||||
uint64_t i = 0;
|
uint64_t i = 0;
|
||||||
uint64_t j = 0;
|
uint64_t j = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
if (i == lsize && j == lsize) return 0;
|
if (i == lsize && j == rsize) return 0;
|
||||||
|
|
||||||
short cmp = short(i == lsize) - short(j == rsize);
|
short cmp = short(i == lsize) - short(j == rsize);
|
||||||
if (cmp != 0) return cmp;
|
if (cmp != 0) return cmp;
|
||||||
|
@ -662,7 +648,6 @@ class Symbol : public Object {
|
||||||
|
|
||||||
static Result<Symbol> create(char32_t* chars, int64_t size) {
|
static Result<Symbol> create(char32_t* chars, int64_t size) {
|
||||||
auto pod = TRY(arena_alloc<PodSymbol>(size * sizeof(char32_t)));
|
auto pod = TRY(arena_alloc<PodSymbol>(size * sizeof(char32_t)));
|
||||||
pod->header.tag = Tag::Symbol;
|
|
||||||
|
|
||||||
memcpy(pod->data, chars, size * sizeof(char32_t));
|
memcpy(pod->data, chars, size * sizeof(char32_t));
|
||||||
|
|
||||||
|
@ -672,7 +657,6 @@ class Symbol : public Object {
|
||||||
static Result<Symbol> create(const char* str) {
|
static Result<Symbol> create(const char* str) {
|
||||||
uint64_t size = strlen(str);
|
uint64_t size = strlen(str);
|
||||||
auto pod = TRY(arena_alloc<PodSymbol>(size * sizeof(char32_t)));
|
auto pod = TRY(arena_alloc<PodSymbol>(size * sizeof(char32_t)));
|
||||||
pod->header.tag = Tag::Symbol;
|
|
||||||
|
|
||||||
for (uint64_t i = 0; i < size; i++) pod->data[i] = str[i];
|
for (uint64_t i = 0; i < size; i++) pod->data[i] = str[i];
|
||||||
pod->size = size;
|
pod->size = size;
|
||||||
|
@ -717,7 +701,6 @@ class SrcLoc : public Object {
|
||||||
static Result<SrcLoc> create(const SourcePosition& start,
|
static Result<SrcLoc> create(const SourcePosition& start,
|
||||||
const SourcePosition& end) {
|
const SourcePosition& end) {
|
||||||
auto pod = TRY(arena_alloc<PodSrcLoc>());
|
auto pod = TRY(arena_alloc<PodSrcLoc>());
|
||||||
pod->header.tag = Tag::SrcLoc;
|
|
||||||
|
|
||||||
pod->sourcerange.start = start;
|
pod->sourcerange.start = start;
|
||||||
pod->sourcerange.end = end;
|
pod->sourcerange.end = end;
|
||||||
|
@ -849,9 +832,8 @@ class Int64 : public Object {
|
||||||
return Int64(TRY(MkGcRoot(obj)));
|
return Int64(TRY(MkGcRoot(obj)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result<Int64> create(double val) {
|
static Result<Int64> create(int64_t val) {
|
||||||
auto pod = TRY(arena_alloc<PodInt64>());
|
auto pod = TRY(arena_alloc<PodInt64>());
|
||||||
pod->header.tag = Tag::Int64;
|
|
||||||
pod->value = val;
|
pod->value = val;
|
||||||
|
|
||||||
return Int64(TRY(MkGcRoot(pod)));
|
return Int64(TRY(MkGcRoot(pod)));
|
||||||
|
@ -908,7 +890,6 @@ class Float : public Object {
|
||||||
|
|
||||||
static Result<Float> create(double val) {
|
static Result<Float> create(double val) {
|
||||||
auto pod = TRY(arena_alloc<PodFloat>());
|
auto pod = TRY(arena_alloc<PodFloat>());
|
||||||
pod->header.tag = Tag::Float;
|
|
||||||
pod->value = val;
|
pod->value = val;
|
||||||
|
|
||||||
return Float(TRY(MkGcRoot(pod)));
|
return Float(TRY(MkGcRoot(pod)));
|
||||||
|
@ -945,7 +926,6 @@ class Bool : public Object {
|
||||||
|
|
||||||
static Result<Bool> create(bool val) {
|
static Result<Bool> create(bool val) {
|
||||||
auto pod = TRY(arena_alloc<PodBool>());
|
auto pod = TRY(arena_alloc<PodBool>());
|
||||||
pod->header.tag = Tag::Bool;
|
|
||||||
pod->value = val;
|
pod->value = val;
|
||||||
|
|
||||||
return Bool(TRY(MkGcRoot(pod)));
|
return Bool(TRY(MkGcRoot(pod)));
|
||||||
|
@ -983,7 +963,6 @@ class Opcode : public Object {
|
||||||
OpArg arg2 = {0, 0}, OpArg arg3 = {0, 0},
|
OpArg arg2 = {0, 0}, OpArg arg3 = {0, 0},
|
||||||
OpArg arg4 = {0, 0}) {
|
OpArg arg4 = {0, 0}) {
|
||||||
auto pod = TRY(arena_alloc<PodOpcode>());
|
auto pod = TRY(arena_alloc<PodOpcode>());
|
||||||
pod->header.tag = Tag::Opcode;
|
|
||||||
pod->opcode = opcode;
|
pod->opcode = opcode;
|
||||||
pod->arg1 = arg1;
|
pod->arg1 = arg1;
|
||||||
pod->arg2 = arg2;
|
pod->arg2 = arg2;
|
||||||
|
@ -1164,13 +1143,13 @@ class StackFrame : public Object {
|
||||||
Result<StackFrame> incpc();
|
Result<StackFrame> incpc();
|
||||||
Result<uint64_t> size() const { return _value->size; }
|
Result<uint64_t> size() const { return _value->size; }
|
||||||
|
|
||||||
static Result<StackFrame> create(const Value& parent, const Value& fun);
|
static Result<StackFrame> create(const Value& parent, const Value& fun,
|
||||||
|
bool guard = false);
|
||||||
|
|
||||||
Result<Array> slice(uint64_t start, uint64_t end) const {
|
Result<Array> slice(uint64_t start, uint64_t end) const {
|
||||||
if (start > end || end > _value->size) return ERROR(IndexOutOfRange);
|
if (start > end || end > _value->size) return ERROR(IndexOutOfRange);
|
||||||
uint64_t res_size = end - start;
|
uint64_t res_size = end - start;
|
||||||
auto pod = TRY(arena_alloc<PodArray>(res_size * sizeof(PodObject*)));
|
auto pod = TRY(arena_alloc<PodArray>(res_size * sizeof(PodObject*)));
|
||||||
pod->header.tag = Tag::Array;
|
|
||||||
pod->size = res_size;
|
pod->size = res_size;
|
||||||
for (uint64_t i = 0; i < end - start; i++) {
|
for (uint64_t i = 0; i < end - start; i++) {
|
||||||
pod->data[i] = _value->data[start + i];
|
pod->data[i] = _value->data[start + i];
|
||||||
|
@ -1182,9 +1161,16 @@ class StackFrame : public Object {
|
||||||
Result<StackFrame> call(const Value& fun, uint64_t start, uint64_t end) const;
|
Result<StackFrame> call(const Value& fun, uint64_t start, uint64_t end) const;
|
||||||
Result<StackFrame> ret(uint64_t regno) const;
|
Result<StackFrame> ret(uint64_t regno) const;
|
||||||
|
|
||||||
|
Result<StackFrame> detach(uint64_t depth) const;
|
||||||
|
Result<StackFrame> attach(const StackFrame& frame) const;
|
||||||
|
|
||||||
|
Result<StackFrame> set_guard(bool guard = true) const;
|
||||||
|
|
||||||
virtual Result<Value> copy_value() const final;
|
virtual Result<Value> copy_value() const final;
|
||||||
Result<StackFrame> copy() const;
|
Result<StackFrame> copy() const;
|
||||||
|
|
||||||
|
bool guard() const { return _value->guard; }
|
||||||
|
|
||||||
Result<String> backtrace(uint64_t indent = 0) const;
|
Result<String> backtrace(uint64_t indent = 0) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1215,7 +1201,6 @@ class Error : public Object {
|
||||||
auto message_str = TRY(String::create(message));
|
auto message_str = TRY(String::create(message));
|
||||||
|
|
||||||
auto pod = TRY(arena_alloc<PodError>());
|
auto pod = TRY(arena_alloc<PodError>());
|
||||||
pod->header.tag = Tag::Error;
|
|
||||||
|
|
||||||
pod->name = name_str.pod();
|
pod->name = name_str.pod();
|
||||||
pod->message = message_str.pod();
|
pod->message = message_str.pod();
|
||||||
|
@ -1225,7 +1210,6 @@ class Error : public Object {
|
||||||
|
|
||||||
static Result<Error> create(const Symbol& name, const String& message) {
|
static Result<Error> create(const Symbol& name, const String& message) {
|
||||||
auto pod = TRY(arena_alloc<PodError>());
|
auto pod = TRY(arena_alloc<PodError>());
|
||||||
pod->header.tag = Tag::Error;
|
|
||||||
|
|
||||||
pod->name = name.pod();
|
pod->name = name.pod();
|
||||||
pod->message = message.pod();
|
pod->message = message.pod();
|
||||||
|
|
|
@ -19,9 +19,58 @@ void reseterrobj() { errobj = Value(); }
|
||||||
|
|
||||||
const char* errname(ErrorCode errcode) {
|
const char* errname(ErrorCode errcode) {
|
||||||
switch (errcode) {
|
switch (errcode) {
|
||||||
|
case ErrorCode::Success:
|
||||||
|
return "success";
|
||||||
|
case ErrorCode::Unknown:
|
||||||
|
return "unknown";
|
||||||
|
case ErrorCode::OutOfMemory:
|
||||||
|
return "out-of-memory";
|
||||||
|
case ErrorCode::IndexOutOfRange:
|
||||||
|
return "index-out-of-range";
|
||||||
|
case ErrorCode::TypeMismatch:
|
||||||
|
return "type-mismatch";
|
||||||
|
case ErrorCode::ReadError:
|
||||||
|
return "read-error";
|
||||||
|
case ErrorCode::UnterminatedStringLiteral:
|
||||||
|
return "unterminalted-string-literal";
|
||||||
|
case ErrorCode::InvalidNumericLiteral:
|
||||||
|
return "invalid-numeric-literal";
|
||||||
|
case ErrorCode::NotImplemented:
|
||||||
|
return "not-implemented";
|
||||||
|
case ErrorCode::InvalidSymbol:
|
||||||
|
return "invalid-symbol";
|
||||||
|
case ErrorCode::MalformedList:
|
||||||
|
return "malformed-list";
|
||||||
|
case ErrorCode::KeyError:
|
||||||
|
return "key-error";
|
||||||
|
case ErrorCode::EndOfProgram:
|
||||||
|
return "end-of-program";
|
||||||
|
case ErrorCode::CompilationError:
|
||||||
|
return "compilation-error";
|
||||||
|
case ErrorCode::ArgumentCountMismatch:
|
||||||
|
return "argument-count-mismatch";
|
||||||
|
case ErrorCode::IOError:
|
||||||
|
return "io-error";
|
||||||
|
case ErrorCode::Interrupt:
|
||||||
|
return "interrupt";
|
||||||
|
case ErrorCode::AssertionFailed:
|
||||||
|
return "assertion-failed";
|
||||||
|
case ErrorCode::DivisionByZero:
|
||||||
|
return "division-by-zero";
|
||||||
case ErrorCode::SyntaxError:
|
case ErrorCode::SyntaxError:
|
||||||
return "syntax-error";
|
return "syntax-error";
|
||||||
default:
|
case ErrorCode::RuntimeError:
|
||||||
return "unknown";
|
return "runtime-error";
|
||||||
|
case ErrorCode::Raise:
|
||||||
|
return "raise";
|
||||||
|
case ErrorCode::TaskFailed:
|
||||||
|
return "task-failed";
|
||||||
}
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<Value> wrap_error(ErrorCode code) {
|
||||||
|
auto name = errname(code);
|
||||||
|
auto message = geterr();
|
||||||
|
return Value(TRY(Error::create(name, message)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,8 @@ const Value& geterrobj(void);
|
||||||
Result<void> seterrobj(const Value&);
|
Result<void> seterrobj(const Value&);
|
||||||
void reseterrobj();
|
void reseterrobj();
|
||||||
|
|
||||||
|
Result<Value> wrap_error(ErrorCode code);
|
||||||
|
|
||||||
#define STRINGIZE_NESTED(A) #A
|
#define STRINGIZE_NESTED(A) #A
|
||||||
#define STRINGIZE(A) STRINGIZE_NESTED(A)
|
#define STRINGIZE(A) STRINGIZE_NESTED(A)
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ Result<ByteArray> read_file(const char* filename) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<ByteArray> read_file(const ByteArray& filename) {
|
Result<ByteArray> read_file(const ByteArray& filename) {
|
||||||
auto filename_bytes = TRY(filename.concat("\0"));
|
auto filename_bytes = TRY(filename.concat("\0", 1));
|
||||||
FILE* fh = fopen(filename_bytes.raw_bytes(), "r");
|
FILE* fh = fopen(filename_bytes.raw_bytes(), "r");
|
||||||
|
|
||||||
if (!fh) {
|
if (!fh) {
|
||||||
|
@ -78,7 +78,7 @@ Result<ByteArray> read_file(const ByteArray& filename) {
|
||||||
Result<ByteArray> read_stdin() { return read_fh(stdin); }
|
Result<ByteArray> read_stdin() { return read_fh(stdin); }
|
||||||
|
|
||||||
Result<void> write_file(const ByteArray& filename, const ByteArray& contents) {
|
Result<void> write_file(const ByteArray& filename, const ByteArray& contents) {
|
||||||
auto filename_bytes = TRY(filename.concat("\0"));
|
auto filename_bytes = TRY(filename.concat("\0", 1));
|
||||||
FILE* fh = fopen(filename_bytes.raw_bytes(), "w");
|
FILE* fh = fopen(filename_bytes.raw_bytes(), "w");
|
||||||
|
|
||||||
if (!fh) {
|
if (!fh) {
|
||||||
|
|
|
@ -201,6 +201,7 @@ class PodStackFrame final : public PodObject {
|
||||||
|
|
||||||
OffPtr<PodObject> parent;
|
OffPtr<PodObject> parent;
|
||||||
OffPtr<PodObject> fun;
|
OffPtr<PodObject> fun;
|
||||||
|
bool guard;
|
||||||
uint64_t pc;
|
uint64_t pc;
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
OffPtr<PodObject> data[];
|
OffPtr<PodObject> data[];
|
||||||
|
|
395
src/serialize.cpp
Normal file
395
src/serialize.cpp
Normal file
|
@ -0,0 +1,395 @@
|
||||||
|
#include "serialize.hpp"
|
||||||
|
|
||||||
|
#include "arena.hpp"
|
||||||
|
#include "common.hpp"
|
||||||
|
#include "pod.hpp"
|
||||||
|
|
||||||
|
class Serializer {
|
||||||
|
public:
|
||||||
|
Serializer(uint8_t* buf, bool dryrun)
|
||||||
|
: buf(buf), _offset(0), dryrun(dryrun) {}
|
||||||
|
|
||||||
|
PodObject* serialize_nil(PodNil* obj) {
|
||||||
|
PodNil* res = (PodNil*)(buf + _offset);
|
||||||
|
if (!dryrun) {
|
||||||
|
memcpy(res, obj, sizeof(PodNil));
|
||||||
|
}
|
||||||
|
|
||||||
|
_offset += round_up(sizeof(PodNil), 8);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
PodObject* serialize_bool(PodBool* obj) {
|
||||||
|
PodBool* res = (PodBool*)(buf + _offset);
|
||||||
|
if (!dryrun) {
|
||||||
|
memcpy(res, obj, sizeof(PodBool));
|
||||||
|
}
|
||||||
|
|
||||||
|
_offset += round_up(sizeof(PodBool), 8);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
PodObject* serialize_int64(PodInt64* obj) {
|
||||||
|
PodInt64* res = (PodInt64*)(buf + _offset);
|
||||||
|
if (!dryrun) {
|
||||||
|
memcpy(res, obj, sizeof(PodInt64));
|
||||||
|
}
|
||||||
|
|
||||||
|
_offset += sizeof(PodInt64);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
PodObject* serialize_float(PodFloat* obj) {
|
||||||
|
PodFloat* res = (PodFloat*)(buf + _offset);
|
||||||
|
if (!dryrun) {
|
||||||
|
memcpy(res, obj, sizeof(PodFloat));
|
||||||
|
}
|
||||||
|
|
||||||
|
_offset += round_up(sizeof(PodFloat), 8);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
PodObject* serialize_string(PodString* obj) {
|
||||||
|
PodString* res = (PodString*)(buf + _offset);
|
||||||
|
uint64_t size = sizeof(PodString) + sizeof(char32_t) * obj->size;
|
||||||
|
if (!dryrun) {
|
||||||
|
memcpy(res, obj, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
_offset += round_up(size, 8);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
PodObject* serialize_symbol(PodSymbol* obj) {
|
||||||
|
PodSymbol* res = (PodSymbol*)(buf + _offset);
|
||||||
|
uint64_t size = sizeof(PodSymbol) + sizeof(char32_t) * obj->size;
|
||||||
|
if (!dryrun) {
|
||||||
|
memcpy(res, obj, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
_offset += round_up(size, 8);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
PodObject* serialize_srcloc(PodSrcLoc* obj) {
|
||||||
|
PodSrcLoc* res = (PodSrcLoc*)(buf + _offset);
|
||||||
|
uint64_t size = sizeof(PodSrcLoc);
|
||||||
|
if (!dryrun) {
|
||||||
|
memcpy(res, obj, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
_offset += round_up(size, 8);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
PodObject* serialize_syntax(PodSyntax* obj) {
|
||||||
|
PodSyntax* res = (PodSyntax*)(buf + _offset);
|
||||||
|
uint64_t size = sizeof(PodSyntax);
|
||||||
|
_offset += round_up(size, 8);
|
||||||
|
|
||||||
|
auto filename = serialize_object(obj->filename.get());
|
||||||
|
auto srcloc = serialize_object(obj->srcloc.get());
|
||||||
|
auto expression = serialize_object(obj->expression.get());
|
||||||
|
if (!dryrun) {
|
||||||
|
res->header.tag = Tag::Syntax;
|
||||||
|
res->filename = filename;
|
||||||
|
res->srcloc = srcloc;
|
||||||
|
res->expression = expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
PodObject* serialize_pair(PodPair* obj) {
|
||||||
|
PodPair* res = (PodPair*)(buf + _offset);
|
||||||
|
uint64_t size = sizeof(PodPair);
|
||||||
|
_offset += round_up(size, 8);
|
||||||
|
|
||||||
|
auto first = serialize_object(obj->first.get());
|
||||||
|
auto rest = serialize_object(obj->rest.get());
|
||||||
|
if (!dryrun) {
|
||||||
|
res->header.tag = Tag::Pair;
|
||||||
|
res->first = first;
|
||||||
|
res->rest = rest;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
PodObject* serialize_array(PodArray* obj) {
|
||||||
|
PodArray* res = (PodArray*)(buf + _offset);
|
||||||
|
uint64_t size = sizeof(PodArray) + sizeof(OffPtr<PodObject>) * obj->size;
|
||||||
|
_offset += round_up(size, 8);
|
||||||
|
|
||||||
|
if (!dryrun) {
|
||||||
|
res->header.tag = Tag::Array;
|
||||||
|
res->size = obj->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i < obj->size; ++i) {
|
||||||
|
auto val = serialize_object(obj->data[i].get());
|
||||||
|
if (!dryrun) {
|
||||||
|
res->data[i] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
PodObject* serialize_bytearray(PodByteArray* obj) {
|
||||||
|
PodByteArray* res = (PodByteArray*)(buf + _offset);
|
||||||
|
uint64_t size = sizeof(PodArray) + obj->size;
|
||||||
|
_offset += round_up(size, 8);
|
||||||
|
|
||||||
|
if (!dryrun) {
|
||||||
|
res->header.tag = Tag::ByteArray;
|
||||||
|
memcpy(res, obj, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
PodObject* serialize_dict(PodDict* obj) {
|
||||||
|
PodDict* res = (PodDict*)(buf + _offset);
|
||||||
|
uint64_t size = sizeof(PodDict) + sizeof(OffPtr<PodObject>) * obj->size * 2;
|
||||||
|
_offset += round_up(size, 8);
|
||||||
|
|
||||||
|
if (!dryrun) {
|
||||||
|
res->header.tag = Tag::Dict;
|
||||||
|
res->size = obj->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i < obj->size * 2; ++i) {
|
||||||
|
auto val = serialize_object(obj->data[i].get());
|
||||||
|
if (!dryrun) {
|
||||||
|
res->data[i] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
PodObject* serialize_opcode(PodOpcode* obj) {
|
||||||
|
PodOpcode* res = (PodOpcode*)(buf + _offset);
|
||||||
|
uint64_t size = sizeof(PodOpcode);
|
||||||
|
_offset += round_up(size, 8);
|
||||||
|
|
||||||
|
if (!dryrun) {
|
||||||
|
memcpy(res, obj, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
PodObject* serialize_function(PodFunction* obj) {
|
||||||
|
PodFunction* res = (PodFunction*)(buf + _offset);
|
||||||
|
uint64_t size = sizeof(PodFunction);
|
||||||
|
_offset += round_up(size, 8);
|
||||||
|
|
||||||
|
auto closure = serialize_object(obj->closure.get());
|
||||||
|
auto code = serialize_object(obj->code.get());
|
||||||
|
auto constants = serialize_object(obj->constants.get());
|
||||||
|
auto name = serialize_object(obj->name.get());
|
||||||
|
|
||||||
|
if (!dryrun) {
|
||||||
|
res->header.tag = Tag::Function;
|
||||||
|
res->arity = obj->arity;
|
||||||
|
res->closure = closure;
|
||||||
|
res->code = code;
|
||||||
|
res->constants = constants;
|
||||||
|
res->name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
PodObject* serialize_stdlib_function(PodStdlibFunction* obj) {
|
||||||
|
PodStdlibFunction* res = (PodStdlibFunction*)(buf + _offset);
|
||||||
|
uint64_t size = sizeof(PodStdlibFunction);
|
||||||
|
_offset += round_up(size, 8);
|
||||||
|
|
||||||
|
if (!dryrun) {
|
||||||
|
memcpy(res, obj, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
PodObject* serialize_module(PodModule* obj) {
|
||||||
|
PodModule* res = (PodModule*)(buf + _offset);
|
||||||
|
uint64_t size = sizeof(PodModule);
|
||||||
|
_offset += round_up(size, 8);
|
||||||
|
|
||||||
|
auto fun = serialize_object(obj->fun.get());
|
||||||
|
auto name = serialize_object(obj->name.get());
|
||||||
|
|
||||||
|
if (!dryrun) {
|
||||||
|
res->header.tag = Tag::Module;
|
||||||
|
res->fun = fun;
|
||||||
|
res->name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
PodObject* serialize_stack(PodStackFrame* obj) {
|
||||||
|
PodStackFrame* res = (PodStackFrame*)(buf + _offset);
|
||||||
|
uint64_t size =
|
||||||
|
sizeof(PodStackFrame) + sizeof(OffPtr<PodObject>) * obj->size;
|
||||||
|
_offset += round_up(size, 8);
|
||||||
|
|
||||||
|
auto fun = serialize_object(obj->fun.get());
|
||||||
|
auto parent = serialize_object(obj->parent.get());
|
||||||
|
|
||||||
|
if (!dryrun) {
|
||||||
|
res->header.tag = Tag::StackFrame;
|
||||||
|
res->fun = fun;
|
||||||
|
res->parent = parent;
|
||||||
|
res->pc = obj->pc;
|
||||||
|
res->size = obj->size;
|
||||||
|
res->guard = obj->guard;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i < obj->size; i++) {
|
||||||
|
auto val = serialize_object(obj->data[i].get());
|
||||||
|
if (!dryrun) {
|
||||||
|
res->data[i] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
PodObject* serialize_error(PodError* obj) {
|
||||||
|
PodError* res = (PodError*)(buf + _offset);
|
||||||
|
uint64_t size = sizeof(PodError);
|
||||||
|
_offset += round_up(size, 8);
|
||||||
|
|
||||||
|
auto name = serialize_object(obj->name.get());
|
||||||
|
auto message = serialize_object(obj->message.get());
|
||||||
|
|
||||||
|
if (!dryrun) {
|
||||||
|
res->header.tag = Tag::Error;
|
||||||
|
res->name = name;
|
||||||
|
res->message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
PodObject* serialize_continuation(PodContinuation* obj) {
|
||||||
|
PodContinuation* res = (PodContinuation*)(buf + _offset);
|
||||||
|
uint64_t size = sizeof(PodContinuation);
|
||||||
|
_offset += round_up(size, 8);
|
||||||
|
|
||||||
|
auto frame = serialize_object(obj->frame.get());
|
||||||
|
auto value = serialize_object(obj->value.get());
|
||||||
|
|
||||||
|
if (!dryrun) {
|
||||||
|
res->header.tag = Tag::Continuation;
|
||||||
|
res->frame = frame;
|
||||||
|
res->value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
PodObject* serialize_task(PodTask* obj) {
|
||||||
|
PodTask* res = (PodTask*)(buf + _offset);
|
||||||
|
uint64_t size = sizeof(PodTask);
|
||||||
|
_offset += round_up(size, 8);
|
||||||
|
|
||||||
|
auto params = serialize_object(obj->params.get());
|
||||||
|
|
||||||
|
if (!dryrun) {
|
||||||
|
res->header.tag = Tag::Task;
|
||||||
|
res->task_id = obj->task_id;
|
||||||
|
res->params = params;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
PodObject* serialize_task_result(PodTaskResult* obj) {
|
||||||
|
PodTaskResult* res = (PodTaskResult*)(buf + _offset);
|
||||||
|
uint64_t size = sizeof(PodTaskResult);
|
||||||
|
_offset += round_up(size, 8);
|
||||||
|
|
||||||
|
auto result = serialize_object(obj->result.get());
|
||||||
|
auto error = serialize_object(obj->error.get());
|
||||||
|
|
||||||
|
if (!dryrun) {
|
||||||
|
res->header.tag = Tag::TaskResult;
|
||||||
|
res->result = result;
|
||||||
|
res->error = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
PodObject* serialize_object(PodObject* obj) {
|
||||||
|
switch (obj->header.tag) {
|
||||||
|
case Tag::Nil:
|
||||||
|
return serialize_nil((PodNil*)obj);
|
||||||
|
case Tag::Bool:
|
||||||
|
return serialize_bool((PodBool*)obj);
|
||||||
|
case Tag::Int64:
|
||||||
|
return serialize_int64((PodInt64*)obj);
|
||||||
|
case Tag::Float:
|
||||||
|
return serialize_float((PodFloat*)obj);
|
||||||
|
case Tag::String:
|
||||||
|
return serialize_string((PodString*)obj);
|
||||||
|
case Tag::Symbol:
|
||||||
|
return serialize_symbol((PodSymbol*)obj);
|
||||||
|
case Tag::SrcLoc:
|
||||||
|
return serialize_srcloc((PodSrcLoc*)obj);
|
||||||
|
case Tag::Syntax:
|
||||||
|
return serialize_syntax((PodSyntax*)obj);
|
||||||
|
case Tag::Pair:
|
||||||
|
return serialize_pair((PodPair*)obj);
|
||||||
|
case Tag::Array:
|
||||||
|
return serialize_array((PodArray*)obj);
|
||||||
|
case Tag::ByteArray:
|
||||||
|
return serialize_bytearray((PodByteArray*)obj);
|
||||||
|
case Tag::Dict:
|
||||||
|
return serialize_dict((PodDict*)obj);
|
||||||
|
case Tag::Opcode:
|
||||||
|
return serialize_opcode((PodOpcode*)obj);
|
||||||
|
case Tag::Function:
|
||||||
|
return serialize_function((PodFunction*)obj);
|
||||||
|
case Tag::StdlibFunction:
|
||||||
|
return serialize_stdlib_function((PodStdlibFunction*)obj);
|
||||||
|
case Tag::Module:
|
||||||
|
return serialize_module((PodModule*)obj);
|
||||||
|
case Tag::StackFrame:
|
||||||
|
return serialize_stack((PodStackFrame*)obj);
|
||||||
|
case Tag::Error:
|
||||||
|
return serialize_error((PodError*)obj);
|
||||||
|
case Tag::Continuation:
|
||||||
|
return serialize_continuation((PodContinuation*)obj);
|
||||||
|
case Tag::Task:
|
||||||
|
return serialize_task((PodTask*)obj);
|
||||||
|
case Tag::TaskResult:
|
||||||
|
return serialize_task_result((PodTaskResult*)obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Should never reach here
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t offset() { return _offset; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t* buf;
|
||||||
|
uint64_t _offset;
|
||||||
|
bool dryrun;
|
||||||
|
};
|
||||||
|
|
||||||
|
Result<ByteArray> serialize(const Value& val) {
|
||||||
|
Serializer s(0, true);
|
||||||
|
s.serialize_object(val.pod());
|
||||||
|
auto size = s.offset();
|
||||||
|
|
||||||
|
auto pod = TRY(arena_alloc<PodByteArray>(size * sizeof(char)));
|
||||||
|
|
||||||
|
pod->size = size;
|
||||||
|
Serializer ss((uint8_t*)pod->data, false);
|
||||||
|
ss.serialize_object(val.pod());
|
||||||
|
|
||||||
|
auto ba = ByteArray(TRY(MkGcRoot(pod)));
|
||||||
|
ba = TRY(ba.to_rle());
|
||||||
|
|
||||||
|
return ba;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<Value> deserialize(const ByteArray& val) {
|
||||||
|
auto decompressed = TRY(val.from_rle());
|
||||||
|
|
||||||
|
auto size = TRY(decompressed.size());
|
||||||
|
PodObject* obj = TRY(arena_alloc_bytes<PodObject>(size));
|
||||||
|
memcpy(obj, decompressed.raw_bytes(), size);
|
||||||
|
|
||||||
|
return TRY(Value::create(obj));
|
||||||
|
}
|
9
src/serialize.hpp
Normal file
9
src/serialize.hpp
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class Result;
|
||||||
|
class Value;
|
||||||
|
class ByteArray;
|
||||||
|
|
||||||
|
Result<ByteArray> serialize(const Value& val);
|
||||||
|
Result<Value> deserialize(const ByteArray& val);
|
103
src/stdlib.cpp
103
src/stdlib.cpp
|
@ -4,6 +4,7 @@
|
||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
#include "fio.hpp"
|
#include "fio.hpp"
|
||||||
#include "pod.hpp"
|
#include "pod.hpp"
|
||||||
|
#include "serialize.hpp"
|
||||||
#include "sourcerange.hpp"
|
#include "sourcerange.hpp"
|
||||||
#include "writer.hpp"
|
#include "writer.hpp"
|
||||||
|
|
||||||
|
@ -391,7 +392,7 @@ Result<StackFrame> stdlib_raise(const StackFrame& stack) {
|
||||||
auto stack_size = TRY(stack.size());
|
auto stack_size = TRY(stack.size());
|
||||||
|
|
||||||
if (stack_size > 1) {
|
if (stack_size > 1) {
|
||||||
return task_return(stack, 1);
|
return TRY(stack.ret(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto params = TRY(stack.get(0));
|
auto params = TRY(stack.get(0));
|
||||||
|
@ -434,6 +435,103 @@ Result<StackFrame> stdlib_task(const StackFrame& stack) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<StackFrame> stdlib_guard(const StackFrame& stack) {
|
||||||
|
auto stack_size = TRY(stack.size());
|
||||||
|
auto params = TRY(stack.get(0));
|
||||||
|
Array& params_array = *params.to<Array>();
|
||||||
|
|
||||||
|
auto size = TRY(params.size());
|
||||||
|
if (size != 2) return ERROR(ArgumentCountMismatch);
|
||||||
|
|
||||||
|
if (stack_size == 1) {
|
||||||
|
// This is the first entry to "guard", so need to establish
|
||||||
|
// context and call the guarded function
|
||||||
|
Value fun = TRY(params_array.get(0));
|
||||||
|
|
||||||
|
auto new_frame = TRY(stack.set_guard(true));
|
||||||
|
// Set stack[1] to "0", meaning that we've entered the guarded
|
||||||
|
// function
|
||||||
|
new_frame = TRY(new_frame.set(1, Value(TRY(Int64::create((int64_t)0)))));
|
||||||
|
new_frame = TRY(new_frame.set(2, fun));
|
||||||
|
|
||||||
|
return new_frame.call(fun, 2, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto state = TRY(stack.get(1));
|
||||||
|
if (!state.is<Int64>()) return ERROR(TypeMismatch);
|
||||||
|
auto state_int = state.to<Int64>()->value();
|
||||||
|
|
||||||
|
if (state_int == 0) {
|
||||||
|
// We've just normally returned from the guarded function. Just return
|
||||||
|
// its results back to the caller.
|
||||||
|
|
||||||
|
return stack.ret(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state_int == 1) {
|
||||||
|
// Exception has occured, and continuation is on the stack. We should
|
||||||
|
// now call the exception handler.
|
||||||
|
Value handler = TRY(params_array.get(1));
|
||||||
|
|
||||||
|
// Set stack[1] to "2", meaning that we've entered the guarded
|
||||||
|
// function
|
||||||
|
auto new_frame = TRY(stack.set(1, Value(TRY(Int64::create((int64_t)2)))));
|
||||||
|
auto cont = TRY(new_frame.get(2));
|
||||||
|
if (!cont.is<Continuation>()) return ERROR(TypeMismatch);
|
||||||
|
auto val = TRY(cont.to<Continuation>()->value());
|
||||||
|
new_frame = TRY(new_frame.set(2, handler));
|
||||||
|
new_frame = TRY(new_frame.set(3, val));
|
||||||
|
new_frame = TRY(new_frame.set(4, cont));
|
||||||
|
|
||||||
|
return new_frame.call(handler, 2, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state_int == 2) {
|
||||||
|
// We've returned from the exception handler. Propagate its result to
|
||||||
|
// the caller.
|
||||||
|
|
||||||
|
return stack.ret(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR(NotImplemented);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<StackFrame> stdlib_serialize(const StackFrame& stack) {
|
||||||
|
auto stack_size = TRY(stack.size());
|
||||||
|
auto params = TRY(stack.get(0));
|
||||||
|
Array& params_array = *params.to<Array>();
|
||||||
|
|
||||||
|
auto size = TRY(params.size());
|
||||||
|
if (size != 1) return ERROR(ArgumentCountMismatch);
|
||||||
|
|
||||||
|
auto val = TRY(params.get(0));
|
||||||
|
auto serialized = Value(TRY(serialize(val)));
|
||||||
|
|
||||||
|
auto res = TRY(stack.set(0, serialized));
|
||||||
|
|
||||||
|
res = TRY(res.ret(0));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<StackFrame> stdlib_deserialize(const StackFrame& stack) {
|
||||||
|
auto stack_size = TRY(stack.size());
|
||||||
|
auto params = TRY(stack.get(0));
|
||||||
|
Array& params_array = *params.to<Array>();
|
||||||
|
|
||||||
|
auto size = TRY(params.size());
|
||||||
|
if (size != 1) return ERROR(ArgumentCountMismatch);
|
||||||
|
|
||||||
|
auto val = TRY(params.get(0));
|
||||||
|
if (!val.is<ByteArray>()) return ERROR(TypeMismatch);
|
||||||
|
auto deserialized = TRY(deserialize(*val.to<ByteArray>()));
|
||||||
|
|
||||||
|
auto res = TRY(stack.set(0, deserialized));
|
||||||
|
|
||||||
|
res = TRY(res.ret(0));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
#define STDLIB_FUNCTION(name, id) \
|
#define STDLIB_FUNCTION(name, id) \
|
||||||
[(uint64_t)StdlibFunctionId::id] = {#name, StdlibFunctionId::id, \
|
[(uint64_t)StdlibFunctionId::id] = {#name, StdlibFunctionId::id, \
|
||||||
stdlib_##name}
|
stdlib_##name}
|
||||||
|
@ -457,6 +555,9 @@ static StdlibFunctionEntry function_entries[] = {
|
||||||
STDLIB_FUNCTION(error, Error),
|
STDLIB_FUNCTION(error, Error),
|
||||||
STDLIB_FUNCTION(raise, Raise),
|
STDLIB_FUNCTION(raise, Raise),
|
||||||
STDLIB_FUNCTION(task, Task),
|
STDLIB_FUNCTION(task, Task),
|
||||||
|
STDLIB_FUNCTION(guard, Guard),
|
||||||
|
STDLIB_FUNCTION(serialize, Serialize),
|
||||||
|
STDLIB_FUNCTION(deserialize, Deserialize),
|
||||||
[(uint64_t)StdlibFunctionId::Max] = {0, StdlibFunctionId::Max,
|
[(uint64_t)StdlibFunctionId::Max] = {0, StdlibFunctionId::Max,
|
||||||
stdlib_unknown},
|
stdlib_unknown},
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,6 +23,9 @@ enum class StdlibFunctionId : uint64_t {
|
||||||
Error,
|
Error,
|
||||||
Raise,
|
Raise,
|
||||||
Task,
|
Task,
|
||||||
|
Guard,
|
||||||
|
Serialize,
|
||||||
|
Deserialize,
|
||||||
Max,
|
Max,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,16 @@ Result<void> print_error(const Result<Value>& res, const String& backtrace) {
|
||||||
auto message = TRY(errobj.to<Error>()->message());
|
auto message = TRY(errobj.to<Error>()->message());
|
||||||
print_string(*message.to<String>());
|
print_string(*message.to<String>());
|
||||||
std::cout << "\n";
|
std::cout << "\n";
|
||||||
|
} else if (errobj.is<Continuation>()) {
|
||||||
|
auto val = TRY(errobj.to<Continuation>()->value());
|
||||||
|
if (val.is<Error>()) {
|
||||||
|
auto message = TRY(val.to<Error>()->message());
|
||||||
|
print_string(*message.to<String>());
|
||||||
|
std::cout << "\n";
|
||||||
|
} else {
|
||||||
|
std::cout << "Continuation: ";
|
||||||
|
debug_print(val);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
std::cout << "Uncaught error: ";
|
std::cout << "Uncaught error: ";
|
||||||
debug_print(errobj);
|
debug_print(errobj);
|
||||||
|
@ -61,6 +71,7 @@ Result<Value> run_string(const String& fname, const String& src) {
|
||||||
if (maybe_res.has_error()) {
|
if (maybe_res.has_error()) {
|
||||||
auto backtrace = TRY(vm.backtrace(2));
|
auto backtrace = TRY(vm.backtrace(2));
|
||||||
print_error(maybe_res, backtrace);
|
print_error(maybe_res, backtrace);
|
||||||
|
return maybe_res;
|
||||||
}
|
}
|
||||||
|
|
||||||
return maybe_res.release_value();
|
return maybe_res.release_value();
|
||||||
|
|
77
src/vm.cpp
77
src/vm.cpp
|
@ -124,6 +124,23 @@ Result<void> VM::vm_call_stdlib(Opcode& oc, StdlibFunction& fun) {
|
||||||
return Result<void>();
|
return Result<void>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<void> VM::vm_call_cont(Opcode& oc, Continuation& fun) {
|
||||||
|
uint64_t reg_start = (uint64_t)oc.arg1().arg;
|
||||||
|
uint64_t reg_end = (uint64_t)oc.arg2().arg;
|
||||||
|
|
||||||
|
if (reg_end - reg_start != 2) return ERROR(ArgumentCountMismatch);
|
||||||
|
|
||||||
|
auto param = TRY(_stack.get(reg_start + 1));
|
||||||
|
_stack = TRY(_stack.settop(reg_start));
|
||||||
|
|
||||||
|
auto cont_stack = TRY(fun.frame());
|
||||||
|
_stack = TRY(_stack.incpc());
|
||||||
|
_stack = TRY(cont_stack.attach(_stack));
|
||||||
|
_stack = TRY(_stack.set(TRY(_stack.size()), param));
|
||||||
|
|
||||||
|
return Result<void>();
|
||||||
|
}
|
||||||
|
|
||||||
Result<void> VM::vm_call(Opcode& oc) {
|
Result<void> VM::vm_call(Opcode& oc) {
|
||||||
Value fun_value = TRY(get(oc.arg1().is_const, oc.arg1().arg));
|
Value fun_value = TRY(get(oc.arg1().is_const, oc.arg1().arg));
|
||||||
if (fun_value.is<Function>()) {
|
if (fun_value.is<Function>()) {
|
||||||
|
@ -136,6 +153,11 @@ Result<void> VM::vm_call(Opcode& oc) {
|
||||||
return vm_call_stdlib(oc, fun);
|
return vm_call_stdlib(oc, fun);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fun_value.is<Continuation>()) {
|
||||||
|
Continuation& fun = *fun_value.to<Continuation>();
|
||||||
|
return vm_call_cont(oc, fun);
|
||||||
|
}
|
||||||
|
|
||||||
return ERROR(TypeMismatch);
|
return ERROR(TypeMismatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,18 +302,58 @@ Result<void> VM::step_bytecode() {
|
||||||
return Result<void>();
|
return Result<void>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<Value> VM::unwind(const Continuation& cont) {
|
||||||
|
StackFrame cur = TRY(cont.frame());
|
||||||
|
|
||||||
|
uint64_t depth = 0;
|
||||||
|
while (true) {
|
||||||
|
if (cur.guard()) {
|
||||||
|
auto state = TRY(cur.get(1));
|
||||||
|
if (!state.is<Int64>()) return ERROR(TypeMismatch);
|
||||||
|
auto state_int = state.to<Int64>()->value();
|
||||||
|
|
||||||
|
if (state_int <= 1) {
|
||||||
|
auto val = TRY(cont.value());
|
||||||
|
auto cont_stack = TRY(cont.frame());
|
||||||
|
cont_stack = TRY(cont_stack.detach(depth - 1));
|
||||||
|
|
||||||
|
auto new_cont = TRY(Continuation::create(val, cont_stack));
|
||||||
|
|
||||||
|
cur = TRY(cur.set(1, Value(TRY(Int64::create((int64_t)1)))));
|
||||||
|
cur = TRY(cur.set(2, Value(std::move(new_cont))));
|
||||||
|
return Value(std::move(cur));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto parent = TRY(cur.parent());
|
||||||
|
if (parent.is<Nil>()) break;
|
||||||
|
|
||||||
|
cur = TRY(parent.to<StackFrame>()->copy());
|
||||||
|
++depth;
|
||||||
|
}
|
||||||
|
return Value(TRY(Nil::create()));
|
||||||
|
}
|
||||||
|
|
||||||
Result<StackFrame> VM::handle_raise(const Continuation& cont) {
|
Result<StackFrame> VM::handle_raise(const Continuation& cont) {
|
||||||
// TODO: this should do proper stack unwinding
|
// TODO: this should do proper stack unwinding
|
||||||
|
|
||||||
|
auto unwind_res = TRY(unwind(cont));
|
||||||
|
|
||||||
|
if (!unwind_res.is<Nil>()) {
|
||||||
|
auto new_stack = TRY(unwind_res.to<StackFrame>()->copy());
|
||||||
|
return new_stack;
|
||||||
|
}
|
||||||
|
|
||||||
auto value = TRY(cont.value());
|
auto value = TRY(cont.value());
|
||||||
|
|
||||||
if (value.is<Error>()) {
|
if (!value.is<Task>()) {
|
||||||
auto obj = TRY(cont.copy_value());
|
auto obj = TRY(cont.copy_value());
|
||||||
return ERROR_OBJ(Raise, obj);
|
return ERROR_OBJ(Raise, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value tr;
|
|
||||||
|
|
||||||
if (value.is<Task>()) {
|
if (value.is<Task>()) {
|
||||||
|
Value tr;
|
||||||
|
|
||||||
auto task_id = value.to<Task>()->task_id();
|
auto task_id = value.to<Task>()->task_id();
|
||||||
auto params = TRY(value.to<Task>()->params());
|
auto params = TRY(value.to<Task>()->params());
|
||||||
|
|
||||||
|
@ -301,7 +363,7 @@ Result<StackFrame> VM::handle_raise(const Continuation& cont) {
|
||||||
const auto& err = geterrobj();
|
const auto& err = geterrobj();
|
||||||
Value errobj;
|
Value errobj;
|
||||||
if (err.is<Nil>()) {
|
if (err.is<Nil>()) {
|
||||||
errobj = Value(TRY(Error::create("unknown-error", "Unknown error")));
|
errobj = TRY(wrap_error(res.error()));
|
||||||
} else {
|
} else {
|
||||||
errobj = TRY(err.copy());
|
errobj = TRY(err.copy());
|
||||||
}
|
}
|
||||||
|
@ -317,6 +379,7 @@ Result<StackFrame> VM::handle_raise(const Continuation& cont) {
|
||||||
auto new_frame = frame.set(TRY(frame.size()), tr);
|
auto new_frame = frame.set(TRY(frame.size()), tr);
|
||||||
return new_frame;
|
return new_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ERROR(TypeMismatch);
|
return ERROR(TypeMismatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,8 +404,12 @@ Result<void> VM::step() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res.has_error()) {
|
if (res.has_error()) {
|
||||||
|
if (res.error() == ErrorCode::EndOfProgram) return res;
|
||||||
|
|
||||||
auto obj = TRY(geterrobj().copy());
|
auto obj = TRY(geterrobj().copy());
|
||||||
if (obj.is<Nil>()) return res;
|
if (obj.is<Nil>()) {
|
||||||
|
obj = TRY(wrap_error(res.error()));
|
||||||
|
}
|
||||||
|
|
||||||
if (res.error() == ErrorCode::Raise) {
|
if (res.error() == ErrorCode::Raise) {
|
||||||
if (obj.is<Continuation>()) {
|
if (obj.is<Continuation>()) {
|
||||||
|
|
|
@ -49,6 +49,7 @@ class VM {
|
||||||
Result<void> vm_selfcall(Opcode& oc);
|
Result<void> vm_selfcall(Opcode& oc);
|
||||||
Result<void> vm_call_lisp(Opcode& oc, Function& fun);
|
Result<void> vm_call_lisp(Opcode& oc, Function& fun);
|
||||||
Result<void> vm_call_stdlib(Opcode& oc, StdlibFunction& fun);
|
Result<void> vm_call_stdlib(Opcode& oc, StdlibFunction& fun);
|
||||||
|
Result<void> vm_call_cont(Opcode& oc, Continuation& fun);
|
||||||
Result<void> vm_ret(Opcode& oc);
|
Result<void> vm_ret(Opcode& oc);
|
||||||
|
|
||||||
Result<void> vm_equal(Opcode& oc);
|
Result<void> vm_equal(Opcode& oc);
|
||||||
|
@ -62,6 +63,7 @@ class VM {
|
||||||
Result<void> vm_global_load(Opcode& oc);
|
Result<void> vm_global_load(Opcode& oc);
|
||||||
Result<void> vm_global_store(Opcode& oc);
|
Result<void> vm_global_store(Opcode& oc);
|
||||||
|
|
||||||
|
Result<Value> unwind(const Continuation& cont);
|
||||||
Result<StackFrame> handle_raise(const Continuation& cont);
|
Result<StackFrame> handle_raise(const Continuation& cont);
|
||||||
|
|
||||||
Result<Value> get(bool is_const, uint64_t idx);
|
Result<Value> get(bool is_const, uint64_t idx);
|
||||||
|
|
|
@ -122,7 +122,12 @@ Result<String> Writer::write_bool(const Bool& val) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<String> Writer::write_bytearray(const ByteArray& val) {
|
Result<String> Writer::write_bytearray(const ByteArray& val) {
|
||||||
return ERROR(NotImplemented);
|
String res = TRY(String::create("#<bytearray "));
|
||||||
|
|
||||||
|
res = TRY(res.concat(TRY(val.hex())));
|
||||||
|
res = TRY(res.concat(">"));
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<String> Writer::write_string(const String& val) {
|
Result<String> Writer::write_string(const String& val) {
|
||||||
|
@ -427,11 +432,11 @@ Result<String> Writer::write_task_result(const TaskResult& val) {
|
||||||
String res = TRY(String::create("#<task-result "));
|
String res = TRY(String::create("#<task-result "));
|
||||||
|
|
||||||
if (error.is<Nil>()) {
|
if (error.is<Nil>()) {
|
||||||
res = TRY(res.concat(" :result "));
|
res = TRY(res.concat(":result "));
|
||||||
String s = TRY(write_one(result));
|
String s = TRY(write_one(result));
|
||||||
res = TRY(res.concat(s));
|
res = TRY(res.concat(s));
|
||||||
} else {
|
} else {
|
||||||
res = TRY(res.concat(" :error "));
|
res = TRY(res.concat(":error "));
|
||||||
String s = TRY(write_one(error));
|
String s = TRY(write_one(error));
|
||||||
res = TRY(res.concat(s));
|
res = TRY(res.concat(s));
|
||||||
}
|
}
|
||||||
|
|
4
test/continuations.vli
Normal file
4
test/continuations.vli
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
(assert (= ((guard (fn () (+ 1 (raise 2)))
|
||||||
|
(fn (e x) x))
|
||||||
|
2)
|
||||||
|
3))
|
2
test/serialize.vli
Normal file
2
test/serialize.vli
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
(assert (= (deserialize (serialize ["foo" "bar" 1]))
|
||||||
|
["foo" "bar" 1]))
|
Loading…
Reference in a new issue