add static symbol check & test file update

This commit is contained in:
Valk Richard Li 2021-03-30 15:55:38 +08:00
parent c7316e9780
commit b06e1bb5dd
14 changed files with 158 additions and 260 deletions

View File

@ -10,15 +10,15 @@ nasal_vm vm;
void help()
{
std::cout
<<">> [\"file\"] input a file name. \n"
<<">> [help ] show help. \n"
<<">> [clear ] clear the screen. \n"
<<">> [lex ] use lexer to turn code into tokens. \n"
<<">> [ast ] do parsing and check the abstract syntax tree.\n"
<<">> [code ] show byte code. \n"
<<">> [exec ] execute program on bytecode vm. \n"
<<">> [logo ] print logo of nasal . \n"
<<">> [exit ] quit nasal interpreter. \n";
<<">> [\"file\"] input file name. \n"
<<">> [help ] show help. \n"
<<">> [clear ] clear the screen. \n"
<<">> [lex ] view tokens. \n"
<<">> [ast ] view abstract syntax tree. \n"
<<">> [code ] view byte code. \n"
<<">> [exec ] execute program on bytecode vm. \n"
<<">> [logo ] print logo of nasal . \n"
<<">> [exit ] quit nasal interpreter. \n";
return;
}
@ -39,16 +39,6 @@ void die(std::string stage,std::string filename)
return;
}
void clear()
{
// this will clear the data in lexer/parser/import modules
// to reduce memory footprint
lexer.get_token_list().clear();
parse.get_root().clear();
import.get_root().clear();
return;
}
void execute(std::string& command)
{
lexer.openfile(file);
@ -61,7 +51,6 @@ void execute(std::string& command)
if(command=="lex")
{
lexer.print_token();
clear();
return;
}
parse.set_toklist(lexer.get_token_list());
@ -74,7 +63,6 @@ void execute(std::string& command)
if(command=="ast")
{
parse.get_root().print_ast(0);
clear();
return;
}
import.link(parse.get_root());
@ -84,7 +72,11 @@ void execute(std::string& command)
return;
}
codegen.main_progress(import.get_root());
clear();
if(codegen.get_error())
{
die("codegen",file);
return;
}
if(command=="code")
{
codegen.print_byte_code();

View File

@ -4,7 +4,6 @@
enum op_code
{
op_nop,
op_load,// load value in value_stack to identifier
op_loadg,
op_loadl,
op_pnum,
@ -43,13 +42,12 @@ enum op_code
op_jmp, // jump with no condition
op_jt, // used in operator and/or,jmp when condition is true and DO NOT POP
op_jf, // used in conditional/loop,jmp when condition is false and POP STACK
op_counter, // add counter for forindex/foreach
op_cnt, // add counter for forindex/foreach
op_cntpop, // pop counter
op_findex, // index counter on the top of forindex_stack plus 1
op_feach, // index counter on the top of forindex_stack plus 1 and get the value in vector
op_call, // call identifier
op_callg,
op_calll,
op_callg, // call value in global scope
op_calll, // call value in local scope
op_callv, // call vec[index]
op_callvi, // call vec[immediate] (used in multi-assign/multi-define)
op_callh, // call hash.label
@ -59,11 +57,10 @@ enum op_code
op_slcend, // end of slice
op_slc, // slice like vec[1]
op_slc2, // slice like vec[nil:10]
op_mcall, // get memory of identifier
op_mcallg,
op_mcalll,
op_mcallv, // get memory of vec[index]
op_mcallh, // get memory of hash.label
op_mcallg, // get memory space of value in global scope
op_mcalll, // get memory space of value in local scope
op_mcallv, // get memory space of vec[index]
op_mcallh, // get memory space of hash.label
op_ret // return
};
@ -74,7 +71,6 @@ struct
}code_table[]=
{
{op_nop, "nop "},
{op_load, "load "},
{op_loadg, "loadg "},
{op_loadl, "loadl "},
{op_pnum, "pnum "},
@ -113,11 +109,10 @@ struct
{op_jmp, "jmp "},
{op_jt, "jt "},
{op_jf, "jf "},
{op_counter, "cnt "},
{op_cnt, "cnt "},
{op_cntpop, "cntpop"},
{op_findex, "findx "},
{op_feach, "feach "},
{op_call, "call "},
{op_callg, "callg "},
{op_calll, "calll "},
{op_callv, "callv "},
@ -129,7 +124,6 @@ struct
{op_slcend, "slcend"},
{op_slc, "slc "},
{op_slc2, "slc2 "},
{op_mcall, "mcall "},
{op_mcallg, "mcallg"},
{op_mcalll, "mcalll"},
{op_mcallv, "mcallv"},
@ -172,10 +166,12 @@ private:
std::vector<std::string> global;
std::list<std::vector<std::string> > local;
void die(std::string,int);
void regist_number(double);
void regist_string(std::string&);
void add_sym(std::string&);
bool find_sym(std::string&);
void add_sym(std::string);
bool local_find(std::string&);
bool global_find(std::string&);
void gen(unsigned char,unsigned int);
void pop_gen();
void nil_gen();
@ -212,6 +208,7 @@ private:
void ret_gen(nasal_ast&);
public:
nasal_codegen();
int get_error();
void main_progress(nasal_ast&);
void print_op(int);
void print_byte_code();
@ -228,10 +225,17 @@ nasal_codegen::nasal_codegen()
return;
}
void nasal_codegen::die(std::string info,int line)
{
++error;
std::cout<<">> [code] line "<<line<<": "<<info<<"\n";
return;
}
void nasal_codegen::regist_number(double num)
{
int size=number_table.size();
if(number_table.find(num)==number_table.end())
if(!number_table.count(num))
number_table[num]=size;
return;
}
@ -239,23 +243,47 @@ void nasal_codegen::regist_number(double num)
void nasal_codegen::regist_string(std::string& str)
{
int size=string_table.size();
if(string_table.find(str)==string_table.end())
if(!string_table.count(str))
string_table[str]=size;
return;
}
void nasal_codegen::add_sym(std::string&)
void nasal_codegen::add_sym(std::string name)
{
if(local.empty())
;
{
for(int i=0;i<global.size();++i)
if(global[i]==name)
return;
regist_string(name);
global.push_back(name);
}
else
;
{
for(auto i=local.begin();i!=local.end();++i)
for(int j=0;j<i->size();++j)
if((*i)[j]==name)
return;
regist_string(name);
local.front().push_back(name);
}
return;
}
bool nasal_codegen::find_sym(std::string&)
bool nasal_codegen::local_find(std::string& name)
{
for(auto i=local.begin();i!=local.end();++i)
for(int j=0;j<i->size();++j)
if((*i)[j]==name)
return true;
return false;
}
bool nasal_codegen::global_find(std::string& name)
{
for(int i=0;i<global.size();++i)
if(global[i]==name)
return true;
return false;
}
@ -332,6 +360,15 @@ void nasal_codegen::func_gen(nasal_ast& ast)
int newfunc_label=exec_code.size();
gen(op_newf,0);
std::vector<std::string> new_scope;
local.push_front(new_scope); // symbol table push front
// add special keyword 'me' into symbol table
// this symbol is only used in local scope(function's scope)
// this keyword is set to nil as default value
// after calling a hash, this keyword is set to this hash
add_sym("me");
nasal_ast& ref_arg=ast.get_children()[0];
int arg_size=ref_arg.get_children().size();
for(int i=0;i<arg_size;++i)
@ -340,20 +377,20 @@ void nasal_codegen::func_gen(nasal_ast& ast)
if(tmp.get_type()==ast_id)
{
std::string str=tmp.get_str();
regist_string(str);
add_sym(str);
gen(op_para,string_table[str]);
}
else if(tmp.get_type()==ast_default_arg)
{
calc_gen(tmp.get_children()[1]);
std::string str=tmp.get_children()[0].get_str();
regist_string(str);
add_sym(str);
gen(op_defpara,string_table[str]);
}
else if(tmp.get_type()==ast_dynamic_id)
{
std::string str=tmp.get_str();
regist_string(str);
add_sym(str);
gen(op_dynpara,string_table[str]);
}
}
@ -362,10 +399,9 @@ void nasal_codegen::func_gen(nasal_ast& ast)
gen(op_jmp,0);
nasal_ast& block=ast.get_children()[1];
std::vector<std::string> new_scope;
local.push_front(new_scope);
block_gen(block);
local.pop_front();
local.pop_front(); // symbol table pop front
if(!block.get_children().size() || block.get_children().back().get_type()!=ast_return)
{
nil_gen();
@ -404,7 +440,12 @@ void nasal_codegen::call_id(nasal_ast& ast)
gen(op_callb,i);
return;
}
gen(op_call,string_table[str]);
if(local_find(str))
gen(op_calll,string_table[str]);
else if(global_find(str))
gen(op_callg,string_table[str]);
else
die("cannot find symbol named \""+str+"\".",ast.get_line());
return;
}
@ -479,7 +520,12 @@ void nasal_codegen::mcall_id(nasal_ast& ast)
{
std::string str=ast.get_str();
regist_string(str);
gen(op_mcall,string_table[str]);
if(local_find(str))
gen(op_mcalll,string_table[str]);
else if(global_find(str))
gen(op_mcallg,string_table[str]);
else
die("cannot find symbol named \""+str+"\".",ast.get_line());
return;
}
@ -500,10 +546,10 @@ void nasal_codegen::mcall_hash(nasal_ast& ast)
void nasal_codegen::single_def(nasal_ast& ast)
{
calc_gen(ast.get_children()[1]);
std::string str=ast.get_children()[0].get_str();
regist_string(str);
gen(op_load,string_table[str]);
add_sym(str);
calc_gen(ast.get_children()[1]);
gen(local.empty()?op_loadg:op_loadl,string_table[str]);
return;
}
void nasal_codegen::multi_def(nasal_ast& ast)
@ -513,10 +559,10 @@ void nasal_codegen::multi_def(nasal_ast& ast)
{
for(int i=0;i<size;++i)
{
calc_gen(ast.get_children()[1].get_children()[i]);
std::string str=ast.get_children()[0].get_children()[i].get_str();
regist_string(str);
gen(op_load,string_table[str]);
add_sym(str);
calc_gen(ast.get_children()[1].get_children()[i]);
gen(local.empty()?op_loadg:op_loadl,string_table[str]);
}
}
else
@ -526,8 +572,8 @@ void nasal_codegen::multi_def(nasal_ast& ast)
{
gen(op_callvi,i);
std::string str=ast.get_children()[0].get_children()[i].get_str();
regist_string(str);
gen(op_load,string_table[str]);
add_sym(str);
gen(local.empty()?op_loadg:op_loadl,string_table[str]);
}
pop_gen();
}
@ -711,14 +757,14 @@ void nasal_codegen::for_gen(nasal_ast& ast)
void nasal_codegen::forindex_gen(nasal_ast& ast)
{
calc_gen(ast.get_children()[1]);
gen(op_counter,0);
gen(op_cnt,0);
int ptr=exec_code.size();
gen(op_findex,0);
if(ast.get_children()[0].get_type()==ast_new_iter)
{
std::string str=ast.get_children()[0].get_children()[0].get_str();
regist_string(str);
gen(op_load,string_table[str]);
add_sym(str);
gen(local.empty()?op_loadg:op_loadl,string_table[str]);
}
else
{
@ -738,14 +784,14 @@ void nasal_codegen::forindex_gen(nasal_ast& ast)
void nasal_codegen::foreach_gen(nasal_ast& ast)
{
calc_gen(ast.get_children()[1]);
gen(op_counter,0);
gen(op_cnt,0);
int ptr=exec_code.size();
gen(op_feach,0);
if(ast.get_children()[0].get_type()==ast_new_iter)
{
std::string str=ast.get_children()[0].get_children()[0].get_str();
regist_string(str);
gen(op_load,string_table[str]);
add_sym(str);
gen(local.empty()?op_loadg:op_loadl,string_table[str]);
}
else
{
@ -951,6 +997,9 @@ void nasal_codegen::main_progress(nasal_ast& ast)
string_table.clear();
exec_code.clear();
global.clear();
local.clear();
int size=ast.get_children().size();
for(int i=0;i<size;++i)
{
@ -1022,15 +1071,18 @@ void nasal_codegen::print_op(int index)
case op_pnum:std::cout<<'('<<num_res_table[exec_code[index].num]<<')';break;
case op_callb:std::cout<<'('<<builtin_func[exec_code[index].num].name<<')';break;
case op_happ:
case op_call:
case op_mcall:
case op_callg:
case op_calll:
case op_mcallg:
case op_mcalll:
case op_pstr:
case op_callh:
case op_mcallh:
case op_para:
case op_defpara:
case op_dynpara:
case op_load:std::cout<<'('<<str_res_table[exec_code[index].num]<<')';break;
case op_loadg:
case op_loadl:std::cout<<'('<<str_res_table[exec_code[index].num]<<')';break;
}
std::cout<<'\n';
return;
@ -1063,4 +1115,9 @@ std::vector<opcode>& nasal_codegen::get_exec_code()
return exec_code;
}
int nasal_codegen::get_error()
{
return error;
}
#endif

View File

@ -333,13 +333,13 @@ struct nasal_gc
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; // main stack
nasal_val* val_stack[STACK_MAX_DEPTH];
nasal_val** stack_top; // stack top
std::vector<nasal_val*> num_addrs; // reserved address for const vm_num
std::vector<nasal_val*> local; // local scope for function block
std::vector<nasal_val*> slice_stack; // slice stack for vec[val,val,val:val]
std::vector<nasal_val*> memory; // gc memory
std::queue<nasal_val*> free_list; // gc free list
std::queue <nasal_val*> free_list; // gc free list
void mark();
void sweep();
void gc_init(std::vector<double>&);
@ -430,7 +430,6 @@ void nasal_gc::gc_init(std::vector<double>& nums)
memory.push_back(tmp);
free_list.push(tmp);
}
val_stack=new nasal_val*[STACK_MAX_DEPTH]; // init runtime stack
stack_top=val_stack; // set stack_top to val_stack
zero_addr=new nasal_val(vm_num); // init constant 0
@ -470,7 +469,6 @@ void nasal_gc::gc_clear()
while(!free_list.empty())
free_list.pop();
global=nullptr;
delete []val_stack;
local.clear();
slice_stack.clear();
return;

View File

@ -20,7 +20,6 @@ private:
void die(std::string);
bool condition(nasal_val*);
void opr_nop();
void opr_load();
void opr_loadg();
void opr_loadl();
void opr_pnum();
@ -63,7 +62,6 @@ private:
void opr_cntpop();
void opr_findex();
void opr_feach();
void opr_call();
void opr_callg();
void opr_calll();
void opr_callv();
@ -75,7 +73,6 @@ private:
void opr_slcend();
void opr_slc();
void opr_slc2();
void opr_mcall();
void opr_mcallg();
void opr_mcalll();
void opr_mcallv();
@ -153,12 +150,6 @@ void nasal_vm::opr_nop()
loop_mark=false;
return;
}
void nasal_vm::opr_load()
{
nasal_val* val=*stack_top--;
(gc.local.empty()?gc.global:gc.local.back())->ptr.scop->elems[exec_code[pc].num]=val;
return;
}
void nasal_vm::opr_loadg()
{
gc.global->ptr.scop->elems[exec_code[pc].num]=*stack_top--;
@ -214,6 +205,7 @@ void nasal_vm::opr_newf()
val->ptr.func->entry=exec_code[pc].num;
if(!gc.local.empty())
val->ptr.func->closure=gc.local.back()->ptr.scop->elems;
val->ptr.func->closure[me]=gc.nil_addr;
*(++stack_top)=val;
return;
}
@ -561,26 +553,6 @@ void nasal_vm::opr_feach()
*(++stack_top)=res;
return;
}
void nasal_vm::opr_call()
{
nasal_val* val=nullptr;
int name_index=exec_code[pc].num;
if(!gc.local.empty())
val=gc.local.back()->ptr.scop->get_val(name_index);
if(val)
{
*(++stack_top)=val;
return;
}
val=gc.global->ptr.scop->get_val(name_index);
if(val)
{
*(++stack_top)=val;
return;
}
die("call: cannot find symbol named \""+str_table[name_index]+"\"");
return;
}
void nasal_vm::opr_callg()
{
*(++stack_top)=gc.global->ptr.scop->elems[exec_code[pc].num];
@ -826,26 +798,6 @@ void nasal_vm::opr_slc2()
aim.push_back(ref[i]);
return;
}
void nasal_vm::opr_mcall()
{
nasal_val** mem_addr=nullptr;
int name_index=exec_code[pc].num;
if(!gc.local.empty())
mem_addr=gc.local.back()->ptr.scop->get_mem(name_index);
if(mem_addr)
{
addr_stack.push(mem_addr);
return;
}
mem_addr=gc.global->ptr.scop->get_mem(name_index);
if(mem_addr)
{
addr_stack.push(mem_addr);
return;
}
die("mcall: cannot find symbol named \""+str_table[name_index]+"\"");
return;
}
void nasal_vm::opr_mcallg()
{
addr_stack.push(&gc.global->ptr.scop->elems[exec_code[pc].num]);
@ -938,7 +890,6 @@ void nasal_vm::run()
static void (nasal_vm::*opr_table[])()=
{
&nasal_vm::opr_nop,
&nasal_vm::opr_load,
&nasal_vm::opr_loadg,
&nasal_vm::opr_loadl,
&nasal_vm::opr_pnum,
@ -981,7 +932,6 @@ void nasal_vm::run()
&nasal_vm::opr_cntpop,
&nasal_vm::opr_findex,
&nasal_vm::opr_feach,
&nasal_vm::opr_call,
&nasal_vm::opr_callg,
&nasal_vm::opr_calll,
&nasal_vm::opr_callv,
@ -993,7 +943,6 @@ void nasal_vm::run()
&nasal_vm::opr_slcend,
&nasal_vm::opr_slc,
&nasal_vm::opr_slc2,
&nasal_vm::opr_mcall,
&nasal_vm::opr_mcallg,
&nasal_vm::opr_mcalll,
&nasal_vm::opr_mcallv,

View File

@ -81,13 +81,12 @@ var matrix=
var prt_s='[\n';
foreach(var i;mat.mat)
{
var s='[';
prt_s~='[';
foreach(var j;i)
s~=(j~',');
s~='],\n';
prt_s~=s;
prt_s~=(j~',');
prt_s~='],\n';
}
prt_s~=']';
prt_s~=']\n';
print(prt_s);
return nil;
},
@ -295,9 +294,9 @@ var bp=
var hidden_diff=matrix.mult_mat();
matrix.prt_mat(hidden_diff);
output_layer=matrix.add_mat(output_layer,output_diff);
me.output_layer=matrix.add_mat(me.output_layer,output_diff);
var error=0;
foreach(var i;tmp.mat[0])
foreach(var i;me.result.mat[0])
error+=i;
error*=0.5;
return error;

View File

@ -1,30 +0,0 @@
id[0] and id[1];
1 or 2;
"str" ==1;
1*1/1+1;
2*3*4/1-2+3;
1-1+20-2*10;
1+s1*(s2+s3[0])-1;
var e=1+s1*(s2+s3[0])-1;
id;
"str";
id(id);
id("str",1,1);
var e=1;
var x=10*2-20;
var id;
var id=[1,2,3,4];
var id={id:"str"};
id();
id.id();
id.id.id();
id[0].id.id(id,"str",1,2,3,4).id[10];
id(0)[1].id;
var hash={
h:"hello",
parent:[id],
};
function_test([1,2,3,4,55],1,2,3,{str:"str"});
var (i,j,k,l,m,n) =[1,2,3,4,5,6];
(var i,j,k)=[1,2,3];
e=e[1:][0];

View File

@ -1,4 +1,4 @@
import("lib.nas");
var condition_true=1;
var condition_false=0;
if(condition_true)

View File

@ -1,4 +1,5 @@
#lib json.nas
import("lib.nas");
var json={
text:'',
line:1,

View File

@ -29,4 +29,4 @@ var makeConnect=func(n,connections)
return cnt;
}
print(makeConnect(n,input));
println(makeConnect(n,input));

View File

@ -1,10 +1,10 @@
#//This is written for Nasal Intepreter
#//Sidi Liang
# This is written for Nasal Intepreter
# Sidi Liang
import("lib.nas");
var w = 1;
var x = "hello";
var f = func(){
print("f is called");
println("f is called");
}
var f2 = func(){
return 2;
@ -28,71 +28,27 @@ var z1 = {
hashh:z
};
var y2 = [w, x, y, z1];
var z2 = {
hashh: z1,
listt2: y2,
};
print(w);#//1
print("\n");
print(x);#//hello
print("\n");
print(y);#//Empty
print("\n");
print(z);#//Empty
print("\n");
print(z1);#//Empty
print("\n");
print(y2);#//Empty
print("\n");
print(y[0]);#//1
print("\n");
print(y1[2][1]);#//hello
print("\n");
print(z.numb);#//1
print("\n");
print(z.listt[2][1]);#//hello
print("\n");
print(z1.hashh.listt[2][1]);#//hello
print("\n");
print(y2[3].hashh.listt[2][1]);#//hello
print("\n");
print(f);#//Empty
print("\n");
println(w);#//1
println(x);#//hello
println(y);#//[1,hello]
println(z);#//{...}
println(z1);#//{...}
println(y2);#//[...]
println(y[0]);#//1
println(y1[2][1]);#//hello
println(z.numb);#//1
println(z.listt[2][1]);#//hello
println(z1.hashh.listt[2][1]);#//hello
println(y2[3].hashh.listt[2][1]);#//hello
println(f);#//func(...){...}
f();#//f is called
print("\n");
print(z.funcc);#//Empty
print("\n");
println(z.funcc);#//func(...){...}
z.funcc();#//f is called
print("\n");
print(z.funcccall);#//Empty
print("\n");
z.funcccall();#//f is called
print("\n");
println(z.funcccall);#//nil
z2.listt2[3].hashh.funcc();#//f is called
print("\n");
print(y1[f2()][w]);#//hello
print("\n");
#//print(z.f3()); Error
call(f);#//f is called
print("\n");
call(z.funcc);#//f is called
print("\n");
println(y1[f2()][w]);#//hello

View File

@ -1,12 +1,12 @@
import("lib.nas");
rand(time(0));
var chartable=split('','abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789');
var chartable='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
var node=func(type)
{
var s="";
for(var i=0;i<10;i+=1)
s~=chartable[rand()*62];
s~=chr(chartable[rand()*62]);
return {name:s,type:type,next:[]};
}
var film_node=[];

View File

@ -26,7 +26,7 @@ var sort=func(vec,left,right)
return nil;
}
var vec=[];
for(var i=0;i<500;i+=1)
for(var i=0;i<200;i+=1)
append(vec,int(rand()*1000));
sort(vec,0,size(vec)-1);
println(vec);

View File

@ -115,7 +115,7 @@ var multi_assign_2=[10,9,8,7];
((-1*2+9))/7-1;
((({num:2})))["num"]*2*2*2;
((((([0,1,2])[0:2]))[0:2]))[1]-1;
(((((((((((((((((((1+1+2+3+5)+8))+13)))+21))))+34)))))+55))))*89;
println((((((((((((((((((((1+1+2+3+5)+8))+13)))+21))))+34)))))+55))))*89); # 12727
number_1*(number_2+number_3)/90-number_4;
(func test_func)()-1;
hash_3.member_3+(func {return {what:"i don't tell you.",case_small:80,case_large:100}})()["case_large"]/10;
@ -129,7 +129,7 @@ nil and 1+7*8;
var hash={str:'hello',f:func{return me.str;}};
var tmp_f=hash.f;
hash=1;
print(tmp_f());
println(tmp_f());
# undefined symbol 'me'
# this means that
# when generating local_scope for function f,
@ -138,13 +138,13 @@ print(tmp_f());
var h1={str:'hello',f:func{return me.str;}};
var h2={str:'world',f:func{return nil;}};
h2.f=h1.f;
print(h2.f());
println(h2.f());
# print 'world'
# this means that 'me' in hash's functions
# only points to the hash this function belongs to
var f1=func(){print(1);return 1;}
var f2=func(){print(2);return 0;}
var f1=func(){println(1);return 1;}
var f2=func(){println(2);return 0;}
f1() or f2();
# print '1'
# this means that when using 'or' or 'and',

View File

@ -1,24 +0,0 @@
var hash={str:'hello',f:func{return me.str;}};
var tmp_f=hash.f;
hash=1;
print(tmp_f());
# undefined symbol 'me'
# this means that
# when generating local_scope for function f,
# nasal_gc will not count 'me' as one reference of this hash
var h1={str:'hello',f:func{return me.str;}};
var h2={str:'world',f:func{return nil;}};
h2.f=h1.f;
print(h2.f());
# print 'world'
# this means that 'me' in hash's functions
# only points to the hash this function belongs to
var f1=func(){print(1);return 1;}
var f2=func(){print(2);return 0;}
f1() or f2();
# print '1'
# this means that when using 'or' or 'and',
# if the result is clear when calculating,
# objects behind will not be calculated