finish caller
Some checks are pending
Nasal Interpreter Test / mac-aarch64 (push) Waiting to run
Nasal Interpreter Test / linux-x86_64 (push) Waiting to run

Signed-off-by: ValKmjolnir <lhk101lhk101@qq.com>
This commit is contained in:
ValKmjolnir
2025-10-24 00:03:43 +08:00
parent f04996201a
commit 72933f4bf6
9 changed files with 3759 additions and 3721 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,169 +1,169 @@
#pragma once #pragma once
#include <unordered_map> #include <unordered_map>
#include "nasal.h" #include "nasal.h"
#include "nasal_ast.h" #include "nasal_ast.h"
#include "nasal_lexer.h" #include "nasal_lexer.h"
#include "nasal_err.h" #include "nasal_err.h"
namespace nasal { namespace nasal {
class parse { class parse {
#define thisspan (toks[ptr].loc) #define thisspan (toks[ptr].loc)
#define prevspan (ptr!=0? toks[ptr-1].loc:toks[ptr].loc) #define prevspan (ptr!=0? toks[ptr-1].loc:toks[ptr].loc)
private: private:
u64 ptr; u64 ptr;
u64 in_func_depth; // count function block u64 in_func_depth; // count function block
u64 in_loop_depth; // count loop block u64 in_loop_depth; // count loop block
const token* toks; const token* toks;
code_block* root; code_block* root;
error err; error err;
private: private:
const std::unordered_map<tok, std::string> token_name_mapper = { const std::unordered_map<tok, std::string> token_name_mapper = {
{tok::tk_true , "true" }, {tok::tk_true , "true" },
{tok::tk_false , "false" }, {tok::tk_false , "false" },
{tok::tk_use , "use" }, {tok::tk_use , "use" },
{tok::tk_for , "for" }, {tok::tk_for , "for" },
{tok::tk_forindex, "forindex"}, {tok::tk_forindex, "forindex"},
{tok::tk_foreach , "foreach" }, {tok::tk_foreach , "foreach" },
{tok::tk_while , "while" }, {tok::tk_while , "while" },
{tok::tk_var , "var" }, {tok::tk_var , "var" },
{tok::tk_func , "func" }, {tok::tk_func , "func" },
{tok::tk_brk , "break" }, {tok::tk_brk , "break" },
{tok::tk_cont , "continue"}, {tok::tk_cont , "continue"},
{tok::tk_ret , "return" }, {tok::tk_ret , "return" },
{tok::tk_if , "if" }, {tok::tk_if , "if" },
{tok::tk_elsif , "elsif" }, {tok::tk_elsif , "elsif" },
{tok::tk_else , "else" }, {tok::tk_else , "else" },
{tok::tk_nil , "nil" }, {tok::tk_nil , "nil" },
{tok::tk_lcurve , "(" }, {tok::tk_lcurve , "(" },
{tok::tk_rcurve , ")" }, {tok::tk_rcurve , ")" },
{tok::tk_lbracket, "[" }, {tok::tk_lbracket, "[" },
{tok::tk_rbracket, "]" }, {tok::tk_rbracket, "]" },
{tok::tk_lbrace , "{" }, {tok::tk_lbrace , "{" },
{tok::tk_rbrace , "}" }, {tok::tk_rbrace , "}" },
{tok::tk_semi , ";" }, {tok::tk_semi , ";" },
{tok::tk_and , "and" }, {tok::tk_and , "and" },
{tok::tk_or , "or" }, {tok::tk_or , "or" },
{tok::tk_comma , "," }, {tok::tk_comma , "," },
{tok::tk_dot , "." }, {tok::tk_dot , "." },
{tok::tk_ellipsis, "..." }, {tok::tk_ellipsis, "..." },
{tok::tk_quesmark, "?" }, {tok::tk_quesmark, "?" },
{tok::tk_quesques, "??" }, {tok::tk_quesques, "??" },
{tok::tk_quesdot , "?." }, {tok::tk_quesdot , "?." },
{tok::tk_colon , ":" }, {tok::tk_colon , ":" },
{tok::tk_add , "+" }, {tok::tk_add , "+" },
{tok::tk_sub , "-" }, {tok::tk_sub , "-" },
{tok::tk_mult , "*" }, {tok::tk_mult , "*" },
{tok::tk_div , "/" }, {tok::tk_div , "/" },
{tok::tk_floater , "~" }, {tok::tk_floater , "~" },
{tok::tk_btand , "&" }, {tok::tk_btand , "&" },
{tok::tk_btor , "|" }, {tok::tk_btor , "|" },
{tok::tk_btxor , "^" }, {tok::tk_btxor , "^" },
{tok::tk_not , "!" }, {tok::tk_not , "!" },
{tok::tk_eq , "=" }, {tok::tk_eq , "=" },
{tok::tk_addeq , "+=" }, {tok::tk_addeq , "+=" },
{tok::tk_subeq , "-=" }, {tok::tk_subeq , "-=" },
{tok::tk_multeq , "*=" }, {tok::tk_multeq , "*=" },
{tok::tk_diveq , "/=" }, {tok::tk_diveq , "/=" },
{tok::tk_lnkeq , "~=" }, {tok::tk_lnkeq , "~=" },
{tok::tk_btandeq , "&=" }, {tok::tk_btandeq , "&=" },
{tok::tk_btoreq , "|=" }, {tok::tk_btoreq , "|=" },
{tok::tk_btxoreq , "^=" }, {tok::tk_btxoreq , "^=" },
{tok::tk_cmpeq , "==" }, {tok::tk_cmpeq , "==" },
{tok::tk_neq , "!=" }, {tok::tk_neq , "!=" },
{tok::tk_less , "<" }, {tok::tk_less , "<" },
{tok::tk_leq , "<=" }, {tok::tk_leq , "<=" },
{tok::tk_grt , ">" }, {tok::tk_grt , ">" },
{tok::tk_geq , ">=" } {tok::tk_geq , ">=" }
}; };
private: private:
void die(const span&, const std::string&); void die(const span&, const std::string&);
void next(); void next();
void match(tok, const char* info = nullptr); void match(tok, const char* info = nullptr);
bool lookahead(tok); bool lookahead(tok);
bool lookahead_expression(); bool lookahead_expression();
bool is_call(tok); bool is_call(tok);
bool check_comma(const tok*); bool check_comma(const tok*);
bool check_tuple(); bool check_tuple();
bool check_func_end(expr*); bool check_func_end(expr*);
bool check_in_curve_multi_definition(); bool check_in_curve_multi_definition();
bool check_special_call(); bool check_special_call();
bool need_semi_check(expr*); bool need_semi_check(expr*);
void update_location(expr*); void update_location(expr*);
private: private:
use_stmt* use_stmt_gen(); use_stmt* use_stmt_gen();
null_expr* null(); null_expr* null();
nil_expr* nil(); nil_expr* nil();
number_literal* num(); number_literal* num();
string_literal* str(); string_literal* str();
identifier* id(); identifier* id();
bool_literal* bools(); bool_literal* bools();
vector_expr* vec(); vector_expr* vec();
hash_expr* hash(); hash_expr* hash();
hash_pair* pair(); hash_pair* pair();
function* func(); function* func();
void params(function*); void params(function*);
expr* lcurve_expr(); expr* lcurve_expr();
expr* expression(); expr* expression();
code_block* expression_block(); code_block* expression_block();
expr* calc(); expr* calc();
expr* bitwise_or(); expr* bitwise_or();
expr* bitwise_xor(); expr* bitwise_xor();
expr* bitwise_and(); expr* bitwise_and();
expr* or_expr(); expr* or_expr();
expr* and_expr(); expr* and_expr();
expr* cmp_expr(); expr* cmp_expr();
expr* null_chain_expr(); expr* null_chain_expr();
expr* additive_expr(); expr* additive_expr();
expr* multive_expr(); expr* multive_expr();
unary_operator* unary(); unary_operator* unary();
expr* scalar(); expr* scalar();
call* call_scalar(); call* call_scalar();
call_hash* callh(); call_hash* callh();
null_access* null_access_call(); null_access* null_access_call();
call_vector* callv(); call_vector* callv();
call_function* callf(); call_function* callf();
slice_vector* subvec(); slice_vector* subvec();
expr* definition(); expr* definition();
multi_identifier* incurve_def(); multi_identifier* incurve_def();
multi_identifier* outcurve_def(); multi_identifier* outcurve_def();
multi_identifier* multi_id(); multi_identifier* multi_id();
tuple_expr* multi_scalar(); tuple_expr* multi_scalar();
multi_assign* multi_assignment(); multi_assign* multi_assignment();
expr* loop(); expr* loop();
while_expr* while_loop(); while_expr* while_loop();
for_expr* for_loop(); for_expr* for_loop();
forei_expr* forei_loop(); forei_expr* forei_loop();
iter_expr* iter_gen(); iter_expr* iter_gen();
condition_expr* cond(); condition_expr* cond();
continue_expr* continue_expression(); continue_expr* continue_expression();
break_expr* break_expression(); break_expr* break_expression();
return_expr* return_expression(); return_expr* return_expression();
public: public:
code_block* tree() {return root;} code_block* tree() {return root;}
// swap root pointer with another pointer(maybe nullptr) // swap root pointer with another pointer(maybe nullptr)
code_block* swap(code_block* another) { code_block* swap(code_block* another) {
auto res = root; auto res = root;
root = another; root = another;
return res; return res;
} }
public: public:
parse(): ptr(0), in_func_depth(0), parse(): ptr(0), in_func_depth(0),
in_loop_depth(0), toks(nullptr), in_loop_depth(0), toks(nullptr),
root(nullptr) {} root(nullptr) {}
~parse() {delete root;} ~parse() {delete root;}
const error& compile(const lexer&); const error& compile(const lexer&);
static void easter_egg(); static void easter_egg();
}; };
} }

