#include "common.hpp" #include "arena.hpp" #include "error.hpp" #include "pod.hpp" #include "sourcerange.hpp" #include "stdlib.hpp" #include "utf8.hpp" #include "writer.hpp" Result Value::create(GcRootBase&& obj) { switch (obj->header.tag) { case Tag::Nil: return Value(Nil(std::move(obj).move_as())); case Tag::Int64: return Value(Int64(std::move(obj).move_as())); case Tag::Float: return Value(Float(std::move(obj).move_as())); case Tag::Bool: return Value(Bool(std::move(obj).move_as())); case Tag::Array: return Value(Array(std::move(obj).move_as())); case Tag::ByteArray: return Value(ByteArray(std::move(obj).move_as())); case Tag::Dict: return Value(Dict(std::move(obj).move_as())); case Tag::String: return Value(String(std::move(obj).move_as())); case Tag::Symbol: return Value(Symbol(std::move(obj).move_as())); case Tag::SrcLoc: return Value(SrcLoc(std::move(obj).move_as())); case Tag::Syntax: return Value(Syntax(std::move(obj).move_as())); case Tag::Pair: return Value(Pair(std::move(obj).move_as())); case Tag::Opcode: return Value(Opcode(std::move(obj).move_as())); case Tag::Function: return Value(Function(std::move(obj).move_as())); case Tag::StdlibFunction: return Value(StdlibFunction(std::move(obj).move_as())); case Tag::Module: return Value(Module(std::move(obj).move_as())); case Tag::StackFrame: return Value(StackFrame(std::move(obj).move_as())); case Tag::Error: return Value(Error(std::move(obj).move_as())); case Tag::Continuation: return Value(Continuation(std::move(obj).move_as())); case Tag::Task: return Value(Task(std::move(obj).move_as())); case Tag::TaskResult: return Value(TaskResult(std::move(obj).move_as())); }; return Value(); } Result Symbol::create(String& rhs) { uint64_t rhs_size = TRY(rhs.size()); uint64_t res_size = rhs_size; auto pod = TRY(arena_alloc(res_size * sizeof(char32_t))); pod->size = res_size; memcpy(pod->data, rhs._value->data, sizeof(char32_t) * rhs_size); return Symbol(std::move(pod)); } Result String::create(const Symbol& rhs) { uint64_t rhs_size = TRY(rhs.size()); uint64_t res_size = rhs_size; auto pod = TRY(arena_alloc(res_size * sizeof(char32_t))); pod->size = res_size; memcpy(pod->data, rhs._value->data, sizeof(char32_t) * rhs_size); return String(std::move(pod)); } Result ByteArray::create(const String& str) { uint64_t size = 0; auto strsize = TRY(str.size()); for (uint64_t i = 0; i < strsize; i++) { size += utf8_codepoint_size(TRY(str[i])); } auto pod = TRY(arena_alloc(size * sizeof(char))); pod->size = size; char* res = pod->data; for (uint64_t i = 0; i < strsize; i++) { char32_t codepoint = TRY(str[i]); size = utf8_codepoint_size(codepoint); res = utf8_write_codepoint(res, codepoint); } return ByteArray(std::move(pod)); } Result ByteArray::hex() const { auto size = _value->size * 2; auto pod = TRY(arena_alloc(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(std::move(pod)); } Result 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(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(std::move(pod)); } Result 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(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(std::move(pod)); } Result SrcLoc::create(const SourceRange& sourcerange) { auto pod = TRY(arena_alloc()); pod->sourcerange = sourcerange; return SrcLoc(std::move(pod)); } short sourceposition_cmp(const SourcePosition& lhs, const SourcePosition& rhs) { short res = (lhs.line > rhs.line) - (lhs.line < rhs.line); if (res != 0) return res; res = (lhs.column > rhs.column) - (lhs.column < rhs.column); if (res != 0) return res; return (lhs.offset > rhs.offset) - (lhs.offset < rhs.offset); } short sourcerange_cmp(const SourceRange& lhs, const SourceRange rhs) { short res = sourceposition_cmp(lhs.start, rhs.start); if (res != 0) return res; return sourceposition_cmp(lhs.end, rhs.end); } SourceRange SrcLoc::sourcerange() const { return _value->sourcerange; } Result SrcLoc::cmp(const SrcLoc& rhs) const { auto lhs_sourcerange = sourcerange(); auto rhs_sourcerange = rhs.sourcerange(); return sourcerange_cmp(lhs_sourcerange, rhs_sourcerange); } Result Syntax::create(const String& filename, const SrcLoc& srcloc, const Value& expression) { auto pod = TRY(arena_alloc()); pod->filename = filename.pod(); pod->srcloc = srcloc.pod(); pod->expression = expression.pod(); return Syntax(std::move(pod)); } Result Syntax::create(const String& filename, const SourcePosition& start, const SourcePosition& end, const Value& expression) { auto srcloc = TRY(SrcLoc::create(start, end)); return Syntax::create(filename, srcloc, expression); } Result Syntax::filename() const { return Value::create(TRY(MkGcRoot(_value->filename.get()))); } Result Syntax::srcloc() const { return Value::create(TRY(MkGcRoot(_value->srcloc.get()))); } Result Syntax::expression() const { return Value::create(TRY(MkGcRoot(_value->expression.get()))); } Result Syntax::cmp(const Syntax& rhs) const { auto lhs_filename = TRY(filename()); auto rhs_filename = TRY(rhs.filename()); short res = TRY(lhs_filename.cmp(rhs_filename)); if (res != 0) return res; auto lhs_srcloc = TRY(srcloc()); auto rhs_srcloc = TRY(rhs.srcloc()); res = TRY(lhs_srcloc.cmp(rhs_srcloc)); return res; auto lhs_expression = TRY(expression()); auto rhs_expression = TRY(rhs.expression()); res = TRY(lhs_expression.cmp(rhs_expression)); return res; } Result syntax_unwrap(Value& val) { Syntax* syntax = val.to(); if (syntax == 0) return val.copy(); return syntax->expression(); } Result Nil::copy_value() const { return Value(Nil(TRY(_value.copy()))); } Result Int64::copy_value() const { return Value(Int64(TRY(_value.copy()))); } Result Float::copy_value() const { return Value(Float(TRY(_value.copy()))); } Result Array::copy_value() const { return Value(Array(TRY(_value.copy()))); } Result Array::copy() const { return Array(TRY(_value.copy())); } Result ByteArray::copy_value() const { return Value(ByteArray(TRY(_value.copy()))); } Result Dict::copy_value() const { return Value(Dict(TRY(_value.copy()))); } Result Dict::copy() const { return Dict(TRY(_value.copy())); } Result String::copy_value() const { return Value(String(TRY(_value.copy()))); } Result String::copy() const { return String(TRY(_value.copy())); } Result String::get(const Value& key) const { if (!key.is()) { return ERROR(TypeMismatch); } uint64_t idx = (uint64_t)key.to()->value(); auto c = TRY(operator[](idx)); auto res = Value(TRY(String::create(&c, 1))); return res; } Result String::set_value(const Value& key, const Value& value) const { if (!key.is()) { return ERROR(TypeMismatch); } if (!value.is()) { return ERROR(TypeMismatch); } uint64_t idx = (uint64_t)key.to()->value(); const String& value_str = *value.to(); auto str_size = TRY(size()); if (idx >= str_size + 1) return ERROR(IndexOutOfRange); auto res = TRY(slice(0, idx)); res = TRY(res.concat(value_str)); auto rem = TRY(slice(std::min(str_size, idx + 1), str_size)); res = TRY(res.concat(rem)); return Value(std::move(res)); } Result Symbol::copy_value() const { return Value(Symbol(TRY(_value.copy()))); } Result Symbol::copy() const { return Symbol(TRY(_value.copy())); } Result Syntax::copy_value() const { return Value(Syntax(TRY(_value.copy()))); } Result Syntax::copy() const { return Syntax(TRY(_value.copy())); } Result SrcLoc::copy_value() const { return Value(SrcLoc(TRY(_value.copy()))); } Result SrcLoc::copy() const { return SrcLoc(TRY(_value.copy())); } Result Pair::copy_value() const { return Value(Pair(TRY(_value.copy()))); } Result Pair::copy() const { return Pair(TRY(_value.copy())); } Result Bool::copy_value() const { return Value(Bool(TRY(_value.copy()))); } Result Opcode::copy_value() const { return Value(Opcode(TRY(_value.copy()))); } Result Opcode::to_string() const { String res = TRY(String::create("")); const char* name = opcode_name(opcode()); OpcodeType ot = opcode_type(opcode()); char buf[256]; switch (ot) { case OpcodeType::Unknown: return ERROR(TypeMismatch); case OpcodeType::Reg0: sprintf(buf, "%s", name); break; case OpcodeType::Reg0I: sprintf(buf, "%s %ld", name, arg1().arg); break; case OpcodeType::Reg1: sprintf(buf, "%s %s%ld", name, (arg1().is_const) ? "c" : "r", arg1().arg); break; case OpcodeType::Reg1I: sprintf(buf, "%s %s%ld %ld", name, (arg1().is_const) ? "c" : "r", arg1().arg, arg2().arg); break; case OpcodeType::Reg2: sprintf(buf, "%s %s%ld %s%ld", name, (arg1().is_const) ? "c" : "r", arg1().arg, (arg2().is_const) ? "c" : "r", arg2().arg); break; case OpcodeType::Reg2I: sprintf(buf, "%s %s%ld %s%ld %ld", name, (arg1().is_const) ? "c" : "r", arg1().arg, (arg2().is_const) ? "c" : "r", arg2().arg, arg3().arg); break; case OpcodeType::Reg3: sprintf(buf, "%s %s%ld %s%ld %s%ld", name, (arg1().is_const) ? "c" : "r", arg1().arg, (arg2().is_const) ? "c" : "r", arg2().arg, (arg3().is_const) ? "c" : "r", arg3().arg); break; case OpcodeType::Reg4: sprintf(buf, "%s %s%ld %s%ld %s%ld %s%ld", name, (arg1().is_const) ? "c" : "r", arg1().arg, (arg2().is_const) ? "c" : "r", arg2().arg, (arg3().is_const) ? "c" : "r", arg3().arg, (arg4().is_const) ? "c" : "r", arg4().arg); break; } res = TRY(res.concat(buf)); return res; } Result Function::copy_value() const { return Value(Function(TRY(_value.copy()))); } Result Function::copy() const { return Function(TRY(_value.copy())); } Result Function::cmp(const Function& rhs) const { short res = (arity() > rhs.arity()) - (arity() < rhs.arity()); if (res != 0) return res; auto lhs_name = TRY(name()); auto rhs_name = TRY(rhs.name()); res = TRY(lhs_name.cmp(rhs_name)); if (res != 0) return res; auto lhs_code = TRY(code()); auto rhs_code = TRY(rhs.code()); res = TRY(lhs_code.cmp(rhs_code)); if (res != 0) return res; auto lhs_closure = TRY(closure()); auto rhs_closure = TRY(rhs.closure()); res = TRY(lhs_closure.cmp(rhs_closure)); if (res != 0) return res; auto lhs_constants = TRY(constants()); auto rhs_constants = TRY(rhs.constants()); res = TRY(lhs_constants.cmp(rhs_constants)); return res; } Result StdlibFunction::copy_value() const { return Value(StdlibFunction(TRY(_value.copy()))); } Result StdlibFunction::copy() const { return StdlibFunction(TRY(_value.copy())); } Result StdlibFunction::cmp(const StdlibFunction& rhs) const { short res = (fun_id() > rhs.fun_id()) - (fun_id() < rhs.fun_id()); 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)); return res; } Result StackFrame::create(const Value& parent, const Value& fun, bool guard) { auto pod = TRY(arena_alloc()); pod->parent = parent.pod(); pod->fun = fun.pod(); pod->guard = guard; pod->pc = 0; pod->size = 0; return StackFrame(std::move(pod)); } Result StackFrame::copy_value() const { return Value(StackFrame(TRY(_value.copy()))); } Result StackFrame::copy() const { return StackFrame(TRY(_value.copy())); } Result StackFrame::get(uint64_t idx) const { if (idx >= _value->size) return ERROR(KeyError); return Value::create(TRY(MkGcRoot(_value->data[idx].get()))); } Result StackFrame::set(uint64_t idx, const Value& val) const { uint64_t size = std::max(_value->size, idx + 1); auto nil = Value(TRY(Nil::create())); auto pod = TRY(arena_alloc(sizeof(OffPtr) * size)); pod->parent = _value->parent; pod->fun = _value->fun; pod->pc = _value->pc; pod->guard = _value->guard; pod->size = size; for (uint64_t i = 0; i < _value->size; i++) { pod->data[i] = _value->data[i]; } if (size > _value->size) { for (uint64_t i = _value->size; i < size; i++) { pod->data[i] = nil.pod(); } } pod->data[idx] = val.pod(); return StackFrame(std::move(pod)); } Result StackFrame::settop(uint64_t idx) const { auto nil = Value(TRY(Nil::create())); auto pod = TRY(arena_alloc(sizeof(OffPtr) * idx)); pod->parent = _value->parent; pod->fun = _value->fun; pod->guard = _value->guard; pod->pc = _value->pc; pod->size = idx; auto min_idx = std::min(_value->size, idx); for (uint64_t i = 0; i < min_idx; i++) { pod->data[i] = _value->data[i]; } if (min_idx < idx) { for (uint64_t i = min_idx; i < idx; i++) { pod->data[i] = nil.pod(); } } return StackFrame(std::move(pod)); } Result StackFrame::parent() const { return Value::create(TRY(MkGcRoot(_value->parent.get()))); } Result StackFrame::fun() const { return Value::create(TRY(MkGcRoot(_value->fun.get()))); } uint64_t StackFrame::pc() const { return _value->pc; } Result StackFrame::setpc(uint64_t pc) { auto pod = TRY(arena_alloc(sizeof(OffPtr) * _value->size)); pod->parent = _value->parent; pod->fun = _value->fun; pod->guard = _value->guard; pod->pc = pc; pod->size = _value->size; for (uint64_t i = 0; i < _value->size; i++) { pod->data[i] = _value->data[i]; } return StackFrame(std::move(pod)); } Result StackFrame::incpc() { return setpc(pc() + 1); } Result StackFrame::call(const Value& fun, uint64_t start, uint64_t end, bool tail) const { StackFrame new_stack; if (!tail) { auto trunc_stack = TRY(settop(start)); new_stack = TRY(StackFrame::create(TRY(trunc_stack.copy_value()), fun)); } else { auto par = TRY(this->parent()); new_stack = TRY(StackFrame::create(par, fun)); } if (fun.is()) { uint64_t arity = fun.to()->arity(); if (arity != (end - start - 1)) { return ERROR(ArgumentCountMismatch); } } for (uint64_t i = 0; i < end - start - 1; i++) { new_stack = TRY(new_stack.set(i, TRY(get(start + i + 1)))); } return new_stack; } Result StackFrame::ret(uint64_t regnum) const { auto parent_frame = TRY(parent()); if (parent_frame.is()) { return ERROR(EndOfProgram); } auto res = TRY(get(regnum)); StackFrame& parent_stack = *parent_frame.to(); uint64_t parent_size = TRY(parent_stack.size()); parent_stack = TRY(parent_stack.set(parent_size, res)); return std::move(parent_stack); } Result StackFrame::ret(const Value& res) const { auto parent_frame = TRY(parent()); if (parent_frame.is()) { return ERROR(EndOfProgram); } StackFrame& parent_stack = *parent_frame.to(); uint64_t parent_size = TRY(parent_stack.size()); parent_stack = TRY(parent_stack.set(parent_size, res)); return std::move(parent_stack); } Result StackFrame::detach(uint64_t depth) const { if (depth == 0) { uint64_t size = _value->size; auto pod = TRY(arena_alloc(sizeof(OffPtr) * 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(std::move(pod)); } auto par = TRY(parent()); if (par.is()) return ERROR(KeyError); StackFrame& par_frame = *par.to(); auto par_frame_new = TRY(par_frame.detach(depth - 1)); uint64_t size = _value->size; auto pod = TRY(arena_alloc(sizeof(OffPtr) * 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(std::move(pod)); } Result StackFrame::attach(const StackFrame& frame) const { auto par = TRY(parent()); if (par.is()) { uint64_t size = _value->size; auto pod = TRY(arena_alloc(sizeof(OffPtr) * 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(std::move(pod)); } StackFrame& par_frame = *par.to(); auto par_frame_new = TRY(par_frame.attach(frame)); uint64_t size = _value->size; auto pod = TRY(arena_alloc(sizeof(OffPtr) * 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(std::move(pod)); } Result StackFrame::unwind(const Value& val, uint64_t start_from) const { StackFrame cur = TRY(copy()); uint64_t depth = 0; while (true) { if (cur.guard() && depth >= start_from) { auto state = TRY(cur.get(1)); if (!state.is()) return ERROR(TypeMismatch); auto state_int = state.to()->value(); if (state_int <= 1) { auto detached_stack = TRY(detach(depth - 1)); auto new_cont = TRY(Continuation::create(val, detached_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()) break; cur = TRY(parent.to()->copy()); ++depth; } return Value(TRY(Nil::create())); } Result StackFrame::depth() const { StackFrame cur = TRY(copy()); uint64_t depth = 1; while (true) { auto parent = TRY(cur.parent()); if (parent.is()) break; cur = TRY(parent.to()->copy()); ++depth; } return depth; } Result StackFrame::set_guard(bool guard) const { uint64_t size = _value->size; auto pod = TRY(arena_alloc(sizeof(OffPtr) * 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(std::move(pod)); } Result StackFrame::backtrace(uint64_t indent) const { String res = TRY(String::create("")); StackFrame cur = TRY(copy()); while (true) { Value par = TRY(cur.parent()); auto fun = TRY(cur.fun()); for (uint64_t i = 0; i < indent; i++) { res = TRY(res.concat(" ")); } if (cur.guard()) { res = TRY(res.concat("guard")); } else { res = TRY(res.concat("Function ")); if (fun.is()) { Function& f = *fun.to(); auto name = TRY(f.name()); if (!name.is()) { name = Value(TRY(String::create(""))); } else { name = Value(TRY(String::create(*name.to()))); } res = TRY(res.concat(*name.to())); } else if (fun.is()) { StdlibFunction& f = *fun.to(); auto name = TRY(String::create(TRY(f.name()))); res = TRY(res.concat(name)); } } res = TRY(res.concat("\n")); if (par.is()) break; cur = TRY(par.to()->copy()); } return res; } Result Error::copy_value() const { return Value(Error(TRY(_value.copy()))); } Result Error::copy() const { return Error(TRY(_value.copy())); } Result Error::name() const { return Value::create(TRY(MkGcRoot(_value->name.get()))); } Result Error::message() const { return Value::create(TRY(MkGcRoot(_value->message.get()))); } Result Error::cmp(const Error& 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_message = TRY(message()); auto rhs_message = TRY(rhs.message()); res = TRY(lhs_message.cmp(rhs_message)); return res; } Result Continuation::create(const Value& value, const StackFrame& frame) { auto pod = TRY(arena_alloc()); pod->value = value.pod(); pod->frame = frame.pod(); return Continuation(std::move(pod)); } Result Continuation::copy_value() const { return Value(Continuation(TRY(_value.copy()))); } Result Continuation::copy() const { return Continuation(TRY(_value.copy())); } Result Continuation::value() const { return Value::create(TRY(MkGcRoot(_value->value.get()))); } Result Continuation::frame() const { return StackFrame( TRY(MkGcRoot((PodStackFrame*)_value->frame.get()))); } Result Continuation::cmp(const Continuation& rhs) const { auto lhs_value = TRY(value()); auto rhs_value = TRY(rhs.value()); short res = TRY(lhs_value.cmp(rhs_value)); if (res != 0) return res; auto lhs_frame = TRY(frame()); auto rhs_frame = TRY(rhs.frame()); res = TRY(lhs_frame.cmp(rhs_frame)); return res; } Result Task::create(uint64_t task_id, const Array& params) { auto pod = TRY(arena_alloc()); pod->task_id = task_id; pod->params = params.pod(); return Task(std::move(pod)); } Result Task::copy_value() const { return Value(Task(TRY(_value.copy()))); } Result Task::copy() const { return Task(TRY(_value.copy())); } Result Task::name() const { const char* task_name = TRY(get_stdlib_task_name(StdlibTaskId(_value->task_id))); return Symbol::create(task_name); } uint64_t Task::task_id() const { return _value->task_id; } Result Task::params() const { return Array(TRY(MkGcRoot((PodArray*)_value->params.get()))); } Result Task::cmp(const Task& rhs) const { short res = (task_id() > rhs.task_id()) - (task_id() < rhs.task_id()); if (res != 0) return res; auto lhs_params = TRY(params()); auto rhs_params = TRY(rhs.params()); res = TRY(lhs_params.cmp(rhs_params)); return res; } Result TaskResult::create(const Value& result, const Value& error) { auto pod = TRY(arena_alloc()); pod->result = result.pod(); pod->error = error.pod(); return TaskResult(std::move(pod)); } Result TaskResult::copy_value() const { return Value(TaskResult(TRY(_value.copy()))); } Result TaskResult::copy() const { return TaskResult(TRY(_value.copy())); } Result TaskResult::result() const { return Value::create(TRY(MkGcRoot(_value->result.get()))); } Result TaskResult::error() const { return Value::create(TRY(MkGcRoot(_value->error.get()))); } Result TaskResult::cmp(const TaskResult& rhs) const { auto lhs_result = TRY(result()); auto rhs_result = TRY(rhs.result()); short res = TRY(lhs_result.cmp(rhs_result)); if (res != 0) return res; auto lhs_error = TRY(error()); auto rhs_error = TRY(rhs.error()); res = TRY(lhs_error.cmp(rhs_error)); return res; } Result Pair::create(const Value& first, const Value& rest) { auto pod = TRY(arena_alloc()); pod->first = first.pod(); pod->rest = rest.pod(); return Pair(std::move(pod)); } Result Pair::create(const Array& arr) { Value cur = TRY(Nil::create()); auto size = TRY(arr.size()); for (uint64_t i = 0; i < size; i++) { Value arr_elt = TRY(arr.get(size - i - 1)); cur = TRY(Pair::create(arr_elt, cur)); } Pair& res = *cur.to(); return TRY(res.copy()); } Result Pair::first() const { auto val = _value->first.get(); return Value::create(TRY(MkGcRoot(val))); } Result Pair::second() const { return TRY(TRY(rest()).first()); } Result Pair::third() const { return TRY(TRY(TRY(rest()).rest()).first()); } Result Pair::rest() const { auto val = _value->rest.get(); return Value::create(TRY(MkGcRoot(val))); } Result Pair::size() const { uint64_t res = 1; Value cur = TRY(rest()); while (!cur.is()) { res += 1; cur = TRY(cur.rest()); } return res; } Result Pair::get(const Value& key) const { if (!key.is()) return ERROR(TypeMismatch); uint64_t i = key.to()->value(); if (i == 0) return first(); i--; Value cur = TRY(rest()); while (!cur.is()) { if (i == 0) return cur.first(); i--; cur = TRY(cur.rest()); } return ERROR(KeyError); } Result Function::create(const Value& name, uint64_t arity, const Array& constants, const Array& code, const Array& closure) { auto pod = TRY(arena_alloc()); pod->arity = arity; pod->name = name.pod(); pod->constants = constants.pod(); pod->code = code.pod(); pod->closure = closure.pod(); return Function(std::move(pod)); } Result Function::create(const Function& prototype, const Array& closure) { auto pod = TRY(arena_alloc()); pod->arity = prototype._value->arity; pod->name = prototype._value->name; pod->constants = prototype._value->constants; pod->code = prototype._value->code; pod->closure = closure.pod(); return Function(std::move(pod)); } Result Function::name() const { return Value::create(TRY(MkGcRoot(_value->name.get()))); } Result Function::code() const { return Array(TRY(MkGcRoot((PodArray*)_value->code.get()))); } Result Function::constants() const { return Array(TRY(MkGcRoot((PodArray*)_value->constants.get()))); } Result Function::closure() const { return Array(TRY(MkGcRoot((PodArray*)_value->closure.get()))); } Result Function::disassemble() const { auto code_arr = TRY(code()); auto constants_arr = TRY(constants()); auto closure_arr = TRY(closure()); auto res = TRY(String::create("")); char buf[256]; auto constants_size = TRY(constants_arr.size()); if (constants_size > 0) { res = TRY(res.concat("constants:\n")); for (uint64_t i = 0; i < constants_size; ++i) { sprintf(buf, " c%ld: ", i); res = TRY(res.concat(buf)); auto val = TRY(constants_arr.get(i)); auto val_str = TRY(write_one(val)); res = TRY(res.concat(val_str)); res = TRY(res.concat("\n")); } res = TRY(res.concat("\n")); } auto closure_size = TRY(closure_arr.size()); if (closure_size > 0) { res = TRY(res.concat("closure:\n")); for (uint64_t i = 0; i < closure_size; ++i) { sprintf(buf, " %ld: ", i); res = TRY(res.concat(buf)); auto val = TRY(closure_arr.get(i)); auto val_str = TRY(write_one(val)); res = TRY(res.concat(val_str)); res = TRY(res.concat("\n")); } res = TRY(res.concat("\n")); } auto code_size = TRY(code_arr.size()); if (code_size > 0) { res = TRY(res.concat("code:\n")); for (uint64_t i = 0; i < code_size; ++i) { res = TRY(res.concat(" ")); auto val = TRY(code_arr.get(i)); if (!val.is()) return ERROR(TypeMismatch); auto val_str = TRY(val.to()->to_string()); res = TRY(res.concat(val_str)); res = TRY(res.concat("\n")); } } return res; } Result StdlibFunction::create(StdlibFunctionId fun_id) { auto pod = TRY(arena_alloc()); pod->fun_id = (uint64_t)fun_id; return StdlibFunction(std::move(pod)); } Result StdlibFunction::name() const { const char* fun_name = TRY(get_stdlib_function_name(StdlibFunctionId(_value->fun_id))); return Symbol::create(fun_name); } StdlibFunctionId StdlibFunction::fun_id() const { return StdlibFunctionId(_value->fun_id); } Result Module::create(const Value& name, const Function& fun) { auto pod = TRY(arena_alloc()); pod->name = name.pod(); pod->fun = fun.pod(); return Module(std::move(pod)); } Result Module::name() const { return Value::create(TRY(MkGcRoot(_value->name.get()))); } Result Module::fun() const { return Function(TRY(MkGcRoot((PodFunction*)_value->fun.get()))); } Result reverse(Value& val) { if (val.is()) return Value(TRY(Nil::create())); if (!val.is()) return ERROR(TypeMismatch); auto res = Value(TRY(Nil::create())); auto cur = TRY(val.copy()); while (!cur.is()) { if (!cur.is()) return ERROR(TypeMismatch); Pair& pair = *cur.to(); Value first = TRY(pair.first()); cur = TRY(pair.rest()); res = TRY(Pair::create(first, res)); } return res; } Result debug_print(const char* val) { std::cout << val << "\n"; return Result(); } Result debug_print(const String& val) { auto ba = TRY(ByteArray::create(val)); auto size = TRY(ba.size()); for (uint64_t i = 0; i < size; i++) { std::cout << TRY(ba[i]); } std::cout << "\n"; return Result(); } Result debug_print(const Value& val) { auto w = Writer(); auto s = TRY(w.write_one(val)); return debug_print(s); } Result Array::get(uint64_t idx) const { if (idx >= _value->size) return ERROR(IndexOutOfRange); auto val = _value->data[idx].get(); return Value::create(TRY(MkGcRoot(val))); } Result Array::get(const Value& key) const { if (!key.is()) return ERROR(TypeMismatch); return get(key.to()->value()); } Result Array::set(uint64_t idx, const Value& value) const { uint64_t res_size = TRY(size()); if (idx >= res_size) return ERROR(IndexOutOfRange); auto pod = TRY(arena_alloc(res_size * sizeof(OffPtr))); pod->size = res_size; for (uint64_t i = 0; i < res_size; i++) { pod->data[i] = _value->data[i].get(); } pod->data[idx] = value.pod(); return Array(std::move(pod)); } Result Array::set(const Value& key, const Value& value) const { if (!key.is()) return ERROR(TypeMismatch); return set(key.to()->value(), value); } Result Array::set_value(const Value& key, const Value& value) const { return Value(TRY(set(key, value))); } Result Array::append(const Value& rhs) const { uint64_t res_size = TRY(size()) + 1; auto size = TRY(this->size()); auto pod = TRY(arena_alloc(res_size * sizeof(OffPtr))); pod->size = res_size; for (uint64_t i = 0; i < size; i++) { pod->data[i] = _value->data[i].get(); } pod->data[TRY(this->size())] = rhs.pod(); return Array(std::move(pod)); } short cmp_tag(Tag lhs, Tag rhs) { if (lhs < rhs) return -1; if (rhs < lhs) return 1; return 0; } Result Dict::create(const Array& arr) { auto arr_size = TRY(arr.size()); if (arr_size % 2 != 0) return ERROR(KeyError); Dict res = TRY(Dict::create()); for (uint64_t i = 0; i < arr_size / 2; i++) { auto key = TRY(Value::create(TRY(MkGcRoot(arr._value->data[2 * i].get())))); auto value = TRY(Value::create(TRY(MkGcRoot(arr._value->data[2 * i + 1].get())))); res = TRY(res.set(key, value)); } return std::move(res); } Result Dict::get(const Value& key) const { auto pos = TRY(find(key)); if (pos >= TRY(size())) { return ERROR(KeyError); } auto k = TRY(Value::create(TRY(MkGcRoot(_value->data[pos * 2].get())))); if (TRY(k.cmp(key)) != 0) { return ERROR(KeyError); } return TRY(Value::create(TRY(MkGcRoot(_value->data[pos * 2 + 1].get())))); } Result Dict::set(const Value& key, const Value& value) const { auto pos = TRY(find(key)); auto this_size = TRY(size()); auto s = this_size; if (pos >= s) { s += 1; } else { auto k = TRY(Value::create(TRY(MkGcRoot(_value->data[pos * 2].get())))); if (TRY(k.cmp(key)) != 0) s += 1; } auto pod = TRY(arena_alloc(2 * s * sizeof(OffPtr))); pod->size = s; auto vpod = _value.get(); for (uint64_t i = 0, j = 0; i < s; i++, j++) { if (i == pos) { pod->data[i * 2] = key.pod(); pod->data[i * 2 + 1] = value.pod(); if (s > this_size && i < s - 1) { i++; pod->data[i * 2] = _value->data[j * 2].get(); pod->data[i * 2 + 1] = _value->data[j * 2 + 1].get(); } } else { pod->data[i * 2] = _value->data[j * 2].get(); pod->data[i * 2 + 1] = _value->data[j * 2 + 1].get(); } } return Dict(std::move(pod)); } Result Dict::set_value(const Value& key, const Value& value) const { return Value(TRY(set(key, value))); } Result Dict::find(const Value& key) const { uint64_t left = 0; uint64_t right = TRY(size()); uint64_t pos = (left + right) / 2; while (left < right) { auto v = TRY(Value::create(TRY(MkGcRoot(_value->data[pos * 2].get())))); auto c = TRY(v.cmp(key)); if (c == 0) { return pos; } if (c < 0) { left = pos + 1; } if (c > 0) { right = pos; } pos = (left + right) / 2; } return left; } Result Object::add(const Object&) const { return ERROR(NotImplemented); } Result Object::add(const Int64&) const { return ERROR(NotImplemented); } Result Object::add(const Float&) const { return ERROR(NotImplemented); } Result Object::sub(const Object&) const { return ERROR(NotImplemented); } Result Object::sub_inv(const Int64&) const { return ERROR(NotImplemented); } Result Object::sub_inv(const Float&) const { return ERROR(NotImplemented); } Result Object::mul(const Object&) const { return ERROR(NotImplemented); } Result Object::mul(const Int64&) const { return ERROR(NotImplemented); } Result Object::mul(const Float&) const { return ERROR(NotImplemented); } Result Object::div(const Object&) const { return ERROR(NotImplemented); } Result Object::div_inv(const Int64&) const { return ERROR(NotImplemented); } Result Object::div_inv(const Float&) const { return ERROR(NotImplemented); } Result Int64::add(const Object& rhs) const { return rhs.add(*this); } Result Int64::add(const Int64& rhs) const { return Value(TRY(Int64::create(value() + rhs.value()))); } Result Int64::add(const Float& rhs) const { return Value(TRY(Float::create(value() + rhs.value()))); } Result Int64::mul(const Object& rhs) const { return rhs.mul(*this); } Result Int64::mul(const Int64& rhs) const { return Value(TRY(Int64::create(value() * rhs.value()))); } Result Int64::mul(const Float& rhs) const { return Value(TRY(Float::create(value() * rhs.value()))); } Result Int64::sub(const Object& rhs) const { return rhs.sub_inv(*this); } Result Int64::sub_inv(const Int64& rhs) const { return Value(TRY(Int64::create(rhs.value() - value()))); } Result Int64::sub_inv(const Float& rhs) const { return Value(TRY(Int64::create(rhs.value() - float(value())))); } Result Int64::div(const Object& rhs) const { return rhs.div_inv(*this); } Result Int64::div_inv(const Int64& rhs) const { if (value() == 0) return ERROR(DivisionByZero); if (rhs.value() % value() == 0) { return Value(TRY(Int64::create(rhs.value() / value()))); } return Value(TRY(Float::create(float(rhs.value()) / float(value())))); } Result Int64::div_inv(const Float& rhs) const { if (value() == 0) return ERROR(DivisionByZero); return Value(TRY(Float::create(rhs.value() / float(value())))); } Result Float::add(const Object& rhs) const { return rhs.add(*this); } Result Float::add(const Float& rhs) const { return Value(TRY(Float::create(value() + rhs.value()))); } Result Float::add(const Int64& rhs) const { return Value(TRY(Float::create(value() + float(rhs.value())))); } Result Float::mul(const Object& rhs) const { return rhs.mul(*this); } Result Float::mul(const Float& rhs) const { return Value(TRY(Float::create(value() * rhs.value()))); } Result Float::mul(const Int64& rhs) const { return Value(TRY(Float::create(value() * float(rhs.value())))); } Result Float::sub(const Object& rhs) const { return rhs.sub_inv(*this); } Result Float::sub_inv(const Float& rhs) const { return Value(TRY(Float::create(rhs.value() - value()))); } Result Float::sub_inv(const Int64& rhs) const { return Value(TRY(Float::create(float(rhs.value()) - value()))); } Result Float::div(const Object& rhs) const { return rhs.div_inv(*this); } Result Float::div_inv(const Float& rhs) const { if (value() == 0) return ERROR(DivisionByZero); return Value(TRY(Float::create(rhs.value() / value()))); } Result Float::div_inv(const Int64& rhs) const { if (value() == 0) return ERROR(DivisionByZero); return Value(TRY(Float::create(float(rhs.value()) / value()))); } Result Int64::cmp(const Float& rhs) const { return (_value->value > rhs._value->value) - (_value->value < rhs._value->value); } Result Float::cmp(const Int64& rhs) const { return (_value->value > rhs._value->value) - (_value->value < rhs._value->value); } Result Dict::cmp(const Dict& rhs) const { auto lsize = TRY(size()) * 2; auto rsize = TRY(rhs.size()) * 2; uint64_t i = 0; uint64_t j = 0; while (1) { if (i == lsize && j == rsize) return 0; short cmp = short(i == lsize) - short(j == rsize); if (cmp != 0) return cmp; Value lc = TRY(Value::create(TRY(MkGcRoot(_value->data[i].get())))); Value rc = TRY(Value::create(TRY(MkGcRoot(rhs._value->data[j].get())))); cmp = TRY(lc.cmp(rc)); if (cmp != 0) return cmp; i++; j++; } return 0; } Result Array::cmp(const Array& rhs) const { auto lsize = TRY(size()); auto rsize = TRY(rhs.size()); uint64_t i = 0; uint64_t j = 0; while (1) { if (i == lsize && j == rsize) return 0; short cmp = short(i == lsize) - short(j == rsize); if (cmp != 0) return cmp; Value lc = TRY(Value::create(TRY(MkGcRoot(_value->data[i].get())))); Value rc = TRY(Value::create(TRY(MkGcRoot(rhs._value->data[j].get())))); cmp = TRY(lc.cmp(rc)); if (cmp != 0) return cmp; i++; j++; } return 0; } Result Object::get(const Value& key) const { return ERROR(TypeMismatch); } Result Object::set_value(const Value& key, const Value& value) const { return ERROR(TypeMismatch); } Result Object::first() const { return ERROR(TypeMismatch); } Result Object::second() const { return ERROR(TypeMismatch); } Result Object::third() const { return ERROR(TypeMismatch); } Result Object::rest() const { return ERROR(TypeMismatch); } Result Object::size() const { return ERROR(TypeMismatch); } Result syntax_is_list(const Value& value) { if (!value.is()) return value.is() || value.is(); auto val = TRY(value.to()->expression()); return val.is() || val.is(); } Result syntax_is_nil(const Value& value) { if (!value.is()) return value.is(); auto val = TRY(value.to()->expression()); return val.is(); } Result syntax_unwrap(const Value& value) { if (!value.is()) return value.copy(); return TRY(value.to()->expression()); } Result syntax_unwrap_all(const Value& value) { if (value.is()) { auto val = TRY(value.to()->expression()); return syntax_unwrap_all(val); } if (value.is()) { auto res = Value(TRY(Nil::create())); auto cur = TRY(value.copy()); while (!cur.is()) { auto val = TRY(syntax_unwrap_all(TRY(cur.first()))); res = Value(TRY(Pair::create(val, res))); cur = TRY(cur.rest()); } return reverse(res); } return value.copy(); } Result Syntax::first() const { auto val = TRY(expression()); return val.first(); } Result Syntax::second() const { auto val = TRY(expression()); return val.second(); } Result Syntax::third() const { auto val = TRY(expression()); return val.third(); } Result Syntax::rest() const { auto val = TRY(expression()); return val.rest(); } Result Syntax::size() const { auto val = TRY(expression()); return val.size(); } Result build_string(const String& value) { return value.copy(); } Result build_string(const Value& value) { if (value.is()) { return value.to()->copy(); } return write_one(value); } Result build_string(const char* value) { return String::create(value); } Result build_string(int64_t value) { auto val = Value(TRY(Int64::create(value))); return write_one(val); } Result build_string(uint64_t value) { auto val = Value(TRY(Int64::create((int64_t)value))); return write_one(val); } Result print_string(const String& s) { auto ba = TRY(ByteArray::create(s)); auto size = TRY(ba.size()); for (uint64_t i = 0; i < size; i++) { std::cout << TRY(ba[i]); } return Result(); }