Nasal-Interpreter/src/nasal_type.cpp

300 lines
8.2 KiB
C++

#include "nasal_type.h"
#include "util/util.h"
#include <cstring>
#include <sstream>
namespace nasal {
std::ostream& operator<<(std::ostream& out, nas_vec& vec) {
if (!vec.elems.size() || vec.printed) {
out << (vec.elems.size()? "[..]":"[]");
return out;
}
vec.printed = true;
usize iter = 0, size = vec.elems.size();
out << "[";
for(auto& i:vec.elems) {
out << i << ",]"[(++iter)==size];
}
vec.printed = false;
return out;
}
var nas_hash::get_value(const std::string& key) {
if (elems.count(key)) {
return elems.at(key);
}
if (!elems.count("parents")) {
return var::none();
}
auto ret = var::none();
auto& val = elems.at("parents");
if (!val.is_vec()) {
return ret;
}
for(auto& i : val.vec().elems) {
if (i.is_hash()) {
ret = i.hash().get_value(key);
}
if (!ret.is_none()) {
return ret;
}
}
return ret;
}
var* nas_hash::get_memory(const std::string& key) {
if (elems.count(key)) {
return &elems.at(key);
}
if (!elems.count("parents")) {
return nullptr;
}
var* addr = nullptr;
var& val = elems.at("parents");
if (!val.is_vec()) {
return addr;
}
for(auto& i : val.vec().elems) {
// recursively search key in `parents`
if (i.is_hash()) {
addr = i.hash().get_memory(key);
}
if (addr) {
return addr;
}
}
return addr;
}
std::ostream& operator<<(std::ostream& out, nas_hash& hash) {
if (!hash.elems.size() || hash.printed) {
out << (hash.elems.size()? "{..}":"{}");
return out;
}
// mark print, to avoid infinite recursion
hash.printed = true;
static const char* sep[] = {", ", "}"};
usize iter = 0, size = hash.elems.size();
out << "{";
for(auto& i : hash.elems) {
out << i.first << ": " << i.second << sep[(++iter)==size];
}
// restore flag
hash.printed = false;
return out;
}
std::ostream& operator<<(std::ostream& out, nas_func& func) {
out << "func(";
std::vector<std::string> argument_list = {};
argument_list.resize(func.keys.size());
for(const auto& key : func.keys) {
argument_list[key.second-1] = key.first;
}
for(const auto& key : argument_list) {
out << key;
if (key != argument_list.back()) {
out << ", ";
}
}
if (func.dynamic_parameter_index>=0) {
out << (argument_list.size()? ", ":"");
out << func.dynamic_parameter_name << "...";
}
out << ") {..}";
return out;
}
void nas_func::clear() {
dynamic_parameter_index = -1;
local.clear();
upval.clear();
keys.clear();
}
void nas_ghost::set(const std::string& ghost_type_name,
destructor destructor_pointer,
marker gc_marker_pointer,
void* ghost_pointer) {
type_name = ghost_type_name;
destructor_function = destructor_pointer;
gc_mark_function = gc_marker_pointer;
pointer = ghost_pointer;
}
void nas_ghost::clear() {
// do nothing if pointer is null
if (!pointer) {
return;
}
// do clear pointer if destructor function pointer is null
if (!destructor_function) {
type_name = "";
pointer = nullptr;
return;
}
// do destruction
destructor_function(pointer);
type_name = "";
pointer = nullptr;
destructor_function = nullptr;
gc_mark_function = nullptr;
}
std::ostream& operator<<(std::ostream& out, const nas_ghost& ghost) {
out << "<" << ghost.get_ghost_name();
out << "@0x" << std::hex << ghost.convert<u64>() << std::dec << ">";
return out;
}
void nas_co::clear() {
if (!ctx.stack) {
return;
}
for(u32 i = 0; i<VM_STACK_DEPTH; ++i) {
ctx.stack[i] = var::nil();
}
ctx.pc = 0;
ctx.localr = nullptr;
ctx.memr = nullptr;
ctx.canary = ctx.stack+VM_STACK_DEPTH-1;
ctx.top = ctx.stack;
ctx.funcr = var::nil();
ctx.upvalr = var::nil();
status = status::suspended;
}
std::ostream& operator<<(std::ostream& out, const nas_co& co) {
out << "<coroutine at 0x" << std::hex;
out << reinterpret_cast<u64>(&co) << std::dec << ">";
return out;
}
var nas_map::get_value(const std::string& key) {
if (mapper.count(key)) {
return *mapper.at(key);
}
return var::none();
}
var* nas_map::get_memory(const std::string& key) {
if (mapper.count(key)) {
return mapper.at(key);
}
return nullptr;
}
std::ostream& operator<<(std::ostream& out, nas_map& mp) {
if (!mp.mapper.size() || mp.printed) {
out << (mp.mapper.size()? "{..}":"{}");
return out;
}
// mark print, to avoid infinite recursion
mp.printed = true;
static const char* sep[] = {", ", "}"};
usize iter = 0, size = mp.mapper.size();
out << "{";
for(auto& i : mp.mapper) {
out << i.first << ": " << *i.second << sep[(++iter)==size];
}
// restore flag
mp.printed = false;
return out;
}
nas_val::nas_val(vm_type val_type) {
mark = gc_status::collected;
type = val_type;
immutable = 0;
switch(val_type) {
case vm_type::vm_str: ptr.str = new std::string; break;
case vm_type::vm_vec: ptr.vec = new nas_vec; break;
case vm_type::vm_hash: ptr.hash = new nas_hash; break;
case vm_type::vm_func: ptr.func = new nas_func; break;
case vm_type::vm_upval: ptr.upval = new nas_upval; break;
case vm_type::vm_ghost: ptr.obj = new nas_ghost; break;
case vm_type::vm_co: ptr.co = new nas_co; break;
case vm_type::vm_map: ptr.map = new nas_map; break;
default: break;
}
}
nas_val::~nas_val() {
switch(type) {
case vm_type::vm_str: delete ptr.str; break;
case vm_type::vm_vec: delete ptr.vec; break;
case vm_type::vm_hash: delete ptr.hash; break;
case vm_type::vm_func: delete ptr.func; break;
case vm_type::vm_upval: delete ptr.upval; break;
case vm_type::vm_ghost: delete ptr.obj; break;
case vm_type::vm_co: delete ptr.co; break;
case vm_type::vm_map: delete ptr.map; break;
default: break;
}
type = vm_type::vm_nil;
}
void nas_val::clear() {
switch(type) {
case vm_type::vm_str: ptr.str->clear(); break;
case vm_type::vm_vec: ptr.vec->elems.clear(); break;
case vm_type::vm_hash: ptr.hash->elems.clear(); break;
case vm_type::vm_func: ptr.func->clear(); break;
case vm_type::vm_upval: ptr.upval->clear(); break;
case vm_type::vm_ghost: ptr.obj->clear(); break;
case vm_type::vm_co: ptr.co->clear(); break;
case vm_type::vm_map: ptr.map->clear(); break;
default: break;
}
}
std::string var::to_str() {
if (type==vm_type::vm_str) {
return str();
} else if (type==vm_type::vm_num) {
auto tmp = std::to_string(num());
tmp.erase(tmp.find_last_not_of('0') + 1, std::string::npos);
tmp.erase(tmp.find_last_not_of('.') + 1, std::string::npos);
return tmp;
}
std::stringstream ss;
ss << *this;
return ss.str();
}
std::ostream& operator<<(std::ostream& out, var& ref) {
switch(ref.type) {
case vm_type::vm_none: out << "undefined"; break;
case vm_type::vm_nil: out << "nil"; break;
case vm_type::vm_num: out << ref.val.num; break;
case vm_type::vm_str: out << ref.str(); break;
case vm_type::vm_vec: out << ref.vec(); break;
case vm_type::vm_hash: out << ref.hash(); break;
case vm_type::vm_func: out << ref.func(); break;
case vm_type::vm_ghost: out << ref.ghost(); break;
case vm_type::vm_co: out << ref.co(); break;
case vm_type::vm_map: out << ref.map(); break;
default: break;
}
return out;
}
}