fully functional closure

This commit is contained in:
Li Haokun 2021-08-11 14:54:17 +08:00 committed by GitHub
parent e3f3bd7387
commit 35fc848672
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 90 additions and 82 deletions

View File

@ -829,7 +829,7 @@ But in this new interpreter, it will get:
[codegen] in <test.nas>: error(s) occurred,stop. [codegen] in <test.nas>: error(s) occurred,stop.
``` ```
This difference is caused by different kinds of ways of lexical analysis. (outdated)This difference is caused by different kinds of ways of lexical analysis.
In most script language interpreters, they use dynamic analysis to check if this symbol is defined yet. In most script language interpreters, they use dynamic analysis to check if this symbol is defined yet.
However, this kind of analysis is at the cost of lower efficiency. However, this kind of analysis is at the cost of lower efficiency.
To make sure the interpreter runs at higher efficiency, i choose static analysis to manage the memory space of each symbol. To make sure the interpreter runs at higher efficiency, i choose static analysis to manage the memory space of each symbol.

View File

@ -115,7 +115,7 @@ void execute(std::string& file,std::string& command)
} }
int main(int argc,const char* argv[]) int main(int argc,const char* argv[])
{ {
std::string command,file="null"; std::string command,file;
if(argc==2 && (!strcmp(argv[1],"-v") || !strcmp(argv[1],"--version"))) if(argc==2 && (!strcmp(argv[1],"-v") || !strcmp(argv[1],"--version")))
logo(); logo();
else if(argc==2 && (!strcmp(argv[1],"-h") || !strcmp(argv[1],"--help"))) else if(argc==2 && (!strcmp(argv[1],"-h") || !strcmp(argv[1],"--help")))

View File

@ -51,7 +51,7 @@ struct nasal_func// 120 bytes
uint32_t entry; // pc will set to entry-1 to call this function uint32_t entry; // pc will set to entry-1 to call this function
std::vector<nasal_val*> default_para;// default value(nasal_val*) std::vector<nasal_val*> default_para;// default value(nasal_val*)
std::unordered_map<std::string,int> key_table;// parameter name hash std::unordered_map<std::string,int> key_table;// parameter name hash
std::vector<nasal_val*> closure;// closure will be loaded to gc.local.back() as the local scope nasal_val* closure;// closure will be loaded to gc.local.back() as the local scope
nasal_func(); nasal_func();
void clear(); void clear();
@ -214,7 +214,6 @@ void nasal_func::clear()
dynpara=-1; dynpara=-1;
default_para.clear(); default_para.clear();
key_table.clear(); key_table.clear();
closure.clear();
return; return;
} }
@ -272,7 +271,7 @@ struct nasal_gc
std::vector<nasal_val*> str_addrs; // reserved address for const vm_str std::vector<nasal_val*> str_addrs; // reserved address for const vm_str
std::vector<nasal_val*> memory; // gc memory std::vector<nasal_val*> memory; // gc memory
std::queue <nasal_val*> free_list[vm_type_size]; // gc free list std::queue <nasal_val*> free_list[vm_type_size]; // gc free list
std::list<std::vector<nasal_val*>> local; std::vector<nasal_val*> local;
void mark(); void mark();
void sweep(); void sweep();
void gc_init(std::vector<double>&,std::vector<std::string>&); void gc_init(std::vector<double>&,std::vector<std::string>&);
@ -285,9 +284,8 @@ struct nasal_gc
void nasal_gc::mark() void nasal_gc::mark()
{ {
std::queue<nasal_val*> bfs; std::queue<nasal_val*> bfs;
for(auto& i:local) for(auto i:local)
for(auto j:i) bfs.push(i);
bfs.push(j);
for(nasal_val** i=val_stack;i<=stack_top;++i) for(nasal_val** i=val_stack;i<=stack_top;++i)
bfs.push(*i); bfs.push(*i);
while(!bfs.empty()) while(!bfs.empty())
@ -307,8 +305,7 @@ void nasal_gc::mark()
bfs.push(i.second); bfs.push(i.second);
break; break;
case vm_func: case vm_func:
for(auto i:tmp->ptr.func->closure) bfs.push(tmp->ptr.func->closure);
bfs.push(i);
for(auto i:tmp->ptr.func->default_para) for(auto i:tmp->ptr.func->default_para)
if(i) if(i)
bfs.push(i); bfs.push(i);

View File

@ -245,7 +245,12 @@ inline void nasal_vm::opr_intg()
} }
inline void nasal_vm::opr_intl() inline void nasal_vm::opr_intl()
{ {
stack_top[0]->ptr.func->closure.resize(imm[pc],gc.nil_addr); auto& vec=stack_top[0]->ptr.func->closure->ptr.vec->elems;
// if many functions share the same closure
// resize will break the size of vector and cause exe_bad_access
// so choose the maximum size as the size of this closure
if(vec.size()<imm[pc])
vec.resize(imm[pc],gc.nil_addr);
return; return;
} }
inline void nasal_vm::opr_offset() inline void nasal_vm::opr_offset()
@ -260,7 +265,7 @@ inline void nasal_vm::opr_loadg()
} }
inline void nasal_vm::opr_loadl() inline void nasal_vm::opr_loadl()
{ {
gc.local.back()[imm[pc]]=(stack_top--)[0]; gc.local.back()->ptr.vec->elems[imm[pc]]=(stack_top--)[0];
return; return;
} }
inline void nasal_vm::opr_pnum() inline void nasal_vm::opr_pnum()
@ -309,8 +314,9 @@ inline void nasal_vm::opr_newf()
{ {
(++stack_top)[0]=gc.gc_alloc(vm_func); (++stack_top)[0]=gc.gc_alloc(vm_func);
stack_top[0]->ptr.func->entry=imm[pc]; stack_top[0]->ptr.func->entry=imm[pc];
stack_top[0]->ptr.func->closure=gc.nil_addr;
if(gc.local.empty()) if(gc.local.empty())
stack_top[0]->ptr.func->closure.push_back(gc.nil_addr);// me stack_top[0]->ptr.func->closure=gc.gc_alloc(vm_vec);
else else
stack_top[0]->ptr.func->closure=gc.local.back();// local contains 'me' stack_top[0]->ptr.func->closure=gc.local.back();// local contains 'me'
return; return;
@ -557,7 +563,7 @@ inline void nasal_vm::opr_callg()
} }
inline void nasal_vm::opr_calll() inline void nasal_vm::opr_calll()
{ {
(++stack_top)[0]=gc.local.back()[imm[pc]]; (++stack_top)[0]=gc.local.back()->ptr.vec->elems[imm[pc]];
return; return;
} }
inline void nasal_vm::opr_callv() inline void nasal_vm::opr_callv()
@ -584,7 +590,7 @@ inline void nasal_vm::opr_callv()
return; return;
} }
if(stack_top[0]->type==vm_func) if(stack_top[0]->type==vm_func)
stack_top[0]->ptr.func->closure[0]=val;// me stack_top[0]->ptr.func->closure->ptr.vec->elems[0]=val;// me
} }
else if(vec_addr->type==vm_str) else if(vec_addr->type==vm_str)
{ {
@ -632,7 +638,7 @@ inline void nasal_vm::opr_callh()
return; return;
} }
if(stack_top[0]->type==vm_func) if(stack_top[0]->type==vm_func)
stack_top[0]->ptr.func->closure[0]=val;// me stack_top[0]->ptr.func->closure->ptr.vec->elems[0]=val;// me
return; return;
} }
inline void nasal_vm::opr_callfv() inline void nasal_vm::opr_callfv()
@ -648,10 +654,11 @@ inline void nasal_vm::opr_callfv()
} }
// push new local scope // push new local scope
auto& ref_func=*func_addr->ptr.func; auto& ref_func=*func_addr->ptr.func;
gc.local.push_back(ref_func.closure); gc.local.push_back(gc.gc_alloc(vm_vec));
gc.local.back()->ptr.vec->elems=ref_func.closure->ptr.vec->elems;
// load parameters // load parameters
auto& ref_default=ref_func.default_para; auto& ref_default=ref_func.default_para;
auto& ref_closure=gc.local.back(); auto& ref_closure=gc.local.back()->ptr.vec->elems;
uint32_t offset=ref_func.offset; uint32_t offset=ref_func.offset;
uint32_t para_size=ref_func.key_table.size(); uint32_t para_size=ref_func.key_table.size();
@ -694,10 +701,11 @@ inline void nasal_vm::opr_callfh()
} }
// push new local scope // push new local scope
auto& ref_func=*func_addr->ptr.func; auto& ref_func=*func_addr->ptr.func;
gc.local.push_back(ref_func.closure); gc.local.push_back(gc.gc_alloc(vm_vec));
gc.local.back()->ptr.vec->elems=ref_func.closure->ptr.vec->elems;
// load parameters // load parameters
auto& ref_default=ref_func.default_para; auto& ref_default=ref_func.default_para;
auto& ref_closure=gc.local.back(); auto& ref_closure=gc.local.back()->ptr.vec->elems;
if(ref_func.dynpara>=0) if(ref_func.dynpara>=0)
{ {
@ -725,7 +733,7 @@ inline void nasal_vm::opr_callfh()
} }
inline void nasal_vm::opr_callb() inline void nasal_vm::opr_callb()
{ {
(++stack_top)[0]=(*builtin_func[imm[pc]].func)(gc.local.back(),gc); (++stack_top)[0]=(*builtin_func[imm[pc]].func)(gc.local.back()->ptr.vec->elems,gc);
if(!stack_top[0]) if(!stack_top[0])
die("native function error."); die("native function error.");
return; return;
@ -796,7 +804,7 @@ inline void nasal_vm::opr_mcallg()
} }
inline void nasal_vm::opr_mcalll() inline void nasal_vm::opr_mcalll()
{ {
mem_addr=&gc.local.back()[imm[pc]]; mem_addr=&(gc.local.back()->ptr.vec->elems[imm[pc]]);
(++stack_top)[0]=mem_addr[0]; (++stack_top)[0]=mem_addr[0];
return; return;
} }
@ -851,9 +859,13 @@ inline void nasal_vm::opr_mcallh()
} }
inline void nasal_vm::opr_ret() inline void nasal_vm::opr_ret()
{ {
auto& vec=stack_top[-1]->ptr.func->closure->ptr.vec->elems;
for(uint32_t i=0;i<stack_top[-1]->ptr.func->offset;++i)
vec[i]=gc.local.back()->ptr.vec->elems[i];
vec[0]=gc.nil_addr;// set 'me' to nil
gc.local.pop_back();// delete local scope gc.local.pop_back();// delete local scope
pc=ret.top();ret.pop();// fetch pc pc=ret.top();ret.pop();// fetch pc
(--stack_top)[0]->ptr.func->closure[0]=gc.nil_addr;// set 'me' to nil --stack_top;
stack_top[0]=stack_top[1];// rewrite nasal_func with returned value stack_top[0]=stack_top[1];// rewrite nasal_func with returned value
return; return;
} }

