🧑‍💻 add important symbol "globals"

This commit is contained in:
ValKmjolnir 2023-07-06 22:10:07 +08:00
parent eca6141408
commit b4482792c8
11 changed files with 381 additions and 243 deletions

View File

@ -100,6 +100,7 @@ test:nasal
-@ ./nasal -d test/exception.nas
@ ./nasal -t -d test/fib.nas
@ ./nasal -e test/filesystem.nas
@ ./nasal -t -d test/globals_test.nas
@ ./nasal -d test/hexdump.nas
@ ./nasal -e test/json.nas
@ ./nasal -e test/leetcode1319.nas

View File

@ -334,15 +334,21 @@ var builtin_delete(var* local, gc& ngc) {
var builtin_keys(var* local, gc& ngc) {
var hash=local[1];
if (hash.type!=vm_hash) {
if (hash.type!=vm_hash && hash.type!=vm_map) {
return nas_err("keys", "\"hash\" must be hash");
}
// avoid being sweeped
var res=ngc.temp=ngc.alloc(vm_vec);
auto& vec=res.vec().elems;
for(auto& iter:hash.hash().elems) {
if (hash.type==vm_hash) {
for(const auto& iter : hash.hash().elems) {
vec.push_back(ngc.newstr(iter.first));
}
} else {
for(const auto& iter : hash.map().mapper) {
vec.push_back(ngc.newstr(iter.first));
}
}
ngc.temp=nil;
return res;
}
@ -372,6 +378,7 @@ var builtin_type(var* local, gc& ngc) {
case vm_func: return ngc.newstr("func"); break;
case vm_obj: return ngc.newstr("obj"); break;
case vm_co: return ngc.newstr("coroutine");break;
case vm_map: return ngc.newstr("mapper"); break;
}
return nil;
}

View File

@ -1091,6 +1091,7 @@ const error& codegen::compile(parse& parse, linker& import) {
fileindex = 0;
file = import.filelist().data();
in_iterloop.push(0);
add_symbol("globals");
find_symbol(parse.tree()); // search symbols first
gen(op_intg, global.size(), 0);
block_gen(parse.tree()); // generate main block

View File

@ -97,6 +97,7 @@ public:
const std::vector<std::string>& strs() const {return const_string_table;}
const std::vector<f64>& nums() const {return const_number_table;}
const std::vector<opcode>& codes() const {return code;}
const std::unordered_map<std::string, i32>& globals() const {return global;}
public:
codegen(error& e): fileindex(0), err(e), file(nullptr) {}

View File

@ -163,7 +163,12 @@ void dbg::run(
const std::vector<std::string>& argv) {
verbose=true;
fsize=linker.filelist().size();
init(gen.strs(), gen.nums(), gen.codes(), linker.filelist(), argv);
init(gen.strs(),
gen.nums(),
gen.codes(),
gen.globals(),
linker.filelist(),
argv);
u64 count[op_ret+1]={0};
typedef void (dbg::*nafunc)();
const nafunc oprs[]={

View File

@ -153,6 +153,35 @@ void nas_co::clear() {
status = coroutine_status::suspended;
}
var nas_map::get_val(const std::string& key) {
if (mapper.count(key)) {
return *mapper.at(key);
}
return var::none();
}
var* nas_map::get_mem(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;
}
mp.printed = true;
usize iter = 0, size = mp.mapper.size();
out << "{";
for(auto& i : mp.mapper) {
out << i.first << ":" << *i.second << ",}"[(++iter)==size];
}
mp.printed = false;
return out;
}
nas_val::nas_val(u8 val_type) {
mark = gc_status::collected;
type = val_type;
@ -165,6 +194,7 @@ nas_val::nas_val(u8 val_type) {
case vm_upval: ptr.upval = new nas_upval; break;
case vm_obj: ptr.obj = new nas_ghost; break;
case vm_co: ptr.co = new nas_co; break;
case vm_map: ptr.map = new nas_map; break;
}
}
@ -177,6 +207,7 @@ nas_val::~nas_val() {
case vm_upval:delete ptr.upval;break;
case vm_obj: delete ptr.obj; break;
case vm_co: delete ptr.co; break;
case vm_map: delete ptr.map; break;
}
type=vm_nil;
}
@ -190,6 +221,7 @@ void nas_val::clear() {
case vm_upval:ptr.upval->clear(); break;
case vm_obj: ptr.obj->clear(); break;
case vm_co: ptr.co->clear(); break;
case vm_map: ptr.map->clear(); break;
}
}
@ -220,6 +252,7 @@ std::ostream& operator<<(std::ostream& out, var& ref) {
case vm_func: out << "func(..) {..}"; break;
case vm_obj: out << ref.obj(); break;
case vm_co: out << "<coroutine>"; break;
case vm_map: out << ref.map(); break;
}
return out;
}
@ -300,6 +333,10 @@ nas_co& var::co() {
return *val.gcobj->ptr.co;
}
nas_map& var::map() {
return *val.gcobj->ptr.map;
}
void gc::mark() {
std::vector<var> bfs;
mark_context(bfs);
@ -345,6 +382,7 @@ void gc::mark_var(std::vector<var>& bfs_queue, var& value) {
case vm_func: mark_func(bfs_queue, value.func()); break;
case vm_upval: mark_upval(bfs_queue, value.upval()); break;
case vm_co: mark_co(bfs_queue, value.co()); break;
case vm_map: mark_map(bfs_queue, value.map()); break;
default: break;
}
}
@ -384,6 +422,12 @@ void gc::mark_co(std::vector<var>& bfs_queue, nas_co& co) {
}
}
void gc::mark_map(std::vector<var>& bfs_queue, nas_map& mp) {
for(const auto& i : mp.mapper) {
bfs_queue.push_back(*i.second);
}
}
void gc::sweep() {
for(auto i : memory) {
if (i->mark==gc_status::uncollected) {
@ -469,7 +513,8 @@ void gc::info() {
"function ",
"upvalue ",
"object ",
"coroutine"
"coroutine",
"mapper "
};
usize indent = 0;

View File

@ -47,10 +47,11 @@ enum vm_type:u8 {
vm_func,
vm_upval,
vm_obj,
vm_co
vm_co,
vm_map // for globals, arg
};
const u32 gc_type_size = vm_co-vm_str+1;
const u32 gc_type_size = vm_map-vm_str+1;
enum class coroutine_status:u32 {
suspended,
@ -70,6 +71,7 @@ struct nas_func; // function(lambda)
struct nas_upval; // upvalue
struct nas_ghost; // objects
struct nas_co; // coroutine
struct nas_map; // mapper
struct nas_val; // nas_val includes gc-managed types
struct var {
@ -127,6 +129,7 @@ public:
nas_upval& upval();
nas_ghost& obj();
nas_co& co();
nas_map& map();
};
struct nas_vec {
@ -295,6 +298,19 @@ struct nas_co {
void clear();
};
struct nas_map {
bool printed = false;
std::unordered_map<std::string, var*> mapper;
nas_map() {}
void clear() {
mapper.clear();
}
var get_val(const std::string&);
var* get_mem(const std::string&);
};
struct nas_val {
gc_status mark;
u8 type; // value type
@ -307,6 +323,7 @@ struct nas_val {
nas_upval* upval;
nas_ghost* obj;
nas_co* co;
nas_map* map;
} ptr;
nas_val(u8);
@ -316,6 +333,7 @@ struct nas_val {
std::ostream& operator<<(std::ostream&, nas_vec&);
std::ostream& operator<<(std::ostream&, nas_hash&);
std::ostream& operator<<(std::ostream&, nas_map&);
std::ostream& operator<<(std::ostream&, var&);
const var zero = var::num(0);
@ -348,7 +366,8 @@ struct gc {
128, // vm_func
256, // vm_upval
16, // vm_obj
16 // vm_co
16, // vm_co
2, // vm_map
};
/* values for analysis */
@ -372,6 +391,7 @@ private:
void mark_func(std::vector<var>&, nas_func&);
void mark_upval(std::vector<var>&, nas_upval&);
void mark_co(std::vector<var>&, nas_co&);
void mark_map(std::vector<var>&, nas_map&);
void sweep();
public:

View File

@ -4,6 +4,7 @@ void vm::init(
const std::vector<std::string>& strs,
const std::vector<f64>& nums,
const std::vector<opcode>& code,
const std::unordered_map<std::string, i32>& global,
const std::vector<std::string>& filenames,
const std::vector<std::string>& argv
) {
@ -27,6 +28,13 @@ void vm::init(
/* init gc */
ngc.init(strs,argv);
/* init vm globals */
auto map_instance = ngc.alloc(vm_map);
stack[global.at("globals")] = map_instance;
for(const auto& i : global) {
map_instance.map().mapper[i.first] = stack+i.second;
}
}
void vm::valinfo(var& val) {
@ -204,7 +212,12 @@ void vm::run(
const bool detail
) {
verbose=detail;
init(gen.strs(), gen.nums(), gen.codes(), linker.filelist(), argv);
init(gen.strs(),
gen.nums(),
gen.codes(),
gen.globals(),
linker.filelist(),
argv);
#ifndef _MSC_VER
const void* oprs[]={
&&vmexit, &&intg, &&intl, &&loadg,

View File

@ -39,6 +39,7 @@ protected:
const std::vector<std::string>&,
const std::vector<f64>&,
const std::vector<opcode>&,
const std::unordered_map<std::string, i32>&,
const std::vector<std::string>&,
const std::vector<std::string>&);
@ -155,8 +156,7 @@ public:
const codegen&,
const linker&,
const std::vector<std::string>&,
const bool
);
const bool);
};
inline bool vm::cond(var& val) {
@ -172,7 +172,8 @@ inline bool vm::cond(var& val) {
inline void vm::o_intg() {
// global values store on stack
ctx.top += imm[ctx.pc];
--ctx.top;// point to the top
// point to the top
--ctx.top;
}
inline void vm::o_intl() {
@ -223,7 +224,7 @@ inline void vm::o_newh() {
inline void vm::o_newf() {
(++ctx.top)[0] = ngc.alloc(vm_func);
nas_func& func=ctx.top[0].func();
auto& func = ctx.top[0].func();
func.entry = imm[ctx.pc];
func.psize = 1;
@ -246,7 +247,7 @@ inline void vm::o_happ() {
}
inline void vm::o_para() {
nas_func& func=ctx.top[0].func();
auto& func = ctx.top[0].func();
// func->size has 1 place reserved for "me"
func.keys[imm[ctx.pc]] = func.psize;
func.local[func.psize++] = var::none();
@ -254,7 +255,7 @@ inline void vm::o_para() {
inline void vm::o_deft() {
var val = ctx.top[0];
nas_func& func=(--ctx.top)[0].func();
auto& func = (--ctx.top)[0].func();
// func->size has 1 place reserved for "me"
func.keys[imm[ctx.pc]] = func.psize;
func.local[func.psize++] = val;
@ -277,10 +278,9 @@ inline void vm::o_lnot() {
ctx.top[0] = num? zero:one;
}
} break;
default:{
default:
die("incorrect value type");
return;
} break;
}
}
@ -293,17 +293,23 @@ inline void vm::o_bnot() {
}
inline void vm::o_btor() {
ctx.top[-1]=var::num(static_cast<int32_t>(ctx.top[-1].tonum())|static_cast<int32_t>(ctx.top[0].tonum()));
ctx.top[-1] = var::num(
static_cast<int32_t>(ctx.top[-1].tonum())|
static_cast<int32_t>(ctx.top[0].tonum()));
--ctx.top;
}
inline void vm::o_btxor() {
ctx.top[-1]=var::num(static_cast<int32_t>(ctx.top[-1].tonum())^static_cast<int32_t>(ctx.top[0].tonum()));
ctx.top[-1] = var::num(
static_cast<int32_t>(ctx.top[-1].tonum())^
static_cast<int32_t>(ctx.top[0].tonum()));
--ctx.top;
}
inline void vm::o_btand() {
ctx.top[-1]=var::num(static_cast<int32_t>(ctx.top[-1].tonum())&static_cast<int32_t>(ctx.top[0].tonum()));
ctx.top[-1] = var::num(
static_cast<int32_t>(ctx.top[-1].tonum())&
static_cast<int32_t>(ctx.top[0].tonum()));
--ctx.top;
}
@ -556,6 +562,16 @@ inline void vm::o_callv() {
return;
}
ctx.top[0] = var::num(f64((u8)str[num>=0? num:num+len]));
} else if (vec.type==vm_map) {
if (val.type!=vm_str) {
die("must use string as the key");
return;
}
ctx.top[0] = vec.map().get_val(val.str());
if (ctx.top[0].type==vm_none) {
die("cannot find symbol \""+val.str()+"\"");
return;
}
} else {
die("must call a vector/hash/string");
return;
@ -578,13 +594,20 @@ inline void vm::o_callvi() {
inline void vm::o_callh() {
var val = ctx.top[0];
if (val.type!=vm_hash) {
if (val.type!=vm_hash && val.type!=vm_map) {
die("must call a hash");
return;
}
ctx.top[0]=val.hash().get_val(cstr[imm[ctx.pc]]);
const auto& str = cstr[imm[ctx.pc]];
if (val.type==vm_hash) {
ctx.top[0] = val.hash().get_val(str);
} else {
ctx.top[0] = val.map().get_val(str);
}
if (ctx.top[0].type==vm_none) {
die("member \""+cstr[imm[ctx.pc]]+"\" does not exist");
val.type==vm_hash?
die("member \"" + str + "\" does not exist"):
die("cannot find symbol \"" + str + "\"");
return;
} else if (ctx.top[0].type==vm_func) {
ctx.top[0].func().local[0] = val; // 'me'
@ -676,7 +699,7 @@ inline void vm::o_callfh() {
local[i] = func.local[i];
}
for(auto& i:func.keys) {
for(const auto& i : func.keys) {
auto& key = cstr[i.first];
if (hash.count(key)) {
local[i.second] = hash[key];
@ -786,7 +809,10 @@ inline void vm::o_mcalll() {
}
inline void vm::o_mupval() {
ctx.memr=&(ctx.funcr.func().upval[(imm[ctx.pc]>>16)&0xffff].upval()[imm[ctx.pc]&0xffff]);
ctx.memr = &(
ctx.funcr.func()
.upval[(imm[ctx.pc]>>16)&0xffff]
.upval()[imm[ctx.pc]&0xffff]);
(++ctx.top)[0] = ctx.memr[0];
// push value in this memory space on stack
// to avoid being garbage collected
@ -813,6 +839,17 @@ inline void vm::o_mcallv() {
ref.elems[str] = nil;
ctx.memr = ref.get_mem(str);
}
} else if (vec.type==vm_map) {
if (val.type!=vm_str) {
die("key must be string");
return;
}
auto& ref = vec.map();
auto& str = val.str();
ctx.memr = ref.get_mem(str);
if (!ctx.memr) {
die("cannot find symbol \"" + str + "\"");
}
} else {
die("cannot get memory space in this type");
return;
@ -821,12 +858,19 @@ inline void vm::o_mcallv() {
inline void vm::o_mcallh() {
var hash = ctx.top[0]; // mcall hash, reserved on stack to avoid gc
if (hash.type!=vm_hash) {
if (hash.type!=vm_hash && hash.type!=vm_map) {
die("must call a hash");
return;
}
auto& ref=hash.hash();
auto& str = cstr[imm[ctx.pc]];
if (hash.type==vm_map) {
ctx.memr = hash.map().get_mem(str);
if (!ctx.memr) {
die("cannot find symbol \"" + str + "\"");
}
return;
}
auto& ref = hash.hash();
ctx.memr = ref.get_mem(str);
if (!ctx.memr) { // create a new key
ref.elems[str] = nil;

15
test/globals_test.nas Normal file
View File

@ -0,0 +1,15 @@
# test if globals run correctly
println(globals);
println(keys(globals));
foreach(var i; keys(globals)) {
println("var ", i, " = ", typeof(globals[i]), ";");
}
var test_func = nil;
globals.test_func = func() {
println("succeed!");
}
println();
println(globals.test_func);
globals.test_func();

View File

@ -1,5 +1,6 @@
# hexdump.nas by ValKmjolnir
# 2021/8/13
import.std.file;
# init
var hex=func(){
@ -20,22 +21,7 @@ var hex=func(){
# read file
var s=func(){
var filename=[
"main.cpp",
"nasal_ast.h",
"nasal_builtin.h",
"nasal_codegen.h",
"nasal_dbg.h",
"nasal_err.h",
"nasal_gc.h",
"nasal_import.h",
"nasal_lexer.h",
"nasal_opt.h",
"nasal_parse.h",
"nasal_vm.h",
"nasal.ebnf",
"nasal.h"
];
var filename = find_all_files_with_extension("./src","cpp","h");
if(size(runtime.argv())!=0){
var argv=runtime.argv();
if(argv[0]=="-h" or argv[0]=="--h"){