View File

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

View File

@@ -1,368 +1,398 @@
#pragma once #pragma once
#include "nasal.h" #include "nasal.h"
#include "util/util.h" #include "util/util.h"
#include <cstring> #include <cstring>
#include <sstream> #include <sstream>
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
namespace nasal { namespace nasal {
enum class vm_type: u8 { enum class vm_type: u8 {
/* none-gc object */ /* none-gc object */
vm_none = 0, // error type vm_none = 0, // error type
vm_cnt, // counter for forindex/foreach loop vm_cnt, // counter for forindex/foreach loop
vm_addr, // var* address vm_addr, // var* address
vm_ret, // return addres(program counter) vm_ret, // return addres(program counter)
vm_nil, // nil vm_nil, // nil
vm_num, // number vm_num, // number
/* gc object */ /* gc object */
vm_str, // string vm_str, // string
vm_vec, // vector vm_vec, // vector
vm_hash, // hashmap(dict) vm_hash, // hashmap(dict)
vm_func, // function(lambda) vm_func, // function(lambda)
vm_upval, // upvalue vm_upval, // upvalue
vm_ghost, // ghost type vm_ghost, // ghost type
vm_co, // coroutine vm_co, // coroutine
vm_map, // for globals and namespaces vm_map, // for globals and namespaces
/* mark type range */ /* mark type range */
vm_type_size_max vm_type_size_max
}; };
// size of gc object type // size of gc object type
const u32 GC_TYPE_SIZE = const u32 GC_TYPE_SIZE =
static_cast<u32>(vm_type::vm_type_size_max) - static_cast<u32>(vm_type::vm_type_size_max) -
static_cast<u32>(vm_type::vm_str); static_cast<u32>(vm_type::vm_str);
// basic types // basic types
struct nas_vec; // vector struct nas_vec; // vector
struct nas_hash; // hashmap(dict) struct nas_hash; // hashmap(dict)
struct nas_func; // function(lambda) struct nas_func; // function(lambda)
struct nas_upval; // upvalue struct nas_upval; // upvalue
struct nas_ghost; // objects struct nas_ghost; // objects
struct nas_co; // coroutine struct nas_co; // coroutine
struct nas_map; // mapper struct nas_map; // mapper
// nas_val includes gc-managed types // nas_val includes gc-managed types
struct nas_val { struct nas_val {
enum class gc_status: u8 { enum class gc_status: u8 {
uncollected = 0, uncollected = 0,
collected, collected,
found found
}; };
gc_status mark; gc_status mark;
vm_type type; // value type vm_type type; // value type
u8 immutable; // used to mark if a string is immutable u8 immutable; // used to mark if a string is immutable
union elem { union elem {
std::string* str; std::string* str;
nas_vec* vec; nas_vec* vec;
nas_hash* hash; nas_hash* hash;
nas_func* func; nas_func* func;
nas_upval* upval; nas_upval* upval;
nas_ghost* obj; nas_ghost* obj;
nas_co* co; nas_co* co;
nas_map* map; nas_map* map;
} ptr; } ptr;
nas_val(vm_type); nas_val(vm_type);
~nas_val(); ~nas_val();
void clear(); void clear();
}; };
struct var { struct var {
public: public:
vm_type type = vm_type::vm_none; vm_type type = vm_type::vm_none;
union { union {
u64 ret; u64 ret;
i64 cnt; i64 cnt;
f64 num; f64 num;
var* addr; var* addr;
nas_val* gcobj; nas_val* gcobj;
} val; } val;
private: private:
var(vm_type t, u64 pc) { type = t; val.ret = pc; } var(vm_type t, u64 pc) { type = t; val.ret = pc; }
var(vm_type t, i64 ct) { type = t; val.cnt = ct; } var(vm_type t, i64 ct) { type = t; val.cnt = ct; }
var(vm_type t, f64 n) { type = t; val.num = n; } var(vm_type t, f64 n) { type = t; val.num = n; }
var(vm_type t, var* p) { type = t; val.addr = p; } var(vm_type t, var* p) { type = t; val.addr = p; }
var(vm_type t, nas_val* p) { type = t; val.gcobj = p; } var(vm_type t, nas_val* p) { type = t; val.gcobj = p; }
public: public:
var() = default; var() = default;
var(const var&) = default; var(const var&) = default;
bool operator==(const var& nr) const { bool operator==(const var& nr) const {
return type == nr.type && val.gcobj == nr.val.gcobj; return type == nr.type && val.gcobj == nr.val.gcobj;
} }
bool operator!=(const var& nr) const { bool operator!=(const var& nr) const {
return type != nr.type || val.gcobj != nr.val.gcobj; return type != nr.type || val.gcobj != nr.val.gcobj;
} }
public: public:
// create new var object // create new var object
static var none() { static var none() {
return var(vm_type::vm_none, static_cast<u64>(0)); return var(vm_type::vm_none, static_cast<u64>(0));
} }
static var nil() { static var nil() {
return var(vm_type::vm_nil, static_cast<u64>(0)); return var(vm_type::vm_nil, static_cast<u64>(0));
} }
static var ret(u64 pc) { static var ret(u64 pc) {
return var(vm_type::vm_ret, pc); return var(vm_type::vm_ret, pc);
} }
static var cnt(i64 n) { static var cnt(i64 n) {
return var(vm_type::vm_cnt, n); return var(vm_type::vm_cnt, n);
} }
static var num(f64 n) { static var num(f64 n) {
return var(vm_type::vm_num, n); return var(vm_type::vm_num, n);
} }
static var gcobj(nas_val* p) { static var gcobj(nas_val* p) {
return var(p->type, p); return var(p->type, p);
} }
static var addr(var* p) { static var addr(var* p) {
return var(vm_type::vm_addr, p); return var(vm_type::vm_addr, p);
} }
public: public:
// get value // get value
var* addr() const { return val.addr; } var* addr() const { return val.addr; }
u64 ret() const { return val.ret; } u64 ret() const { return val.ret; }
i64& cnt() { return val.cnt; } i64& cnt() { return val.cnt; }
f64 num() const { return val.num; } f64 num() const { return val.num; }
public: public:
// get gc object // get gc object
std::string& str() { return *val.gcobj->ptr.str; } std::string& str() { return *val.gcobj->ptr.str; }
nas_vec& vec() { return *val.gcobj->ptr.vec; } nas_vec& vec() { return *val.gcobj->ptr.vec; }
nas_hash& hash() { return *val.gcobj->ptr.hash; } nas_hash& hash() { return *val.gcobj->ptr.hash; }
nas_func& func() { return *val.gcobj->ptr.func; } nas_func& func() { return *val.gcobj->ptr.func; }
nas_upval& upval() { return *val.gcobj->ptr.upval; } nas_upval& upval() { return *val.gcobj->ptr.upval; }
nas_ghost& ghost() { return *val.gcobj->ptr.obj; } nas_ghost& ghost() { return *val.gcobj->ptr.obj; }
nas_co& co() { return *val.gcobj->ptr.co; } nas_co& co() { return *val.gcobj->ptr.co; }
nas_map& map() { return *val.gcobj->ptr.map; } nas_map& map() { return *val.gcobj->ptr.map; }
public: public:
// get const gc object // get const gc object
const std::string& str() const { return *val.gcobj->ptr.str; } const std::string& str() const { return *val.gcobj->ptr.str; }
const nas_vec& vec() const { return *val.gcobj->ptr.vec; } const nas_vec& vec() const { return *val.gcobj->ptr.vec; }
const nas_hash& hash() const { return *val.gcobj->ptr.hash; } const nas_hash& hash() const { return *val.gcobj->ptr.hash; }
const nas_func& func() const { return *val.gcobj->ptr.func; } const nas_func& func() const { return *val.gcobj->ptr.func; }
const nas_upval& upval() const { return *val.gcobj->ptr.upval; } const nas_upval& upval() const { return *val.gcobj->ptr.upval; }
const nas_ghost& ghost() const { return *val.gcobj->ptr.obj; } const nas_ghost& ghost() const { return *val.gcobj->ptr.obj; }
const nas_co& co() const { return *val.gcobj->ptr.co; } const nas_co& co() const { return *val.gcobj->ptr.co; }
const nas_map& map() const { return *val.gcobj->ptr.map; } const nas_map& map() const { return *val.gcobj->ptr.map; }
public: public:
bool is_none() const { return type == vm_type::vm_none; } bool is_none() const { return type == vm_type::vm_none; }
bool is_cnt() const { return type == vm_type::vm_cnt; } bool is_cnt() const { return type == vm_type::vm_cnt; }
bool is_addr() const { return type == vm_type::vm_addr; } bool is_addr() const { return type == vm_type::vm_addr; }
bool is_ret() const { return type == vm_type::vm_ret; } bool is_ret() const { return type == vm_type::vm_ret; }
bool is_nil() const { return type == vm_type::vm_nil; } bool is_nil() const { return type == vm_type::vm_nil; }
bool is_num() const { return type == vm_type::vm_num; } bool is_num() const { return type == vm_type::vm_num; }
bool is_str() const { return type == vm_type::vm_str; } bool is_str() const { return type == vm_type::vm_str; }
bool is_vec() const { return type == vm_type::vm_vec; } bool is_vec() const { return type == vm_type::vm_vec; }
bool is_hash() const { return type == vm_type::vm_hash; } bool is_hash() const { return type == vm_type::vm_hash; }
bool is_func() const { return type == vm_type::vm_func; } bool is_func() const { return type == vm_type::vm_func; }
bool is_upval() const { return type == vm_type::vm_upval; } bool is_upval() const { return type == vm_type::vm_upval; }
bool is_ghost() const { return type == vm_type::vm_ghost; } bool is_ghost() const { return type == vm_type::vm_ghost; }
bool is_coroutine() const { return type == vm_type::vm_co; } bool is_coroutine() const { return type == vm_type::vm_co; }
bool is_map() const { return type == vm_type::vm_map; } bool is_map() const { return type == vm_type::vm_map; }
public: public:
// convert to number // convert to number
f64 to_num() const { f64 to_num() const {
return type != vm_type::vm_str return type != vm_type::vm_str
? val.num ? val.num
: util::str_to_num(str().c_str()); : util::str_to_num(str().c_str());
} }
// convert to string // convert to string
std::string to_str(); std::string to_str();
inline bool object_check(const std::string&) const; inline bool object_check(const std::string&) const;
friend std::ostream& operator<<(std::ostream&, var&); friend std::ostream& operator<<(std::ostream&, var&);
}; };
struct nas_vec { struct nas_vec {
std::vector<var> elems; std::vector<var> elems;
// mark if this is printed, avoid stack overflow // mark if this is printed, avoid stack overflow
bool printed = false; bool printed = false;
auto size() const { return elems.size(); } auto size() const { return elems.size(); }
var get_value(const i32 index) { var get_value(const i32 index) {
i32 size = elems.size(); i32 size = elems.size();
if (index < -size || index >= size) { if (index < -size || index >= size) {
return var::none(); return var::none();
} }
return elems[index >= 0 ? index : index + size]; return elems[index >= 0 ? index : index + size];
} }
var* get_memory(const i32 index) { var* get_memory(const i32 index) {
i32 size = elems.size(); i32 size = elems.size();
if (index < -size || index >= size) { if (index < -size || index >= size) {
return nullptr; return nullptr;
} }
return &elems[index >= 0 ? index : index + size]; return &elems[index >= 0 ? index : index + size];
} }
friend std::ostream& operator<<(std::ostream&, nas_vec&); friend std::ostream& operator<<(std::ostream&, nas_vec&);
}; };
struct nas_hash { struct nas_hash {
std::unordered_map<std::string, var> elems; std::unordered_map<std::string, var> elems;
// mark if this is printed, avoid stack overflow // mark if this is printed, avoid stack overflow
bool printed = false; bool printed = false;
auto size() const { return elems.size(); } auto size() const { return elems.size(); }
var get_value(const std::string&); var get_value(const std::string&);
var* get_memory(const std::string&); var* get_memory(const std::string&);
friend std::ostream& operator<<(std::ostream&, nas_hash&); friend std::ostream& operator<<(std::ostream&, nas_hash&);
}; };
struct nas_func { struct nas_func {
i64 dynamic_parameter_index; // dynamic parameter name index in hash. i64 dynamic_parameter_index; // dynamic parameter name index in hash.
u64 entry; // pc will set to entry-1 to call this function u64 entry; // pc will set to entry-1 to call this function
u32 parameter_size; // used to load default parameters to a new function u32 parameter_size; // used to load default parameters to a new function
u64 local_size; // used to expand memory space for local values on stack u64 local_size; // used to expand memory space for local values on stack
std::vector<var> local; // local scope with default value(var) std::vector<var> local; // local scope with default value(var)
std::vector<var> upval; // closure std::vector<var> upval; // closure
// parameter table, u32 begins from 1 // parameter table, u32 begins from 1
std::unordered_map<std::string, u32> keys; std::unordered_map<std::string, u32> keys;
// dynamic parameter name // dynamic parameter name
std::string dynamic_parameter_name; std::string dynamic_parameter_name;
nas_func(): nas_func():
dynamic_parameter_index(-1), entry(0), dynamic_parameter_index(-1), entry(0),
parameter_size(0), local_size(0), parameter_size(0), local_size(0),
dynamic_parameter_name("") {} dynamic_parameter_name("") {}
void clear(); void clear();
friend std::ostream& operator<<(std::ostream&, nas_func&); friend std::ostream& operator<<(std::ostream&, nas_func&);
}; };
struct nas_upval { struct nas_upval {
public: public:
/* on stack, use these variables */ /* on stack, use these variables */
bool on_stack; bool on_stack;
u64 size; u64 size;
var* stack_frame_offset; var* stack_frame_offset;
/* not on stack, use this */ /* not on stack, use this */
std::vector<var> elems; std::vector<var> elems;
public: public:
nas_upval(): on_stack(true), size(0), stack_frame_offset(nullptr) {} nas_upval(): on_stack(true), size(0), stack_frame_offset(nullptr) {}
var& operator[](usize n) { var& operator[](usize n) {
return on_stack? stack_frame_offset[n] : elems[n]; return on_stack? stack_frame_offset[n] : elems[n];
} }
void clear() { void clear() {
on_stack = true; on_stack = true;
elems.clear(); elems.clear();
size = 0; size = 0;
} }
}; };
struct nas_ghost { struct nas_ghost {
private: private:
using destructor = void (*)(void*); using destructor = void (*)(void*);
using marker = void (*)(void*, std::vector<var>*); using marker = void (*)(void*, std::vector<var>*);
public: public:
std::string type_name; std::string type_name;
destructor destructor_function; destructor destructor_function;
marker gc_mark_function; marker gc_mark_function;
void* pointer; void* pointer;
public: public:
nas_ghost(): nas_ghost():
type_name(""), destructor_function(nullptr), type_name(""), destructor_function(nullptr),
gc_mark_function(nullptr), pointer(nullptr) {} gc_mark_function(nullptr), pointer(nullptr) {}
~nas_ghost() { clear(); } ~nas_ghost() { clear(); }
void set(const std::string&, destructor, marker, void*); void set(const std::string&, destructor, marker, void*);
void clear(); void clear();
friend std::ostream& operator<<(std::ostream&, const nas_ghost&); friend std::ostream& operator<<(std::ostream&, const nas_ghost&);
public: public:
const auto& get_ghost_name() const { return type_name; } const auto& get_ghost_name() const { return type_name; }
public: public:
template<typename T> template<typename T>
T* get() { return static_cast<T*>(pointer); } T* get() { return static_cast<T*>(pointer); }
template<typename T> template<typename T>
T convert() const { return reinterpret_cast<T>(pointer); } T convert() const { return reinterpret_cast<T>(pointer); }
}; };
struct context { struct callsite {
u64 pc = 0; var caller;
var* localr = nullptr; u64 file_index = 0;
var* memr = nullptr; u64 line = 0;
var funcr = var::nil(); };
var upvalr = var::nil();
var* canary = nullptr; struct context {
u64 pc = 0;
var* stack = nullptr; var* localr = nullptr;
var* top = nullptr; var* memr = nullptr;
var funcr = var::nil();
var* func_stack = nullptr; var upvalr = var::nil();
var* func_top = nullptr; var* canary = nullptr;
};
var* stack = nullptr;
struct nas_co { var* top = nullptr;
enum class status:u32 {
suspended, callsite* func_stack = nullptr;
running, callsite* func_top = nullptr;
dead
}; const std::string* files = nullptr;
context ctx; void ctor() {
status status; stack = new var[VM_STACK_DEPTH];
func_stack = new callsite[VM_STACK_DEPTH];
nas_co() { }
ctx.stack = new var[VM_STACK_DEPTH]; void dtor() {
ctx.func_stack = new var[VM_STACK_DEPTH]; delete[] stack;
clear(); delete[] func_stack;
} }
~nas_co() { void clear() {
delete[] ctx.stack; /* set canary and program counter */
delete[] ctx.func_stack; pc = 0;
} localr = nullptr;
void clear(); memr = nullptr;
friend std::ostream& operator<<(std::ostream&, const nas_co&); funcr = var::nil();
}; upvalr = var::nil();
struct nas_map { /* set canary = stack[VM_STACK_DEPTH-1] */
bool printed = false; canary = stack + VM_STACK_DEPTH - 1;
std::unordered_map<std::string, var*> mapper;
/* nothing is on stack */
public: top = stack;
void clear() { func_top = func_stack - 1;
mapper.clear();
} /* clear main stack */
auto size() const { return mapper.size(); } for (u32 i = 0; i < VM_STACK_DEPTH; ++i) {
stack[i] = var::nil();
var get_value(const std::string&); }
var* get_memory(const std::string&); }
friend std::ostream& operator<<(std::ostream&, nas_map&); };
};
struct nas_co {
const var zero = var::num(0); enum class status:u32 {
const var one = var::num(1); suspended,
const var nil = var::nil(); running,
dead
inline bool var::object_check(const std::string& name) const { };
return is_ghost() && ghost().type_name == name && ghost().pointer;
} context ctx;
status status;
// use to print error log and return error value
static var nas_err(const std::string& func, const std::string& info) { nas_co() { ctx.ctor(); }
std::cerr << "[vm] " << func << ": " << info << "\n"; ~nas_co() { ctx.dtor(); }
return var::none(); void clear() { ctx.clear(); status = status::suspended; }
} friend std::ostream& operator<<(std::ostream&, const nas_co&);
};
struct nas_map {
bool printed = false;
std::unordered_map<std::string, var*> mapper;
public:
void clear() {
mapper.clear();
}
auto size() const { return mapper.size(); }
var get_value(const std::string&);
var* get_memory(const std::string&);
friend std::ostream& operator<<(std::ostream&, nas_map&);
};
const var zero = var::num(0);
const var one = var::num(1);
const var nil = var::nil();
inline bool var::object_check(const std::string& name) const {
return is_ghost() && ghost().type_name == name && ghost().pointer;
}
// use to print error log and return error value
static var nas_err(const std::string& func, const std::string& info) {
std::cerr << "[vm] " << func << ": " << info << "\n";
return var::none();
}
} }