View File

@ -2,65 +2,65 @@
# valkmjolnir 2021/3/31 # valkmjolnir 2021/3/31
var list=func() var list=func()
{ {
var _={begin:nil,end:nil}; var (begin,end)=(nil,nil);
return return
{ {
push_back:func(elem) push_back:func(elem)
{ {
var tmp={elem:elem,prev:nil,next:nil}; var tmp={elem:elem,prev:nil,next:nil};
if(_.end!=nil) if(end!=nil)
{ {
_.end.next=tmp; end.next=tmp;
tmp.prev=_.end; tmp.prev=end;
_.end=tmp; end=tmp;
} }
else else
_.begin=_.end=tmp; begin=end=tmp;
return; return;
}, },
push_front:func(elem) push_front:func(elem)
{ {
var tmp={elem:elem,prev:nil,next:nil}; var tmp={elem:elem,prev:nil,next:nil};
if(_.begin!=nil) if(begin!=nil)
{ {
_.begin.prev=tmp; begin.prev=tmp;
tmp.next=_.begin; tmp.next=begin;
_.begin=tmp; begin=tmp;
} }
else else
_.begin=_.end=tmp; begin=end=tmp;
return; return;
}, },
pop_back:func() pop_back:func()
{ {
if(_.end!=nil) if(end!=nil)
_.end=_.end.prev; end=end.prev;
if(_.end==nil) if(end==nil)
_.begin=nil; begin=nil;
else else
_.end.next=nil; end.next=nil;
return; return;
}, },
pop_front:func() pop_front:func()
{ {
if(_.begin!=nil) if(begin!=nil)
_.begin=_.begin.next; begin=begin.next;
if(_.begin==nil) if(begin==nil)
_.end=nil; end=nil;
else else
_.begin.prev=nil; begin.prev=nil;
return; return;
}, },
front:func() front:func()
{ {
if(_.begin!=nil) if(begin!=nil)
return _.begin.elem; return begin.elem;
return nil; return nil;
}, },
back:func() back:func()
{ {
if(_.end!=nil) if(end!=nil)
return _.end.elem; return end.elem;
return nil; return nil;
}, },
}; };

View File

@ -2,7 +2,7 @@
# valkmjolnir 2021/3/31 # valkmjolnir 2021/3/31
var queue=func() var queue=func()
{ {
var _={begin:nil,end:nil}; var (begin,end)=(nil,nil);
return return
{ {
push:func(elem) push:func(elem)
@ -12,35 +12,35 @@ var queue=func()
elem:elem, elem:elem,
next:nil next:nil
}; };
if(_.begin==nil) if(begin==nil)
_.begin=_.end=new_node; begin=end=new_node;
else else
{ {
_.end.next=new_node; end.next=new_node;
_.end=new_node; end=new_node;
} }
return; return;
}, },
pop:func() pop:func()
{ {
if(_.begin!=nil) if(begin!=nil)
_.begin=_.begin.next; begin=begin.next;
if(_.begin==nil) if(begin==nil)
_.end=nil; end=nil;
}, },
front:func() front:func()
{ {
if(_.begin!=nil) if(begin!=nil)
return _.begin.elem; return begin.elem;
return nil; return nil;
}, },
clear:func() clear:func()
{ {
_.begin=_.end=nil; begin=end=nil;
}, },
empty:func() empty:func()
{ {
return _.begin==nil; return begin==nil;
} }
}; };
} }

