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.
```
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.
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.

View File

@ -115,7 +115,7 @@ void execute(std::string& file,std::string& command)
}
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")))
logo();
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
std::vector<nasal_val*> default_para;// default value(nasal_val*)
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();
void clear();
@ -214,7 +214,6 @@ void nasal_func::clear()
dynpara=-1;
default_para.clear();
key_table.clear();
closure.clear();
return;
}
@ -272,7 +271,7 @@ struct nasal_gc
std::vector<nasal_val*> str_addrs; // reserved address for const vm_str
std::vector<nasal_val*> memory; // gc memory
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 sweep();
void gc_init(std::vector<double>&,std::vector<std::string>&);
@ -285,9 +284,8 @@ struct nasal_gc
void nasal_gc::mark()
{
std::queue<nasal_val*> bfs;
for(auto& i:local)
for(auto j:i)
bfs.push(j);
for(auto i:local)
bfs.push(i);
for(nasal_val** i=val_stack;i<=stack_top;++i)
bfs.push(*i);
while(!bfs.empty())
@ -307,8 +305,7 @@ void nasal_gc::mark()
bfs.push(i.second);
break;
case vm_func:
for(auto i:tmp->ptr.func->closure)
bfs.push(i);
bfs.push(tmp->ptr.func->closure);
for(auto i:tmp->ptr.func->default_para)
if(i)
bfs.push(i);

View File

@ -245,7 +245,12 @@ inline void nasal_vm::opr_intg()
}
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;
}
inline void nasal_vm::opr_offset()
@ -260,7 +265,7 @@ inline void nasal_vm::opr_loadg()
}
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;
}
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]->ptr.func->entry=imm[pc];
stack_top[0]->ptr.func->closure=gc.nil_addr;
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
stack_top[0]->ptr.func->closure=gc.local.back();// local contains 'me'
return;
@ -557,7 +563,7 @@ inline void nasal_vm::opr_callg()
}
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;
}
inline void nasal_vm::opr_callv()
@ -584,7 +590,7 @@ inline void nasal_vm::opr_callv()
return;
}
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)
{
@ -632,7 +638,7 @@ inline void nasal_vm::opr_callh()
return;
}
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;
}
inline void nasal_vm::opr_callfv()
@ -648,10 +654,11 @@ inline void nasal_vm::opr_callfv()
}
// push new local scope
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
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 para_size=ref_func.key_table.size();
@ -694,10 +701,11 @@ inline void nasal_vm::opr_callfh()
}
// push new local scope
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
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)
{
@ -725,7 +733,7 @@ inline void nasal_vm::opr_callfh()
}
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])
die("native function error.");
return;
@ -796,7 +804,7 @@ inline void nasal_vm::opr_mcallg()
}
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];
return;
}
@ -851,9 +859,13 @@ inline void nasal_vm::opr_mcallh()
}
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
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
return;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -2,16 +2,13 @@ import("lib.nas");
var student=func(name,age)
{
var val={
name:name,
age:age
};
var (n,a)=(name,age);
return {
print_info:func(){println(val.name,' ',val.age);},
set_age: func(age){val.age=age;},
get_age: func(){return val.age;},
set_name: func(name){val.name=name;},
get_name: func(){return val.name;}
print_info:func println(n,' ',a),
set_age: func(age) a=age,
get_age: func return a,
set_name: func(name) n=name,
get_name: func return n
};
}
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));