File diff suppressed because it is too large Load Diff

View File

@@ -287,13 +287,11 @@ public:
/* constructor of vm instance */ /* constructor of vm instance */
vm() { vm() {
ctx.stack = new var[VM_STACK_DEPTH]; ctx.ctor();
ctx.func_stack = new var[VM_STACK_DEPTH];
global = new var[VM_STACK_DEPTH]; global = new var[VM_STACK_DEPTH];
} }
~vm() { ~vm() {
delete[] ctx.stack; ctx.dtor();
delete[] ctx.func_stack;
delete[] global; delete[] global;
} }
@@ -902,7 +900,11 @@ inline void vm::o_callfv() {
var tmp = local[-1]; var tmp = local[-1];
local[-1] = ctx.funcr; local[-1] = ctx.funcr;
ctx.funcr = tmp; ctx.funcr = tmp;
(++ctx.func_top)[0] = tmp; (++ctx.func_top)[0] = {
tmp,
bytecode[ctx.pc].fidx,
bytecode[ctx.pc].line
};
// top-argc+lsize(local) +1(old pc) +1(old localr) +1(old upvalr) // top-argc+lsize(local) +1(old pc) +1(old localr) +1(old upvalr)
if (ctx.top-argc+func.local_size+3>=ctx.canary) { if (ctx.top-argc+func.local_size+3>=ctx.canary) {
@@ -972,7 +974,11 @@ inline void vm::o_callfh() {
var tmp = ctx.top[-1]; var tmp = ctx.top[-1];
ctx.top[-1] = ctx.funcr; ctx.top[-1] = ctx.funcr;
ctx.funcr = tmp; ctx.funcr = tmp;
(++ctx.func_top)[0] = tmp; (++ctx.func_top)[0] = {
tmp,
bytecode[ctx.pc].fidx,
bytecode[ctx.pc].line
};
// top -1(hash) +lsize(local) +1(old pc) +1(old localr) +1(old upvalr) // top -1(hash) +lsize(local) +1(old pc) +1(old localr) +1(old upvalr)
if (ctx.top+func.local_size+2>= ctx.canary) { if (ctx.top+func.local_size+2>= ctx.canary) {
@@ -1015,6 +1021,9 @@ inline void vm::o_callb() {
// this code is written for coroutine // this code is written for coroutine
(++ctx.top)[0] = nil; (++ctx.top)[0] = nil;
// set file list into ctx
ctx.files = files;
// if running a native function about coroutine // if running a native function about coroutine
// (top) will be set to another context.top, instead of main_context.top // (top) will be set to another context.top, instead of main_context.top
auto function_pointer = native_function[imm[ctx.pc]].func; auto function_pointer = native_function[imm[ctx.pc]].func;

File diff suppressed because it is too large Load Diff

24
test/caller.nas Normal file
View File

@@ -0,0 +1,24 @@
var a = func(x, y, z) {
for (var i = 0; i < 20; i += 1) {
var cl = caller(i);
if (cl == nil) {
return;
}
print("[", i, "]\t", cl[1], "\t -> called from ", cl[2], ":", cl[3], "\n");
}
}
var b = func(x, y) {
a(1, 2, 3);
}
var c = func(x) b(1, 2);
var d = func c(1);
var e = func d();
var f = func e();
var g = func f();
var h = func g();
var i = func h();
var j = func i();
j();

View File

@@ -109,7 +109,7 @@ for (var t = 0; t < 10; t += 1) {
counter += 1; counter += 1;
for (var i = 0; i < t + 1; i += 1) for (var i = 0; i < t + 1; i += 1)
coroutine.resume(co); coroutine.resume(co);
if (counter - int(counter / 1000) * 1000 == 0) { if (counter - int(counter / 2500) * 2500 == 0) {
var rate = counter / 2e5; var rate = counter / 2e5;
print(" ", bar.bar(rate), " ", print(" ", bar.bar(rate), " ",
padding.leftpad(str(int(rate*100)),3), "% | ", padding.leftpad(str(int(rate*100)),3), "% | ",
@@ -120,7 +120,7 @@ for (var t = 0; t < 10; t += 1) {
} }
tm.stamp(); tm.stamp();
for (var i = 0; i < 1e5; i += 1) for (var i = 0; i < 2e5; i += 1)
consumer(); consumer();
println(" ", bar.bar(1), " 100% | ", println(" ", bar.bar(1), " 100% | ",
str(int(1e3 * counter / tm.elapsedMSec())), str(int(1e3 * counter / tm.elapsedMSec())),