1597 lines
44 KiB
C++
1597 lines
44 KiB
C++
#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> Value::create(GcRootBase&& obj) {
|
|
switch (obj->header.tag) {
|
|
case Tag::Nil:
|
|
return Value(Nil(std::move(obj).move_as<PodNil>()));
|
|
case Tag::Int64:
|
|
return Value(Int64(std::move(obj).move_as<PodInt64>()));
|
|
case Tag::Float:
|
|
return Value(Float(std::move(obj).move_as<PodFloat>()));
|
|
case Tag::Bool:
|
|
return Value(Bool(std::move(obj).move_as<PodBool>()));
|
|
case Tag::Array:
|
|
return Value(Array(std::move(obj).move_as<PodArray>()));
|
|
case Tag::ByteArray:
|
|
return Value(ByteArray(std::move(obj).move_as<PodByteArray>()));
|
|
case Tag::Dict:
|
|
return Value(Dict(std::move(obj).move_as<PodDict>()));
|
|
case Tag::String:
|
|
return Value(String(std::move(obj).move_as<PodString>()));
|
|
case Tag::Symbol:
|
|
return Value(Symbol(std::move(obj).move_as<PodSymbol>()));
|
|
case Tag::SrcLoc:
|
|
return Value(SrcLoc(std::move(obj).move_as<PodSrcLoc>()));
|
|
case Tag::Syntax:
|
|
return Value(Syntax(std::move(obj).move_as<PodSyntax>()));
|
|
case Tag::Pair:
|
|
return Value(Pair(std::move(obj).move_as<PodPair>()));
|
|
case Tag::Opcode:
|
|
return Value(Opcode(std::move(obj).move_as<PodOpcode>()));
|
|
case Tag::Function:
|
|
return Value(Function(std::move(obj).move_as<PodFunction>()));
|
|
case Tag::StdlibFunction:
|
|
return Value(StdlibFunction(std::move(obj).move_as<PodStdlibFunction>()));
|
|
case Tag::Module:
|
|
return Value(Module(std::move(obj).move_as<PodModule>()));
|
|
case Tag::StackFrame:
|
|
return Value(StackFrame(std::move(obj).move_as<PodStackFrame>()));
|
|
case Tag::Error:
|
|
return Value(Error(std::move(obj).move_as<PodError>()));
|
|
case Tag::Continuation:
|
|
return Value(Continuation(std::move(obj).move_as<PodContinuation>()));
|
|
case Tag::Task:
|
|
return Value(Task(std::move(obj).move_as<PodTask>()));
|
|
case Tag::TaskResult:
|
|
return Value(TaskResult(std::move(obj).move_as<PodTaskResult>()));
|
|
};
|
|
return Value();
|
|
}
|
|
|
|
Result<Symbol> Symbol::create(String& rhs) {
|
|
uint64_t rhs_size = TRY(rhs.size());
|
|
uint64_t res_size = rhs_size;
|
|
|
|
auto pod = TRY(arena_alloc<PodSymbol>(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> String::create(const Symbol& rhs) {
|
|
uint64_t rhs_size = TRY(rhs.size());
|
|
uint64_t res_size = rhs_size;
|
|
|
|
auto pod = TRY(arena_alloc<PodString>(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> 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<PodByteArray>(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<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(std::move(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(std::move(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(std::move(pod));
|
|
}
|
|
|
|
Result<SrcLoc> SrcLoc::create(const SourceRange& sourcerange) {
|
|
auto pod = TRY(arena_alloc<PodSrcLoc>());
|
|
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<short> SrcLoc::cmp(const SrcLoc& rhs) const {
|
|
auto lhs_sourcerange = sourcerange();
|
|
auto rhs_sourcerange = rhs.sourcerange();
|
|
return sourcerange_cmp(lhs_sourcerange, rhs_sourcerange);
|
|
}
|
|
|
|
Result<Syntax> Syntax::create(const String& filename, const SrcLoc& srcloc,
|
|
const Value& expression) {
|
|
auto pod = TRY(arena_alloc<PodSyntax>());
|
|
pod->filename = filename.pod();
|
|
pod->srcloc = srcloc.pod();
|
|
pod->expression = expression.pod();
|
|
|
|
return Syntax(std::move(pod));
|
|
}
|
|
|
|
Result<Syntax> 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<Value> Syntax::filename() const {
|
|
return Value::create(TRY(MkGcRoot(_value->filename.get())));
|
|
}
|
|
|
|
Result<Value> Syntax::srcloc() const {
|
|
return Value::create(TRY(MkGcRoot(_value->srcloc.get())));
|
|
}
|
|
|
|
Result<Value> Syntax::expression() const {
|
|
return Value::create(TRY(MkGcRoot(_value->expression.get())));
|
|
}
|
|
|
|
Result<short> 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<Value> syntax_unwrap(Value& val) {
|
|
Syntax* syntax = val.to<Syntax>();
|
|
if (syntax == 0) return val.copy();
|
|
|
|
return syntax->expression();
|
|
}
|
|
|
|
Result<Value> Nil::copy_value() const { return Value(Nil(TRY(_value.copy()))); }
|
|
|
|
Result<Value> Int64::copy_value() const {
|
|
return Value(Int64(TRY(_value.copy())));
|
|
}
|
|
Result<Value> Float::copy_value() const {
|
|
return Value(Float(TRY(_value.copy())));
|
|
}
|
|
|
|
Result<Value> Array::copy_value() const {
|
|
return Value(Array(TRY(_value.copy())));
|
|
}
|
|
Result<Array> Array::copy() const { return Array(TRY(_value.copy())); }
|
|
|
|
Result<Value> ByteArray::copy_value() const {
|
|
return Value(ByteArray(TRY(_value.copy())));
|
|
}
|
|
|
|
Result<Value> Dict::copy_value() const {
|
|
return Value(Dict(TRY(_value.copy())));
|
|
}
|
|
|
|
Result<Dict> Dict::copy() const { return Dict(TRY(_value.copy())); }
|
|
|
|
Result<Value> String::copy_value() const {
|
|
return Value(String(TRY(_value.copy())));
|
|
}
|
|
|
|
Result<String> String::copy() const { return String(TRY(_value.copy())); }
|
|
|
|
Result<Value> String::get(const Value& key) const {
|
|
if (!key.is<Int64>()) {
|
|
return ERROR(TypeMismatch);
|
|
}
|
|
uint64_t idx = (uint64_t)key.to<Int64>()->value();
|
|
auto c = TRY(operator[](idx));
|
|
|
|
auto res = Value(TRY(String::create(&c, 1)));
|
|
return res;
|
|
}
|
|
|
|
Result<Value> String::set_value(const Value& key, const Value& value) const {
|
|
if (!key.is<Int64>()) {
|
|
return ERROR(TypeMismatch);
|
|
}
|
|
|
|
if (!value.is<String>()) {
|
|
return ERROR(TypeMismatch);
|
|
}
|
|
|
|
uint64_t idx = (uint64_t)key.to<Int64>()->value();
|
|
const String& value_str = *value.to<String>();
|
|
|
|
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<Value> Symbol::copy_value() const {
|
|
return Value(Symbol(TRY(_value.copy())));
|
|
}
|
|
|
|
Result<Symbol> Symbol::copy() const { return Symbol(TRY(_value.copy())); }
|
|
|
|
Result<Value> Syntax::copy_value() const {
|
|
return Value(Syntax(TRY(_value.copy())));
|
|
}
|
|
|
|
Result<Syntax> Syntax::copy() const { return Syntax(TRY(_value.copy())); }
|
|
|
|
Result<Value> SrcLoc::copy_value() const {
|
|
return Value(SrcLoc(TRY(_value.copy())));
|
|
}
|
|
|
|
Result<SrcLoc> SrcLoc::copy() const { return SrcLoc(TRY(_value.copy())); }
|
|
|
|
Result<Value> Pair::copy_value() const {
|
|
return Value(Pair(TRY(_value.copy())));
|
|
}
|
|
|
|
Result<Pair> Pair::copy() const { return Pair(TRY(_value.copy())); }
|
|
|
|
Result<Value> Bool::copy_value() const {
|
|
return Value(Bool(TRY(_value.copy())));
|
|
}
|
|
|
|
Result<Value> Opcode::copy_value() const {
|
|
return Value(Opcode(TRY(_value.copy())));
|
|
}
|
|
|
|
Result<String> 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<Value> Function::copy_value() const {
|
|
return Value(Function(TRY(_value.copy())));
|
|
}
|
|
Result<Function> Function::copy() const { return Function(TRY(_value.copy())); }
|
|
|
|
Result<short> 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<Value> StdlibFunction::copy_value() const {
|
|
return Value(StdlibFunction(TRY(_value.copy())));
|
|
}
|
|
Result<StdlibFunction> StdlibFunction::copy() const {
|
|
return StdlibFunction(TRY(_value.copy()));
|
|
}
|
|
|
|
Result<short> StdlibFunction::cmp(const StdlibFunction& rhs) const {
|
|
short res = (fun_id() > rhs.fun_id()) - (fun_id() < rhs.fun_id());
|
|
return res;
|
|
}
|
|
|
|
Result<Value> Module::copy_value() const {
|
|
return Value(Module(TRY(_value.copy())));
|
|
}
|
|
Result<Module> Module::copy() const { return Module(TRY(_value.copy())); }
|
|
|
|
Result<short> 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> StackFrame::create(const Value& parent, const Value& fun,
|
|
bool guard) {
|
|
auto pod = TRY(arena_alloc<PodStackFrame>());
|
|
|
|
pod->parent = parent.pod();
|
|
pod->fun = fun.pod();
|
|
pod->guard = guard;
|
|
pod->pc = 0;
|
|
pod->size = 0;
|
|
|
|
return StackFrame(std::move(pod));
|
|
}
|
|
|
|
Result<Value> StackFrame::copy_value() const {
|
|
return Value(StackFrame(TRY(_value.copy())));
|
|
}
|
|
|
|
Result<StackFrame> StackFrame::copy() const {
|
|
return StackFrame(TRY(_value.copy()));
|
|
}
|
|
|
|
Result<Value> StackFrame::get(uint64_t idx) const {
|
|
if (idx >= _value->size) return ERROR(KeyError);
|
|
|
|
return Value::create(TRY(MkGcRoot(_value->data[idx].get())));
|
|
}
|
|
|
|
Result<StackFrame> 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<PodStackFrame>(sizeof(OffPtr<PodObject>) * 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> StackFrame::settop(uint64_t idx) const {
|
|
auto nil = Value(TRY(Nil::create()));
|
|
auto pod = TRY(arena_alloc<PodStackFrame>(sizeof(OffPtr<PodObject>) * 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<Value> StackFrame::parent() const {
|
|
return Value::create(TRY(MkGcRoot(_value->parent.get())));
|
|
}
|
|
Result<Value> StackFrame::fun() const {
|
|
return Value::create(TRY(MkGcRoot(_value->fun.get())));
|
|
}
|
|
uint64_t StackFrame::pc() const { return _value->pc; }
|
|
|
|
Result<StackFrame> StackFrame::setpc(uint64_t pc) {
|
|
auto pod =
|
|
TRY(arena_alloc<PodStackFrame>(sizeof(OffPtr<PodObject>) * _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> StackFrame::incpc() { return setpc(pc() + 1); }
|
|
|
|
Result<StackFrame> 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<Function>()) {
|
|
uint64_t arity = fun.to<Function>()->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> StackFrame::ret(uint64_t regnum) const {
|
|
auto parent_frame = TRY(parent());
|
|
if (parent_frame.is<Nil>()) {
|
|
return ERROR(EndOfProgram);
|
|
}
|
|
|
|
auto res = TRY(get(regnum));
|
|
StackFrame& parent_stack = *parent_frame.to<StackFrame>();
|
|
uint64_t parent_size = TRY(parent_stack.size());
|
|
parent_stack = TRY(parent_stack.set(parent_size, res));
|
|
|
|
return std::move(parent_stack);
|
|
}
|
|
|
|
Result<StackFrame> StackFrame::ret(const Value& res) const {
|
|
auto parent_frame = TRY(parent());
|
|
if (parent_frame.is<Nil>()) {
|
|
return ERROR(EndOfProgram);
|
|
}
|
|
|
|
StackFrame& parent_stack = *parent_frame.to<StackFrame>();
|
|
uint64_t parent_size = TRY(parent_stack.size());
|
|
parent_stack = TRY(parent_stack.set(parent_size, res));
|
|
|
|
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(std::move(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(std::move(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(std::move(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(std::move(pod));
|
|
}
|
|
|
|
Result<Value> 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<Int64>()) return ERROR(TypeMismatch);
|
|
auto state_int = state.to<Int64>()->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<Nil>()) break;
|
|
|
|
cur = TRY(parent.to<StackFrame>()->copy());
|
|
++depth;
|
|
}
|
|
return Value(TRY(Nil::create()));
|
|
}
|
|
|
|
Result<uint64_t> StackFrame::depth() const {
|
|
StackFrame cur = TRY(copy());
|
|
|
|
uint64_t depth = 1;
|
|
while (true) {
|
|
auto parent = TRY(cur.parent());
|
|
if (parent.is<Nil>()) break;
|
|
|
|
cur = TRY(parent.to<StackFrame>()->copy());
|
|
++depth;
|
|
}
|
|
return depth;
|
|
}
|
|
|
|
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(std::move(pod));
|
|
}
|
|
|
|
Result<String> 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>()) {
|
|
Function& f = *fun.to<Function>();
|
|
auto name = TRY(f.name());
|
|
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("\n"));
|
|
|
|
if (par.is<Nil>()) break;
|
|
|
|
cur = TRY(par.to<StackFrame>()->copy());
|
|
}
|
|
return res;
|
|
}
|
|
|
|
Result<Value> Error::copy_value() const {
|
|
return Value(Error(TRY(_value.copy())));
|
|
}
|
|
Result<Error> Error::copy() const { return Error(TRY(_value.copy())); }
|
|
|
|
Result<Value> Error::name() const {
|
|
return Value::create(TRY(MkGcRoot(_value->name.get())));
|
|
}
|
|
Result<Value> Error::message() const {
|
|
return Value::create(TRY(MkGcRoot(_value->message.get())));
|
|
}
|
|
|
|
Result<short> 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> Continuation::create(const Value& value,
|
|
const StackFrame& frame) {
|
|
auto pod = TRY(arena_alloc<PodContinuation>());
|
|
|
|
pod->value = value.pod();
|
|
pod->frame = frame.pod();
|
|
|
|
return Continuation(std::move(pod));
|
|
}
|
|
|
|
Result<Value> Continuation::copy_value() const {
|
|
return Value(Continuation(TRY(_value.copy())));
|
|
}
|
|
Result<Continuation> Continuation::copy() const {
|
|
return Continuation(TRY(_value.copy()));
|
|
}
|
|
|
|
Result<Value> Continuation::value() const {
|
|
return Value::create(TRY(MkGcRoot(_value->value.get())));
|
|
}
|
|
Result<StackFrame> Continuation::frame() const {
|
|
return StackFrame(
|
|
TRY(MkGcRoot<PodStackFrame>((PodStackFrame*)_value->frame.get())));
|
|
}
|
|
|
|
Result<short> 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> Task::create(uint64_t task_id, const Array& params) {
|
|
auto pod = TRY(arena_alloc<PodTask>());
|
|
|
|
pod->task_id = task_id;
|
|
pod->params = params.pod();
|
|
|
|
return Task(std::move(pod));
|
|
}
|
|
|
|
Result<Value> Task::copy_value() const {
|
|
return Value(Task(TRY(_value.copy())));
|
|
}
|
|
Result<Task> Task::copy() const { return Task(TRY(_value.copy())); }
|
|
|
|
Result<Symbol> 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<Array> Task::params() const {
|
|
return Array(TRY(MkGcRoot((PodArray*)_value->params.get())));
|
|
}
|
|
|
|
Result<short> 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> TaskResult::create(const Value& result, const Value& error) {
|
|
auto pod = TRY(arena_alloc<PodTaskResult>());
|
|
|
|
pod->result = result.pod();
|
|
pod->error = error.pod();
|
|
|
|
return TaskResult(std::move(pod));
|
|
}
|
|
|
|
Result<Value> TaskResult::copy_value() const {
|
|
return Value(TaskResult(TRY(_value.copy())));
|
|
}
|
|
Result<TaskResult> TaskResult::copy() const {
|
|
return TaskResult(TRY(_value.copy()));
|
|
}
|
|
|
|
Result<Value> TaskResult::result() const {
|
|
return Value::create(TRY(MkGcRoot(_value->result.get())));
|
|
}
|
|
Result<Value> TaskResult::error() const {
|
|
return Value::create(TRY(MkGcRoot(_value->error.get())));
|
|
}
|
|
|
|
Result<short> 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> Pair::create(const Value& first, const Value& rest) {
|
|
auto pod = TRY(arena_alloc<PodPair>());
|
|
pod->first = first.pod();
|
|
pod->rest = rest.pod();
|
|
|
|
return Pair(std::move(pod));
|
|
}
|
|
|
|
Result<Pair> 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<Pair>();
|
|
return TRY(res.copy());
|
|
}
|
|
|
|
Result<Value> Pair::first() const {
|
|
auto val = _value->first.get();
|
|
return Value::create(TRY(MkGcRoot(val)));
|
|
}
|
|
|
|
Result<Value> Pair::second() const { return TRY(TRY(rest()).first()); }
|
|
Result<Value> Pair::third() const {
|
|
return TRY(TRY(TRY(rest()).rest()).first());
|
|
}
|
|
|
|
Result<Value> Pair::rest() const {
|
|
auto val = _value->rest.get();
|
|
return Value::create(TRY(MkGcRoot(val)));
|
|
}
|
|
|
|
Result<uint64_t> Pair::size() const {
|
|
uint64_t res = 1;
|
|
|
|
Value cur = TRY(rest());
|
|
while (!cur.is<Nil>()) {
|
|
res += 1;
|
|
cur = TRY(cur.rest());
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
Result<Value> Pair::get(const Value& key) const {
|
|
if (!key.is<Int64>()) return ERROR(TypeMismatch);
|
|
|
|
uint64_t i = key.to<Int64>()->value();
|
|
|
|
if (i == 0) return first();
|
|
i--;
|
|
|
|
Value cur = TRY(rest());
|
|
|
|
while (!cur.is<Nil>()) {
|
|
if (i == 0) return cur.first();
|
|
i--;
|
|
cur = TRY(cur.rest());
|
|
}
|
|
|
|
return ERROR(KeyError);
|
|
}
|
|
|
|
Result<Function> Function::create(const Value& name, uint64_t arity,
|
|
const Array& constants, const Array& code,
|
|
const Array& closure) {
|
|
auto pod = TRY(arena_alloc<PodFunction>());
|
|
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> Function::create(const Function& prototype,
|
|
const Array& closure) {
|
|
auto pod = TRY(arena_alloc<PodFunction>());
|
|
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<Value> Function::name() const {
|
|
return Value::create(TRY(MkGcRoot(_value->name.get())));
|
|
}
|
|
|
|
Result<Array> Function::code() const {
|
|
return Array(TRY(MkGcRoot((PodArray*)_value->code.get())));
|
|
}
|
|
|
|
Result<Array> Function::constants() const {
|
|
return Array(TRY(MkGcRoot((PodArray*)_value->constants.get())));
|
|
}
|
|
|
|
Result<Array> Function::closure() const {
|
|
return Array(TRY(MkGcRoot((PodArray*)_value->closure.get())));
|
|
}
|
|
|
|
Result<String> 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<Opcode>()) return ERROR(TypeMismatch);
|
|
auto val_str = TRY(val.to<Opcode>()->to_string());
|
|
res = TRY(res.concat(val_str));
|
|
res = TRY(res.concat("\n"));
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
Result<StdlibFunction> StdlibFunction::create(StdlibFunctionId fun_id) {
|
|
auto pod = TRY(arena_alloc<PodStdlibFunction>());
|
|
pod->fun_id = (uint64_t)fun_id;
|
|
|
|
return StdlibFunction(std::move(pod));
|
|
}
|
|
|
|
Result<Symbol> 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> Module::create(const Value& name, const Function& fun) {
|
|
auto pod = TRY(arena_alloc<PodModule>());
|
|
pod->name = name.pod();
|
|
pod->fun = fun.pod();
|
|
|
|
return Module(std::move(pod));
|
|
}
|
|
|
|
Result<Value> Module::name() const {
|
|
return Value::create(TRY(MkGcRoot(_value->name.get())));
|
|
}
|
|
|
|
Result<Function> Module::fun() const {
|
|
return Function(TRY(MkGcRoot((PodFunction*)_value->fun.get())));
|
|
}
|
|
|
|
Result<Value> reverse(Value& val) {
|
|
if (val.is<Nil>()) return Value(TRY(Nil::create()));
|
|
if (!val.is<Pair>()) return ERROR(TypeMismatch);
|
|
|
|
auto res = Value(TRY(Nil::create()));
|
|
auto cur = TRY(val.copy());
|
|
|
|
while (!cur.is<Nil>()) {
|
|
if (!cur.is<Pair>()) return ERROR(TypeMismatch);
|
|
Pair& pair = *cur.to<Pair>();
|
|
Value first = TRY(pair.first());
|
|
cur = TRY(pair.rest());
|
|
res = TRY(Pair::create(first, res));
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
Result<void> debug_print(const char* val) {
|
|
std::cout << val << "\n";
|
|
return Result<void>();
|
|
}
|
|
|
|
Result<void> 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<void>();
|
|
}
|
|
|
|
Result<void> debug_print(const Value& val) {
|
|
auto w = Writer();
|
|
auto s = TRY(w.write_one(val));
|
|
return debug_print(s);
|
|
}
|
|
|
|
Result<Value> 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<Value> Array::get(const Value& key) const {
|
|
if (!key.is<Int64>()) return ERROR(TypeMismatch);
|
|
return get(key.to<Int64>()->value());
|
|
}
|
|
|
|
Result<Array> 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<PodArray>(res_size * sizeof(OffPtr<PodObject>)));
|
|
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> Array::set(const Value& key, const Value& value) const {
|
|
if (!key.is<Int64>()) return ERROR(TypeMismatch);
|
|
|
|
return set(key.to<Int64>()->value(), value);
|
|
}
|
|
|
|
Result<Value> Array::set_value(const Value& key, const Value& value) const {
|
|
return Value(TRY(set(key, value)));
|
|
}
|
|
|
|
Result<Array> Array::append(const Value& rhs) const {
|
|
uint64_t res_size = TRY(size()) + 1;
|
|
auto size = TRY(this->size());
|
|
|
|
auto pod = TRY(arena_alloc<PodArray>(res_size * sizeof(OffPtr<PodObject>)));
|
|
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> 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<Value> 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> 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<PodDict>(2 * s * sizeof(OffPtr<PodObject>)));
|
|
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<Value> Dict::set_value(const Value& key, const Value& value) const {
|
|
return Value(TRY(set(key, value)));
|
|
}
|
|
|
|
Result<uint64_t> 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<Value> Object::add(const Object&) const { return ERROR(NotImplemented); }
|
|
Result<Value> Object::add(const Int64&) const { return ERROR(NotImplemented); }
|
|
Result<Value> Object::add(const Float&) const { return ERROR(NotImplemented); }
|
|
|
|
Result<Value> Object::sub(const Object&) const { return ERROR(NotImplemented); }
|
|
Result<Value> Object::sub_inv(const Int64&) const {
|
|
return ERROR(NotImplemented);
|
|
}
|
|
Result<Value> Object::sub_inv(const Float&) const {
|
|
return ERROR(NotImplemented);
|
|
}
|
|
|
|
Result<Value> Object::mul(const Object&) const { return ERROR(NotImplemented); }
|
|
Result<Value> Object::mul(const Int64&) const { return ERROR(NotImplemented); }
|
|
Result<Value> Object::mul(const Float&) const { return ERROR(NotImplemented); }
|
|
|
|
Result<Value> Object::div(const Object&) const { return ERROR(NotImplemented); }
|
|
Result<Value> Object::div_inv(const Int64&) const {
|
|
return ERROR(NotImplemented);
|
|
}
|
|
Result<Value> Object::div_inv(const Float&) const {
|
|
return ERROR(NotImplemented);
|
|
}
|
|
|
|
Result<Value> Int64::add(const Object& rhs) const { return rhs.add(*this); }
|
|
Result<Value> Int64::add(const Int64& rhs) const {
|
|
return Value(TRY(Int64::create(value() + rhs.value())));
|
|
}
|
|
|
|
Result<Value> Int64::add(const Float& rhs) const {
|
|
return Value(TRY(Float::create(value() + rhs.value())));
|
|
}
|
|
|
|
Result<Value> Int64::mul(const Object& rhs) const { return rhs.mul(*this); }
|
|
Result<Value> Int64::mul(const Int64& rhs) const {
|
|
return Value(TRY(Int64::create(value() * rhs.value())));
|
|
}
|
|
Result<Value> Int64::mul(const Float& rhs) const {
|
|
return Value(TRY(Float::create(value() * rhs.value())));
|
|
}
|
|
|
|
Result<Value> Int64::sub(const Object& rhs) const { return rhs.sub_inv(*this); }
|
|
Result<Value> Int64::sub_inv(const Int64& rhs) const {
|
|
return Value(TRY(Int64::create(rhs.value() - value())));
|
|
}
|
|
Result<Value> Int64::sub_inv(const Float& rhs) const {
|
|
return Value(TRY(Int64::create(rhs.value() - float(value()))));
|
|
}
|
|
|
|
Result<Value> Int64::div(const Object& rhs) const { return rhs.div_inv(*this); }
|
|
Result<Value> 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<Value> Int64::div_inv(const Float& rhs) const {
|
|
if (value() == 0) return ERROR(DivisionByZero);
|
|
return Value(TRY(Float::create(rhs.value() / float(value()))));
|
|
}
|
|
|
|
Result<Value> Float::add(const Object& rhs) const { return rhs.add(*this); }
|
|
Result<Value> Float::add(const Float& rhs) const {
|
|
return Value(TRY(Float::create(value() + rhs.value())));
|
|
}
|
|
|
|
Result<Value> Float::add(const Int64& rhs) const {
|
|
return Value(TRY(Float::create(value() + float(rhs.value()))));
|
|
}
|
|
|
|
Result<Value> Float::mul(const Object& rhs) const { return rhs.mul(*this); }
|
|
Result<Value> Float::mul(const Float& rhs) const {
|
|
return Value(TRY(Float::create(value() * rhs.value())));
|
|
}
|
|
Result<Value> Float::mul(const Int64& rhs) const {
|
|
return Value(TRY(Float::create(value() * float(rhs.value()))));
|
|
}
|
|
|
|
Result<Value> Float::sub(const Object& rhs) const { return rhs.sub_inv(*this); }
|
|
Result<Value> Float::sub_inv(const Float& rhs) const {
|
|
return Value(TRY(Float::create(rhs.value() - value())));
|
|
}
|
|
Result<Value> Float::sub_inv(const Int64& rhs) const {
|
|
return Value(TRY(Float::create(float(rhs.value()) - value())));
|
|
}
|
|
|
|
Result<Value> Float::div(const Object& rhs) const { return rhs.div_inv(*this); }
|
|
Result<Value> Float::div_inv(const Float& rhs) const {
|
|
if (value() == 0) return ERROR(DivisionByZero);
|
|
return Value(TRY(Float::create(rhs.value() / value())));
|
|
}
|
|
|
|
Result<Value> Float::div_inv(const Int64& rhs) const {
|
|
if (value() == 0) return ERROR(DivisionByZero);
|
|
return Value(TRY(Float::create(float(rhs.value()) / value())));
|
|
}
|
|
Result<short> Int64::cmp(const Float& rhs) const {
|
|
return (_value->value > rhs._value->value) -
|
|
(_value->value < rhs._value->value);
|
|
}
|
|
Result<short> Float::cmp(const Int64& rhs) const {
|
|
return (_value->value > rhs._value->value) -
|
|
(_value->value < rhs._value->value);
|
|
}
|
|
|
|
Result<short> 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<short> 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<Value> Object::get(const Value& key) const {
|
|
return ERROR(TypeMismatch);
|
|
}
|
|
|
|
Result<Value> Object::set_value(const Value& key, const Value& value) const {
|
|
return ERROR(TypeMismatch);
|
|
}
|
|
|
|
Result<Value> Object::first() const { return ERROR(TypeMismatch); }
|
|
Result<Value> Object::second() const { return ERROR(TypeMismatch); }
|
|
Result<Value> Object::third() const { return ERROR(TypeMismatch); }
|
|
|
|
Result<Value> Object::rest() const { return ERROR(TypeMismatch); }
|
|
|
|
Result<uint64_t> Object::size() const { return ERROR(TypeMismatch); }
|
|
|
|
Result<bool> syntax_is_list(const Value& value) {
|
|
if (!value.is<Syntax>()) return value.is<Pair>() || value.is<Nil>();
|
|
|
|
auto val = TRY(value.to<Syntax>()->expression());
|
|
return val.is<Pair>() || val.is<Nil>();
|
|
}
|
|
|
|
Result<bool> syntax_is_nil(const Value& value) {
|
|
if (!value.is<Syntax>()) return value.is<Nil>();
|
|
|
|
auto val = TRY(value.to<Syntax>()->expression());
|
|
return val.is<Nil>();
|
|
}
|
|
|
|
Result<Value> syntax_unwrap(const Value& value) {
|
|
if (!value.is<Syntax>()) return value.copy();
|
|
|
|
return TRY(value.to<Syntax>()->expression());
|
|
}
|
|
|
|
Result<Value> syntax_unwrap_all(const Value& value) {
|
|
if (value.is<Syntax>()) {
|
|
auto val = TRY(value.to<Syntax>()->expression());
|
|
return syntax_unwrap_all(val);
|
|
}
|
|
|
|
if (value.is<Pair>()) {
|
|
auto res = Value(TRY(Nil::create()));
|
|
auto cur = TRY(value.copy());
|
|
|
|
while (!cur.is<Nil>()) {
|
|
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<Value> Syntax::first() const {
|
|
auto val = TRY(expression());
|
|
return val.first();
|
|
}
|
|
Result<Value> Syntax::second() const {
|
|
auto val = TRY(expression());
|
|
return val.second();
|
|
}
|
|
Result<Value> Syntax::third() const {
|
|
auto val = TRY(expression());
|
|
return val.third();
|
|
}
|
|
Result<Value> Syntax::rest() const {
|
|
auto val = TRY(expression());
|
|
return val.rest();
|
|
}
|
|
Result<uint64_t> Syntax::size() const {
|
|
auto val = TRY(expression());
|
|
return val.size();
|
|
}
|
|
|
|
Result<String> build_string(const String& value) { return value.copy(); }
|
|
|
|
Result<String> build_string(const Value& value) {
|
|
if (value.is<String>()) {
|
|
return value.to<String>()->copy();
|
|
}
|
|
|
|
return write_one(value);
|
|
}
|
|
|
|
Result<String> build_string(const char* value) { return String::create(value); }
|
|
|
|
Result<String> build_string(int64_t value) {
|
|
auto val = Value(TRY(Int64::create(value)));
|
|
return write_one(val);
|
|
}
|
|
|
|
Result<String> build_string(uint64_t value) {
|
|
auto val = Value(TRY(Int64::create((int64_t)value)));
|
|
return write_one(val);
|
|
}
|
|
|
|
Result<void> 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<void>();
|
|
}
|