View File

@ -2,35 +2,35 @@
# valkmjolnir 2021/3/31 # valkmjolnir 2021/3/31
var stack=func() var stack=func()
{ {
var _={next:nil}; var next=nil;
return return
{ {
push:func(elem) push:func(elem)
{ {
_.next={elem:elem,next:_.next}; next={elem:elem,next:next};
return; return;
}, },
pop:func() pop:func()
{ {
var tmp=_.next; var tmp=next;
if(tmp!=nil) if(tmp!=nil)
_.next=tmp.next; next=tmp.next;
return; return;
}, },
top:func() top:func()
{ {
var tmp=_.next; var tmp=next;
if(tmp!=nil) if(tmp!=nil)
return tmp.elem; return tmp.elem;
return nil; return nil;
}, },
clear:func() clear:func()
{ {
_.next=nil; next=nil;
}, },
empty:func() empty:func()
{ {
return _.next==nil; return next==nil;
} }
}; };
} }

View File

@ -3,6 +3,7 @@ import("stl/queue.nas");
rand(time(0)); rand(time(0));
var pixel=[' ','#','.','*'];
var map=[]; var map=[];
for(var i=0;i<10;i+=1) for(var i=0;i<10;i+=1)
{ {
@ -17,7 +18,7 @@ var prt=func()
for(var i=0;i<10;i+=1) for(var i=0;i<10;i+=1)
{ {
for(var j=0;j<10;j+=1) for(var j=0;j<10;j+=1)
s~=map[i][j]; s~=pixel[map[i][j]];
s~='\n'; s~='\n';
} }
s~='----------\n'; s~='----------\n';
@ -29,7 +30,7 @@ var bfs=func(begin,end)
var move=[[1,0],[0,1],[-1,0],[0,-1]]; var move=[[1,0],[0,1],[-1,0],[0,-1]];
var que=queue(); var que=queue();
que.push(begin); que.push(begin);
map[begin[0]][begin[1]]=3; map[begin[0]][begin[1]]=2;
while(!que.empty()) while(!que.empty())
{ {
var vertex=que.front(); var vertex=que.front();
@ -40,13 +41,14 @@ var bfs=func(begin,end)
var y=vertex[1]+i[1]; var y=vertex[1]+i[1];
if(x==end[0] and y==end[1]) if(x==end[0] and y==end[1])
{ {
map[x][y]='*'; map[x][y]=3;
prt();
return; return;
} }
if(0<=x and x<10 and 0<=y and y<10 and map[x][y]==0) if(0<=x and x<10 and 0<=y and y<10 and map[x][y]==0)
{ {
que.push([x,y]); que.push([x,y]);
map[x][y]=3; map[x][y]=2;
} }
} }
prt(); prt();

View File

@ -2,16 +2,13 @@ import("lib.nas");
var student=func(name,age) var student=func(name,age)
{ {
var val={ var (n,a)=(name,age);
name:name,
age:age
};
return { return {
print_info:func(){println(val.name,' ',val.age);}, print_info:func println(n,' ',a),
set_age: func(age){val.age=age;}, set_age: func(age) a=age,
get_age: func(){return val.age;}, get_age: func return a,
set_name: func(name){val.name=name;}, set_name: func(name) n=name,
get_name: func(){return val.name;} get_name: func return n
}; };
} }
var s=student('valk',24); var s=student('valk',24);

View File

@ -14,5 +14,5 @@ var fib=func(f){
} }
); );
for(var i=1;i<=20;i+=1) for(var i=1;i<31;i+=1)
println(fib(i)); println(fib(i));