#ifndef __NASAL_GC_H__ #define __NASAL_GC_H__ enum nasal_type { vm_nil=0, vm_num, vm_str, vm_scop, vm_func, vm_vec, vm_hash }; struct nasal_vec; struct nasal_hash; struct nasal_func; struct nasal_scop; struct nasal_val; struct nasal_vec { std::vector elems; void print(); nasal_val* get_val(int); nasal_val** get_mem(int); }; struct nasal_hash { std::unordered_map elems; bool check_contain(std::string&); void print(); nasal_val* get_val(std::string&); nasal_val** get_mem(std::string&); }; struct nasal_func { int dynpara; int entry; std::vector para; std::vector default_para; std::unordered_map closure; nasal_func(); }; struct nasal_scop { std::unordered_map elems; nasal_val* get_val(int); nasal_val** get_mem(int); }; struct nasal_val { bool mark; int type; union { double num; std::string* str; nasal_vec* vec; nasal_hash* hash; nasal_func* func; nasal_scop* scop; }ptr; nasal_val(); nasal_val(int); ~nasal_val(); void clear(); void set_type(int); double to_number(); std::string to_string(); }; /*functions of nasal_vec*/ nasal_val* nasal_vec::get_val(int index) { int vec_size=elems.size(); if(index<-vec_size || index>=vec_size) { std::cout<<">> [gc] nasal_vec::get_val: index out of range: "<=0]]; } nasal_val** nasal_vec::get_mem(int index) { int vec_size=elems.size(); if(index<-vec_size || index>=vec_size) { std::cout<<">> [gc] nasal_vec::get_mem: index out of range: "<=0]]; } void nasal_vec::print() { int size=elems.size(); std::cout<<"["; if(!size) std::cout<<"]"; for(int i=0;itype) { case vm_nil: std::cout<<"nil"; break; case vm_num: std::cout<ptr.num; break; case vm_str: std::cout<<*tmp->ptr.str; break; case vm_vec: tmp->ptr.vec->print(); break; case vm_hash: tmp->ptr.hash->print(); break; case vm_func: std::cout<<"func(...){...}"; break; } std::cout<<",]"[i==size-1]; } return; } /*functions of nasal_hash*/ nasal_val* nasal_hash::get_val(std::string& key) { nasal_val* ret_addr=nullptr; if(elems.count(key)) return elems[key]; else if(elems.count("parents")) { nasal_val* val_addr=elems["parents"]; if(val_addr->type==vm_vec) { std::vector& vec_ref=val_addr->ptr.vec->elems; int size=vec_ref.size(); for(int i=0;itype==vm_hash) ret_addr=tmp->ptr.hash->get_val(key); if(ret_addr) return ret_addr; } } } return ret_addr; } nasal_val** nasal_hash::get_mem(std::string& key) { nasal_val** mem_addr=nullptr; if(elems.count(key)) return &elems[key]; else if(elems.count("parents")) { nasal_val* val_addr=elems["parents"]; if(val_addr->type==vm_vec) { std::vector& vec_ref=val_addr->ptr.vec->elems; int size=vec_ref.size(); for(int i=0;itype==vm_hash) mem_addr=tmp->ptr.hash->get_mem(key); if(mem_addr) return mem_addr; } } } return mem_addr; } bool nasal_hash::check_contain(std::string& key) { if(elems.count(key)) return true; if(elems.count("parents")) { nasal_val* val_addr=elems["parents"]; if(val_addr->type==vm_vec) { bool result=false; std::vector& vec_ref=val_addr->ptr.vec->elems; int size=vec_ref.size(); for(int i=0;itype==vm_hash) result=tmp->ptr.hash->check_contain(key); if(result) return true; } } } return false; } void nasal_hash::print() { std::cout<<'{'; if(!elems.size()) { std::cout<<'}'; return; } for(auto i=elems.begin();i!=elems.end();++i) { std::cout<first<<':'; nasal_val* tmp=i->second; switch(tmp->type) { case vm_nil: std::cout<<"nil"; break; case vm_num: std::cout<ptr.num; break; case vm_str: std::cout<<*tmp->ptr.str; break; case vm_vec: tmp->ptr.vec->print(); break; case vm_hash: tmp->ptr.hash->print(); break; case vm_func: std::cout<<"func(...){...}"; break; } std::cout<<','; } std::cout<<'}'; return; } /*functions of nasal_func*/ nasal_func::nasal_func() { dynpara=-1; return; } /*functions of nasal_scop*/ nasal_val* nasal_scop::get_val(int key) { if(elems.count(key)) return elems[key]; return nullptr; } nasal_val** nasal_scop::get_mem(int key) { if(elems.count(key)) return &(elems[key]); return nullptr; } /*functions of nasal_val*/ nasal_val::nasal_val() { mark=false; type=vm_nil; return; } nasal_val::nasal_val(int val_type) { mark=false; type=val_type; switch(type) { case vm_num: ptr.num=0; break; case vm_str: ptr.str=new std::string; break; case vm_vec: ptr.vec=new nasal_vec; break; case vm_hash: ptr.hash=new nasal_hash; break; case vm_func: ptr.func=new nasal_func; break; case vm_scop: ptr.scop=new nasal_scop; break; } return; } nasal_val::~nasal_val() { switch(type) { case vm_str: delete ptr.str; break; case vm_vec: delete ptr.vec; break; case vm_hash: delete ptr.hash; break; case vm_func: delete ptr.func; break; case vm_scop: delete ptr.scop; break; } type=vm_nil; return; } void nasal_val::clear() { switch(type) { case vm_nil: break; case vm_num: break; case vm_str: delete ptr.str; break; case vm_vec: delete ptr.vec; break; case vm_hash: delete ptr.hash; break; case vm_func: delete ptr.func; break; case vm_scop: delete ptr.scop; break; } type=vm_nil; return; } void nasal_val::set_type(int val_type) { type=val_type; switch(type) { case vm_nil: break; case vm_num: ptr.num=0; break; case vm_str: ptr.str=new std::string; break; case vm_vec: ptr.vec=new nasal_vec; break; case vm_hash: ptr.hash=new nasal_hash; break; case vm_func: ptr.func=new nasal_func; break; case vm_scop: ptr.scop=new nasal_scop; break; } return; } double nasal_val::to_number() { if(type==vm_str) return trans_string_to_number(*ptr.str); return ptr.num; } std::string nasal_val::to_string() { if(type==vm_str) return *ptr.str; else if(type==vm_num) return trans_number_to_string(ptr.num); return ""; } struct nasal_gc { #define STACK_MAX_DEPTH (65536<<4) nasal_val* zero_addr; // reserved address of nasal_val,type vm_num, 0 nasal_val* one_addr; // reserved address of nasal_val,type vm_num, 1 nasal_val* nil_addr; // reserved address of nasal_val,type vm_nil nasal_val* global; // global scope address,type vm_scop nasal_val* val_stack[STACK_MAX_DEPTH]; nasal_val** stack_top; // stack top std::vector num_addrs; // reserved address for const vm_num std::vector local; // local scope for function block std::vector slice_stack; // slice stack for vec[val,val,val:val] std::vector memory; // gc memory std::queue free_list; // gc free list void mark(); void sweep(); void gc_init(std::vector&); void gc_clear(); nasal_val* gc_alloc(int); }; /* gc functions */ void nasal_gc::mark() { std::queue bfs; bfs.push(zero_addr); bfs.push(one_addr); bfs.push(nil_addr); bfs.push(global); int size=num_addrs.size(); for(int i=0;imark) continue; tmp->mark=true; if(tmp->type==vm_vec) { std::vector& vec=tmp->ptr.vec->elems; for(auto i=vec.begin();i!=vec.end();++i) if(!(*i)->mark) bfs.push(*i); } else if(tmp->type==vm_hash) { std::unordered_map& hash=tmp->ptr.hash->elems; for(auto i=hash.begin();i!=hash.end();++i) if(!i->second->mark) bfs.push(i->second); } else if(tmp->type==vm_func) { std::unordered_map& cls=tmp->ptr.func->closure; std::vector& def=tmp->ptr.func->default_para; for(auto i=cls.begin();i!=cls.end();++i) if(!i->second->mark) bfs.push(i->second); for(auto i=def.begin();i!=def.end();++i) if(*i && !(*i)->mark) bfs.push(*i); } else if(tmp->type==vm_scop) { std::unordered_map& scop=tmp->ptr.scop->elems; for(auto i=scop.begin();i!=scop.end();++i) if(!i->second->mark) bfs.push(i->second); } } return; } void nasal_gc::sweep() { int size=memory.size(); for(int i=0;imark) { memory[i]->clear(); free_list.push(memory[i]); } memory[i]->mark=false; } return; } void nasal_gc::gc_init(std::vector& nums) { for(int i=0;i<65536;++i) { nasal_val* tmp=new nasal_val; memory.push_back(tmp); free_list.push(tmp); } stack_top=val_stack; // set stack_top to val_stack zero_addr=new nasal_val(vm_num); // init constant 0 zero_addr->ptr.num=0; memory.push_back(zero_addr); one_addr=new nasal_val(vm_num); // init constant 1 one_addr->ptr.num=1; memory.push_back(one_addr); nil_addr=new nasal_val(vm_nil); // init nil memory.push_back(nil_addr); *val_stack=nil_addr; // the first space will not store any values,but gc checks global=new nasal_val(vm_scop); // init global symbol table memory.push_back(global); num_addrs.clear(); // init constant numbers for(int i=0;iptr.num=nums[i]; num_addrs.push_back(tmp); } return; } void nasal_gc::gc_clear() { int size=memory.size(); for(int i=0;iclear(); delete memory[i]; } memory.clear(); while(!free_list.empty()) free_list.pop(); global=nullptr; local.clear(); slice_stack.clear(); return; } nasal_val* nasal_gc::gc_alloc(int type) { if(free_list.empty()) { mark(); sweep(); } if(free_list.empty()) for(int i=0;i<65536;++i) { nasal_val* tmp=new nasal_val; memory.push_back(tmp); free_list.push(tmp); } nasal_val* ret=free_list.front(); free_list.pop(); ret->set_type(type); return ret; } #endif