🎨 improve error report
This commit is contained in:
parent
309a57070c
commit
9196d7815f
|
@ -170,6 +170,7 @@ public:
|
|||
<<ins.nums[num]<<")";break;
|
||||
case op_callvi:case op_newv: case op_callfv:
|
||||
case op_intg: case op_intl:
|
||||
case op_findex:case op_feach:
|
||||
case op_newf: case op_jmp: case op_jt: case op_jf:
|
||||
case op_callg: case op_mcallg: case op_loadg:
|
||||
case op_calll: case op_mcalll: case op_loadl:
|
||||
|
@ -220,7 +221,7 @@ private:
|
|||
std::stack<u32> fbstk;
|
||||
std::stack<u32> festk;
|
||||
|
||||
void die(const string&,const u32,const u32);
|
||||
void die(const string&,const u32,const u32,const u32);
|
||||
void regist_num(const f64);
|
||||
void regist_str(const string&);
|
||||
void find_symbol(const ast&);
|
||||
|
@ -271,13 +272,10 @@ public:
|
|||
const std::vector<opcode>& codes() const {return code;}
|
||||
};
|
||||
|
||||
void codegen::die(const string& info,const u32 line,const u32 col)
|
||||
void codegen::die(const string& info,const u32 line,const u32 col,const u32 len=1)
|
||||
{
|
||||
err.load(file[fileindex]);
|
||||
if(col)
|
||||
err.err("code",line,col,info);
|
||||
else
|
||||
err.err("code",line,info);
|
||||
err.err("code",line,col,len,info);
|
||||
}
|
||||
|
||||
void codegen::regist_num(const f64 num)
|
||||
|
@ -406,6 +404,32 @@ void codegen::hash_gen(const ast& node)
|
|||
|
||||
void codegen::func_gen(const ast& node)
|
||||
{
|
||||
// parameter list format check
|
||||
bool checked_default=false;
|
||||
bool checked_dynamic=false;
|
||||
std::unordered_map<string,bool> argname;
|
||||
for(auto& tmp:node[0].child()){
|
||||
if(tmp.type()==ast_default){
|
||||
checked_default=true;
|
||||
}else if(tmp.type()==ast_dynamic){
|
||||
checked_dynamic=true;
|
||||
}
|
||||
// check default parameter and dynamic parameter
|
||||
if(checked_default && tmp.type()!=ast_default){
|
||||
die("must use default parameters here",tmp.line(),tmp.col(),tmp.str().length());
|
||||
}
|
||||
if(checked_dynamic && &tmp!=&node[0].child().back()){
|
||||
die("dynamic parameter must be the last one",tmp.line(),tmp.col(),tmp.str().length());
|
||||
}
|
||||
// check redefinition
|
||||
string name=tmp.str();
|
||||
if(argname.count(name)){
|
||||
die("redefinition of parameter: "+name,tmp.line(),tmp.col(),name.length());
|
||||
}else{
|
||||
argname[name]=true;
|
||||
}
|
||||
}
|
||||
|
||||
usize newf=code.size();
|
||||
gen(op_newf,0,node.line());
|
||||
usize lsize=code.size();
|
||||
|
@ -423,7 +447,7 @@ void codegen::func_gen(const ast& node)
|
|||
{
|
||||
const string& str=tmp.str();
|
||||
if(str=="me")
|
||||
die("\"me\" should not be a parameter",tmp.line(),tmp.col());
|
||||
die("\"me\" should not be a parameter",tmp.line(),tmp.col(),tmp.str().length());
|
||||
regist_str(str);
|
||||
switch(tmp.type())
|
||||
{
|
||||
|
@ -486,7 +510,7 @@ void codegen::call_id(const ast& node)
|
|||
{
|
||||
gen(op_callb,i,node.line());
|
||||
if(local.empty())
|
||||
die("should warp native function in local scope",node.line(),node.col());
|
||||
die("should warp native function in local scope",node.line(),node.col(),node.str().length());
|
||||
return;
|
||||
}
|
||||
i32 index;
|
||||
|
@ -505,7 +529,7 @@ void codegen::call_id(const ast& node)
|
|||
gen(op_callg,index,node.line());
|
||||
return;
|
||||
}
|
||||
die("undefined symbol \""+str+"\"",node.line(),node.col());
|
||||
die("undefined symbol \""+str+"\"",node.line(),node.col(),node.str().length());
|
||||
}
|
||||
|
||||
void codegen::call_hash(const ast& node)
|
||||
|
@ -602,7 +626,7 @@ void codegen::mcall_id(const ast& node)
|
|||
for(u32 i=0;builtin[i].name;++i)
|
||||
if(builtin[i].name==str)
|
||||
{
|
||||
die("cannot modify native function",node.line(),node.col());
|
||||
die("cannot modify native function",node.line(),node.col(),node.str().length());
|
||||
return;
|
||||
}
|
||||
i32 index;
|
||||
|
@ -621,7 +645,7 @@ void codegen::mcall_id(const ast& node)
|
|||
gen(op_mcallg,index,node.line());
|
||||
return;
|
||||
}
|
||||
die("undefined symbol \""+str+"\"",node.line(),node.col());
|
||||
die("undefined symbol \""+str+"\"",node.line(),node.col(),node.str().length());
|
||||
}
|
||||
|
||||
void codegen::mcall_vec(const ast& node)
|
||||
|
@ -677,11 +701,23 @@ void codegen::multi_def(const ast& node)
|
|||
|
||||
void codegen::def_gen(const ast& node)
|
||||
{
|
||||
if(node[0].type()==ast_id && node[1].type()==ast_tuple){
|
||||
die("cannot accept too many values",node[1].line(),node[1].col(),1);
|
||||
}else if(node[0].type()==ast_multi_id && node[1].type()==ast_tuple && node[0].size()<node[1].size()){
|
||||
die("lack values in multi-definition",node[1].line(),node[1].col(),1);
|
||||
}else if(node[0].type()==ast_multi_id && node[1].type()==ast_tuple && node[0].size()>node[1].size()){
|
||||
die("too many values in multi-definition",node[1].line(),node[1].col(),1);
|
||||
}
|
||||
node[0].type()==ast_id?single_def(node):multi_def(node);
|
||||
}
|
||||
|
||||
void codegen::multi_assign_gen(const ast& node)
|
||||
{
|
||||
if(node[1].type()==ast_tuple && node[0].size()<node[1].size()){
|
||||
die("lack values in multi-assignment",node[1].line(),node[1].col(),1);
|
||||
}else if(node[1].type()==ast_tuple && node[0].size()>node[1].size()){
|
||||
die("too many values in multi-assignment",node[1].line(),node[1].col(),1);
|
||||
}
|
||||
i32 size=node[0].size();
|
||||
if(node[1].type()==ast_tuple)
|
||||
{
|
||||
|
@ -1244,10 +1280,14 @@ const error& codegen::compile(const parse& parse,const linker& import)
|
|||
gen(op_intg,global.size(),0);
|
||||
block_gen(parse.tree()); // generate main block
|
||||
gen(op_exit,0,0);
|
||||
if(global.size()>=STACK_DEPTH)
|
||||
die("too many global variants: "+std::to_string(global.size()),0,0);
|
||||
if(code.size()>0xffffffff)
|
||||
die("too large generated bytecode file: "+std::to_string(code.size()),0,0);
|
||||
if(global.size()>=STACK_DEPTH){
|
||||
err.load(file[fileindex]);
|
||||
err.err("code","too many global variants: "+std::to_string(global.size()));
|
||||
}
|
||||
if(code.size()>0xffffffff){
|
||||
err.load(file[fileindex]);
|
||||
err.err("code","too large generated bytecode file: "+std::to_string(code.size()));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
73
nasal_err.h
73
nasal_err.h
|
@ -77,20 +77,24 @@ protected:
|
|||
string file;
|
||||
std::vector<string> res;
|
||||
public:
|
||||
flstream():file("<error-file-path>"){}
|
||||
void load(const string& f)
|
||||
{
|
||||
if(file==f) return; // don't need to load a loaded file
|
||||
if(file==f){ // don't need to load a loaded file
|
||||
return;
|
||||
}else{
|
||||
file=f;
|
||||
}
|
||||
|
||||
res.clear();
|
||||
std::ifstream in(f,std::ios::binary);
|
||||
if(in.fail())
|
||||
{
|
||||
if(in.fail()){
|
||||
std::cerr<<red<<"src: "<<reset<<"cannot open <"<<f<<">\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
while(!in.eof()){
|
||||
string line;
|
||||
while(!in.eof())
|
||||
{
|
||||
std::getline(in,line);
|
||||
res.push_back(line);
|
||||
}
|
||||
|
@ -112,54 +116,41 @@ private:
|
|||
}
|
||||
public:
|
||||
error():cnt(0){}
|
||||
void fatal(const string& stage,const string& info)
|
||||
{
|
||||
std::cerr
|
||||
<<red<<stage<<": "<<white<<info<<reset<<"\n"
|
||||
<<cyan<<" --> "<<red<<file<<"\n\n";
|
||||
std::exit(1);
|
||||
}
|
||||
void err(const string& stage,const string& info)
|
||||
{
|
||||
++cnt;
|
||||
std::cerr
|
||||
<<red<<stage<<": "
|
||||
<<white<<info<<reset<<"\n\n";
|
||||
<<red<<stage<<": "<<white<<info<<reset<<"\n"
|
||||
<<cyan<<" --> "<<red<<file<<reset<<"\n\n";
|
||||
}
|
||||
void err(const string& stage,u32 line,u32 col,const string& info)
|
||||
void err(const string& stage,u32 line,u32 col,u32 len,const string& info)
|
||||
{
|
||||
++cnt;
|
||||
const string& code=res[line-1];
|
||||
col=col?col:1;
|
||||
len=len?len:1;
|
||||
|
||||
std::cerr
|
||||
<<red<<stage<<": "<<white<<info<<reset<<"\n"
|
||||
<<cyan<<" --> "<<red<<file<<":"<<line<<":"<<col<<reset<<"\n";
|
||||
|
||||
const string& code=line?res[line-1]:"# empty line";
|
||||
const string iden=identation(std::to_string(line).length());
|
||||
|
||||
std::cerr
|
||||
<<red<<stage<<": "
|
||||
<<white<<info<<reset<<"\n"
|
||||
<<cyan<<" --> "<<reset
|
||||
<<orange<<file<<":"<<line<<":"<<col<<"\n";
|
||||
if(!line)
|
||||
{
|
||||
std::cerr<<"\n";
|
||||
return;
|
||||
}
|
||||
std::cerr
|
||||
<<cyan<<iden<<" | "<<reset<<"\n"
|
||||
<<cyan<<line<<" | "<<reset<<code<<"\n"
|
||||
<<cyan<<iden<<" | "<<reset;
|
||||
for(i32 i=0;i<(i32)col-1;++i)
|
||||
for(i32 i=0;i<(i32)col-(i32)len;++i)
|
||||
std::cerr<<char(" \t"[code[i]=='\t']);
|
||||
std::cerr<<red<<"^ "<<info<<reset<<"\n\n";
|
||||
}
|
||||
void err(const string& stage,u32 line,const string& info)
|
||||
{
|
||||
++cnt;
|
||||
const string iden=identation(std::to_string(line).length());
|
||||
std::cerr
|
||||
<<red<<stage<<": "
|
||||
<<white<<info<<reset<<"\n"
|
||||
<<cyan<<" --> "<<reset
|
||||
<<orange<<file<<":"<<line<<"\n";
|
||||
if(!line)
|
||||
{
|
||||
std::cerr<<"\n";
|
||||
return;
|
||||
}
|
||||
std::cerr
|
||||
<<cyan<<iden<<" | "<<reset<<"\n"
|
||||
<<cyan<<line<<" | "<<reset<<res[line-1]<<"\n"
|
||||
<<cyan<<iden<<" | "<<reset<<"\n\n";
|
||||
for(u32 i=0;i<len;++i)
|
||||
std::cerr<<red<<"^";
|
||||
std::cerr<<red<<" "<<info<<reset<<"\n\n";
|
||||
}
|
||||
void chkerr() const {if(cnt)std::exit(1);}
|
||||
};
|
||||
|
|
|
@ -669,15 +669,19 @@ void gc::info()
|
|||
len=std::to_string(ini[i]+size[i]*incr[i]).length();
|
||||
maxlen=maxlen<len?len:maxlen;
|
||||
}
|
||||
double total=0;
|
||||
for(u8 i=0;i<gc_tsize;++i)
|
||||
if(gcnt[i] || acnt[i] || ini[i] || size[i])
|
||||
{
|
||||
total+=gcnt[i];
|
||||
std::cout<<" "<<name[i]<<" | "<<std::left<<std::setw(maxlen)<<std::setfill(' ')<<gcnt[i];
|
||||
std::cout<<" | "<<std::left<<std::setw(maxlen)<<std::setfill(' ')<<acnt[i];
|
||||
std::cout<<" | "<<std::left<<std::setw(maxlen)<<std::setfill(' ')<<ini[i]+size[i]*incr[i]<<" (+"<<size[i]<<")\n";
|
||||
}
|
||||
double t=worktime*1.0/1000000000;
|
||||
double t=worktime*1.0/1000000000; // seconds
|
||||
std::cout<<" time | "<<(t<0.1? t*1000:t)<<(t<0.1? "ms\n":"s\n");
|
||||
if(total)
|
||||
std::cout<<" avg | "<<t/total*1000<<" ms\n";
|
||||
}
|
||||
var gc::alloc(u8 type)
|
||||
{
|
||||
|
|
|
@ -137,7 +137,6 @@ private:
|
|||
bool is_str(char);
|
||||
bool is_single_opr(char);
|
||||
bool is_calc_opr(char);
|
||||
void die(const string&);
|
||||
void open(const string&);
|
||||
string utf8_gen();
|
||||
string id_gen();
|
||||
|
@ -199,10 +198,10 @@ bool lexer::is_calc_opr(char c)
|
|||
);
|
||||
}
|
||||
|
||||
void lexer::die(const string& info)
|
||||
{
|
||||
err.err("lexer",line,column,info);
|
||||
}
|
||||
// void lexer::die(const string& info)
|
||||
// {
|
||||
// err.err("lexer",line,column,1,info);
|
||||
// }
|
||||
|
||||
void lexer::open(const string& file)
|
||||
{
|
||||
|
@ -246,9 +245,8 @@ string lexer::utf8_gen()
|
|||
string utf_info="0x"+chrhex(tmp[0]);
|
||||
for(u32 i=1;i<tmp.size();++i)
|
||||
utf_info+=" 0x"+chrhex(tmp[i]);
|
||||
die("invalid utf-8 <"+utf_info+">");
|
||||
err.err("lexer","fatal error occurred, stop");
|
||||
std::exit(1);
|
||||
err.err("lexer",line,column,1,"invalid utf-8 <"+utf_info+">");
|
||||
err.fatal("lexer","fatal error occurred, stop");
|
||||
}
|
||||
str+=tmp;
|
||||
column+=2; // may have some problems because not all the unicode takes 2 space
|
||||
|
@ -289,7 +287,7 @@ string lexer::num_gen()
|
|||
str+=res[ptr++];
|
||||
column+=str.length();
|
||||
if(str.length()<3)// "0x"
|
||||
die("invalid number `"+str+"`");
|
||||
err.err("lexer",line,column,str.length(),"invalid number `"+str+"`");
|
||||
return str;
|
||||
}
|
||||
// generate oct number
|
||||
|
@ -299,9 +297,15 @@ string lexer::num_gen()
|
|||
ptr+=2;
|
||||
while(ptr<res.size() && is_oct(res[ptr]))
|
||||
str+=res[ptr++];
|
||||
bool erfmt=false;
|
||||
while(ptr<res.size() && (is_dec(res[ptr]) || is_hex(res[ptr])))
|
||||
{
|
||||
erfmt=true;
|
||||
str+=res[ptr++];
|
||||
}
|
||||
column+=str.length();
|
||||
if(str.length()<3)// "0o"
|
||||
die("invalid number `"+str+"`");
|
||||
if(str.length()==2 || erfmt)
|
||||
err.err("lexer",line,column,str.length(),"invalid number `"+str+"`");
|
||||
return str;
|
||||
}
|
||||
// generate dec number
|
||||
|
@ -318,7 +322,7 @@ string lexer::num_gen()
|
|||
if(str.back()=='.')
|
||||
{
|
||||
column+=str.length();
|
||||
die("invalid number `"+str+"`");
|
||||
err.err("lexer",line,column,str.length(),"invalid number `"+str+"`");
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
|
@ -333,7 +337,7 @@ string lexer::num_gen()
|
|||
if(str.back()=='e' || str.back()=='E' || str.back()=='-' || str.back()=='+')
|
||||
{
|
||||
column+=str.length();
|
||||
die("invalid number `"+str+"`");
|
||||
err.err("lexer",line,column,str.length(),"invalid number `"+str+"`");
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
|
@ -382,12 +386,12 @@ string lexer::str_gen()
|
|||
// check if this string ends with a " or '
|
||||
if(ptr++>=res.size())
|
||||
{
|
||||
die("get EOF when generating string");
|
||||
err.err("lexer",line,column,1,"get EOF when generating string");
|
||||
return str;
|
||||
}
|
||||
++column;
|
||||
if(begin=='`' && str.length()!=1)
|
||||
die("\'`\' is used for string that includes one character");
|
||||
err.err("lexer",line,column,1,"\'`\' is used for string that includes one character");
|
||||
return str;
|
||||
}
|
||||
|
||||
|
@ -434,7 +438,7 @@ const error& lexer::scan(const string& file)
|
|||
++column;
|
||||
u32 type=get_type(str);
|
||||
if(!type)
|
||||
die("invalid operator `"+str+"`");
|
||||
err.err("lexer",line,column,str.length(),"invalid operator `"+str+"`");
|
||||
toks.push_back({line,column,type,str});
|
||||
++ptr;
|
||||
}
|
||||
|
@ -462,7 +466,8 @@ const error& lexer::scan(const string& file)
|
|||
{
|
||||
++column;
|
||||
char c=res[ptr++];
|
||||
die("invalid character 0x"+chrhex(c));
|
||||
err.err("lexer",line,column,1,"invalid character 0x"+chrhex(c));
|
||||
err.fatal("lexer","fatal error occurred, stop");
|
||||
}
|
||||
}
|
||||
toks.push_back({line,column,tok_eof,"<eof>"});
|
||||
|
|
497
nasal_parse.h
497
nasal_parse.h
|
@ -39,7 +39,9 @@
|
|||
|
||||
class parse
|
||||
{
|
||||
#define err_line (toks[ptr].line)
|
||||
#define thisline (toks[ptr].line)
|
||||
#define thiscol (toks[ptr].col)
|
||||
#define thislen (toks[ptr].str.length())
|
||||
private:
|
||||
u32 ptr;
|
||||
u32 in_func; // count function block
|
||||
|
@ -95,7 +97,7 @@ private:
|
|||
{tok_geq ,">=" }
|
||||
};
|
||||
|
||||
void die(u32,string,bool);
|
||||
void die(u32,u32,u32,string,bool);
|
||||
void next(){++ptr;};
|
||||
void match(u32 type,const char* info=nullptr);
|
||||
bool lookahead(u32);
|
||||
|
@ -163,49 +165,53 @@ const error& parse::compile(const lexer& lexer)
|
|||
ptr=in_func=in_loop=0;
|
||||
|
||||
root={0,0,ast_root};
|
||||
while(!lookahead(tok_eof))
|
||||
{
|
||||
while(!lookahead(tok_eof)){
|
||||
root.add(expr());
|
||||
if(lookahead(tok_semi))
|
||||
if(lookahead(tok_semi)){
|
||||
match(tok_semi);
|
||||
}else if(need_semi_check(root.child().back()) && !lookahead(tok_eof)){
|
||||
// the last expression can be recognized without semi
|
||||
else if(need_semi_check(root.child().back()) && !lookahead(tok_eof))
|
||||
die(err_line,"expected \";\"",true);
|
||||
die(thisline,thiscol,thislen,"expected \";\"",true);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
void parse::die(u32 line,string info,bool report_prev=false)
|
||||
void parse::die(u32 line,u32 col,u32 len,string info,bool prev=false)
|
||||
{
|
||||
i32 col=(i32)toks[ptr].col-(lookahead(tok_eof)?0:(i32)toks[ptr].str.length());
|
||||
if(lookahead(tok_str))
|
||||
col-=2; // tok_str's str has no \"
|
||||
if(report_prev && ptr) // used to report lack of ',' ';'
|
||||
{
|
||||
line=toks[ptr-1].line;
|
||||
col=toks[ptr-1].col+1;
|
||||
// tok_str's str has no \"
|
||||
if(lookahead(tok_str)){
|
||||
col-=2;
|
||||
len+=2;
|
||||
}
|
||||
err.err("parse",line,col<0?0:col,info);
|
||||
|
||||
// used to report lack of ',' ';'
|
||||
if(prev && ptr){
|
||||
line=toks[ptr-1].line;
|
||||
col=toks[ptr-1].col;
|
||||
len=toks[ptr-1].str.length();
|
||||
len+=toks[ptr-1].type==tok_str?2:0;
|
||||
}
|
||||
|
||||
err.err("parse",line,col,lookahead(tok_eof)?1:len,info);
|
||||
}
|
||||
void parse::match(u32 type,const char* info)
|
||||
{
|
||||
if(!lookahead(type))
|
||||
{
|
||||
if(info)
|
||||
{
|
||||
die(err_line,info);
|
||||
if(!lookahead(type)){
|
||||
if(info){
|
||||
die(thisline,thiscol,thislen,info);
|
||||
return;
|
||||
}
|
||||
switch(type)
|
||||
{
|
||||
case tok_num:die(err_line,"expected number"); break;
|
||||
case tok_str:die(err_line,"expected string"); break;
|
||||
case tok_id: die(err_line,"expected identifier");break;
|
||||
default: die(err_line,"expected '"+tokname[type]+"'"); break;
|
||||
switch(type){
|
||||
case tok_num:die(thisline,thiscol,thislen,"expected number"); break;
|
||||
case tok_str:die(thisline,thiscol,thislen,"expected string"); break;
|
||||
case tok_id: die(thisline,thiscol,thislen,"expected identifier");break;
|
||||
default: die(thisline,thiscol,thislen,"expected '"+tokname[type]+"'"); break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(lookahead(tok_eof))
|
||||
if(lookahead(tok_eof)){
|
||||
return;
|
||||
}
|
||||
next();
|
||||
}
|
||||
bool parse::lookahead(u32 type)
|
||||
|
@ -218,21 +224,19 @@ bool parse::is_call(u32 type)
|
|||
}
|
||||
bool parse::check_comma(const u32* panic_set)
|
||||
{
|
||||
for(u32 i=0;panic_set[i];++i)
|
||||
if(lookahead(panic_set[i]))
|
||||
{
|
||||
die(err_line,"expected ',' between scalars",true);
|
||||
for(u32 i=0;panic_set[i];++i){
|
||||
if(lookahead(panic_set[i])){
|
||||
die(thisline,thiscol,thislen,"expected ',' between scalars",true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool parse::check_tuple()
|
||||
{
|
||||
u32 check_ptr=ptr,curve=1,bracket=0,brace=0;
|
||||
while(toks[++check_ptr].type!=tok_eof && curve)
|
||||
{
|
||||
switch(toks[check_ptr].type)
|
||||
{
|
||||
while(toks[++check_ptr].type!=tok_eof && curve){
|
||||
switch(toks[check_ptr].type){
|
||||
case tok_lcurve: ++curve; break;
|
||||
case tok_lbracket: ++bracket; break;
|
||||
case tok_lbrace: ++brace; break;
|
||||
|
@ -240,21 +244,21 @@ bool parse::check_tuple()
|
|||
case tok_rbracket: --bracket; break;
|
||||
case tok_rbrace: --brace; break;
|
||||
}
|
||||
if(curve==1 && !bracket && !brace && toks[check_ptr].type==tok_comma)
|
||||
if(curve==1 && !bracket && !brace && toks[check_ptr].type==tok_comma){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool parse::check_func_end(const ast& node)
|
||||
{
|
||||
u32 type=node.type();
|
||||
if(type==ast_func)
|
||||
if(type==ast_func){
|
||||
return true;
|
||||
else if(type==ast_num || type==ast_id || type==ast_str || type==ast_nil || type==ast_vec || type==ast_hash)
|
||||
}else if(type==ast_num || type==ast_id || type==ast_str || type==ast_nil || type==ast_vec || type==ast_hash){
|
||||
return false;
|
||||
if(
|
||||
node.child().empty() ||
|
||||
(
|
||||
}
|
||||
if(node.child().empty() || (
|
||||
type!=ast_def &&
|
||||
type!=ast_equal &&
|
||||
type!=ast_addeq &&
|
||||
|
@ -263,20 +267,19 @@ bool parse::check_func_end(const ast& node)
|
|||
type!=ast_diveq &&
|
||||
type!=ast_lnkeq
|
||||
)
|
||||
)
|
||||
){
|
||||
return false;
|
||||
else
|
||||
}else{
|
||||
return check_func_end(node.child().back());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool parse::check_special_call()
|
||||
{
|
||||
// special call means like this: function_name(a:1,b:2,c:3);
|
||||
u32 check_ptr=ptr,curve=1,bracket=0,brace=0;
|
||||
while(toks[++check_ptr].type!=tok_eof && curve)
|
||||
{
|
||||
switch(toks[check_ptr].type)
|
||||
{
|
||||
while(toks[++check_ptr].type!=tok_eof && curve){
|
||||
switch(toks[check_ptr].type){
|
||||
case tok_lcurve: ++curve; break;
|
||||
case tok_lbracket: ++bracket;break;
|
||||
case tok_lbrace: ++brace; break;
|
||||
|
@ -285,32 +288,36 @@ bool parse::check_special_call()
|
|||
case tok_rbrace: --brace; break;
|
||||
}
|
||||
// m?1:0 will be recognized as normal parameter
|
||||
if(curve==1 && !bracket && !brace && toks[check_ptr].type==tok_quesmark)
|
||||
if(curve==1 && !bracket && !brace && toks[check_ptr].type==tok_quesmark){
|
||||
return false;
|
||||
if(curve==1 && !bracket && !brace && toks[check_ptr].type==tok_colon)
|
||||
}
|
||||
if(curve==1 && !bracket && !brace && toks[check_ptr].type==tok_colon){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool parse::need_semi_check(const ast& node)
|
||||
{
|
||||
u32 type=node.type();
|
||||
if(type==ast_for || type==ast_foreach || type==ast_forindex || type==ast_while || type==ast_cond)
|
||||
if(type==ast_for || type==ast_foreach || type==ast_forindex || type==ast_while || type==ast_cond){
|
||||
return false;
|
||||
}
|
||||
return !check_func_end(node);
|
||||
}
|
||||
void parse::check_memory_reachable(const ast& node)
|
||||
{
|
||||
if(node.type()==ast_call)
|
||||
{
|
||||
if(node.type()==ast_call){
|
||||
const ast& tmp=node.child().back();
|
||||
if(tmp.type()==ast_callf)
|
||||
die(tmp.line(),"bad left-value");
|
||||
if(tmp.type()==ast_callv && (tmp.size()==0 || tmp.size()>1 || tmp[0].type()==ast_subvec))
|
||||
die(tmp.line(),"bad left-value");
|
||||
if(tmp.type()==ast_callf){
|
||||
die(tmp.line(),tmp.col(),1,"bad left-value");
|
||||
}
|
||||
if(tmp.type()==ast_callv && (tmp.size()==0 || tmp.size()>1 || tmp[0].type()==ast_subvec)){
|
||||
die(tmp.line(),tmp.col(),1,"bad left-value");
|
||||
}
|
||||
}else if(node.type()!=ast_id){
|
||||
die(node.line(),node.col(),1,"bad left-value");
|
||||
}
|
||||
else if(node.type()!=ast_id)
|
||||
die(node.line(),"bad left-value");
|
||||
}
|
||||
ast parse::null()
|
||||
{
|
||||
|
@ -354,16 +361,16 @@ ast parse::vec()
|
|||
};
|
||||
ast node(toks[ptr].line,toks[ptr].col,ast_vec);
|
||||
match(tok_lbracket);
|
||||
while(!lookahead(tok_rbracket))
|
||||
{
|
||||
while(!lookahead(tok_rbracket)){
|
||||
node.add(calc());
|
||||
if(lookahead(tok_comma))
|
||||
if(lookahead(tok_comma)){
|
||||
match(tok_comma);
|
||||
else if(lookahead(tok_eof))
|
||||
}else if(lookahead(tok_eof)){
|
||||
break;
|
||||
else if(!lookahead(tok_rbracket) && !check_comma(panic_set))
|
||||
}else if(!lookahead(tok_rbracket) && !check_comma(panic_set)){
|
||||
break;
|
||||
}
|
||||
}
|
||||
match(tok_rbracket,"expected ']' when generating vector");
|
||||
return node;
|
||||
}
|
||||
|
@ -371,28 +378,29 @@ ast parse::hash()
|
|||
{
|
||||
ast node(toks[ptr].line,toks[ptr].col,ast_hash);
|
||||
match(tok_lbrace);
|
||||
while(!lookahead(tok_rbrace))
|
||||
{
|
||||
while(!lookahead(tok_rbrace)){
|
||||
node.add(pair());
|
||||
if(lookahead(tok_comma))
|
||||
if(lookahead(tok_comma)){
|
||||
match(tok_comma);
|
||||
else if(lookahead(tok_id) || lookahead(tok_str))// first set of hashmember
|
||||
die(err_line,"expected ',' between hash members",true);
|
||||
else
|
||||
}else if(lookahead(tok_id) || lookahead(tok_str)){ // first set of hashmember
|
||||
die(thisline,thiscol,thislen,"expected ',' between hash members",true);
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
match(tok_rbrace,"expected '}' when generating hash");
|
||||
return node;
|
||||
}
|
||||
ast parse::pair()
|
||||
{
|
||||
ast node(toks[ptr].line,toks[ptr].col,ast_pair);
|
||||
if(lookahead(tok_id))
|
||||
if(lookahead(tok_id)){
|
||||
node.add(id());
|
||||
else if(lookahead(tok_str))
|
||||
}else if(lookahead(tok_str)){
|
||||
node.add(str());
|
||||
else
|
||||
}else{
|
||||
match(tok_id,"expected hashmap key");
|
||||
}
|
||||
match(tok_colon);
|
||||
node.add(calc());
|
||||
return node;
|
||||
|
@ -402,10 +410,11 @@ ast parse::func()
|
|||
++in_func;
|
||||
ast node(toks[ptr].line,toks[ptr].col,ast_func);
|
||||
match(tok_func);
|
||||
if(lookahead(tok_lcurve))
|
||||
if(lookahead(tok_lcurve)){
|
||||
node.add(args());
|
||||
else
|
||||
}else{
|
||||
node.add(null());
|
||||
}
|
||||
node.add(exprs());
|
||||
--in_func;
|
||||
return node;
|
||||
|
@ -414,77 +423,33 @@ ast parse::args()
|
|||
{
|
||||
ast node(toks[ptr].line,toks[ptr].col,ast_args);
|
||||
match(tok_lcurve);
|
||||
while(!lookahead(tok_rcurve))
|
||||
{
|
||||
while(!lookahead(tok_rcurve)){
|
||||
ast tmp=id();
|
||||
if(lookahead(tok_eq) || lookahead(tok_ellipsis))
|
||||
{
|
||||
if(lookahead(tok_eq) || lookahead(tok_ellipsis)){
|
||||
ast special_arg(toks[ptr].line,toks[ptr].col,ast_null);
|
||||
if(lookahead(tok_eq))
|
||||
{
|
||||
if(lookahead(tok_eq)){
|
||||
match(tok_eq);
|
||||
special_arg=std::move(tmp);
|
||||
special_arg.set_type(ast_default);
|
||||
special_arg.add(calc());
|
||||
}
|
||||
else
|
||||
{
|
||||
}else{
|
||||
match(tok_ellipsis);
|
||||
special_arg=std::move(tmp);
|
||||
special_arg.set_type(ast_dynamic);
|
||||
}
|
||||
node.add(std::move(special_arg));
|
||||
}
|
||||
else
|
||||
}else{
|
||||
node.add(std::move(tmp));
|
||||
if(lookahead(tok_comma))
|
||||
}
|
||||
if(lookahead(tok_comma)){
|
||||
match(tok_comma);
|
||||
else if(lookahead(tok_id))// first set of identifier
|
||||
die(err_line,"expected ',' between identifiers",true);
|
||||
else
|
||||
}else if(lookahead(tok_id)){ // first set of identifier
|
||||
die(thisline,thiscol,thislen,"expected ',' between identifiers",true);
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
match(tok_rcurve,"expected ')' after parameter list");
|
||||
|
||||
string format="func(";
|
||||
for(auto& tmp:node.child())
|
||||
{
|
||||
format+=tmp.str();
|
||||
switch(tmp.type())
|
||||
{
|
||||
case ast_id: break;
|
||||
case ast_default: format+="=val";break;
|
||||
case ast_dynamic: format+="..."; break;
|
||||
}
|
||||
format+=",)"[&tmp==&node.child().back()];
|
||||
}
|
||||
bool checked_default=false,checked_dynamic=false;
|
||||
for(auto& tmp:node.child())
|
||||
{
|
||||
if(tmp.type()==ast_default)
|
||||
checked_default=true;
|
||||
else if(tmp.type()==ast_dynamic)
|
||||
checked_dynamic=true;
|
||||
if(checked_default && tmp.type()!=ast_default)
|
||||
die(tmp.line(),"must use default paras after using once: "+format);
|
||||
if(checked_dynamic && &tmp!=&node.child().back())
|
||||
die(tmp.line(),"dynamic para must be the end: "+format);
|
||||
}
|
||||
std::unordered_map<string,bool> argname;
|
||||
for(auto& tmp:node.child())
|
||||
{
|
||||
string name;
|
||||
switch(tmp.type())
|
||||
{
|
||||
case ast_dynamic:
|
||||
case ast_id: name=tmp.str();break;
|
||||
case ast_default:name=tmp.str();break;
|
||||
}
|
||||
if(argname.count(name))
|
||||
die(tmp.line(),"parameter's name repeats: "+name);
|
||||
else
|
||||
argname[name]=true;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
ast parse::lcurve_expr()
|
||||
|
@ -496,12 +461,13 @@ ast parse::lcurve_expr()
|
|||
ast parse::expr()
|
||||
{
|
||||
u32 type=toks[ptr].type;
|
||||
if((type==tok_break || type==tok_continue) && !in_loop)
|
||||
die(err_line,"should use break/continue in loops");
|
||||
if(type==tok_ret && !in_func)
|
||||
die(err_line,"should use return in functions");
|
||||
switch(type)
|
||||
{
|
||||
if((type==tok_break || type==tok_continue) && !in_loop){
|
||||
die(thisline,thiscol,thislen,"must use break/continue in loops");
|
||||
}
|
||||
if(type==tok_ret && !in_func){
|
||||
die(thisline,thiscol,thislen,"must use return in functions");
|
||||
}
|
||||
switch(type){
|
||||
case tok_nil:
|
||||
case tok_num:
|
||||
case tok_str:
|
||||
|
@ -523,7 +489,7 @@ ast parse::expr()
|
|||
case tok_ret: return ret_expr(); break;
|
||||
case tok_semi: break;
|
||||
default:
|
||||
die(err_line,"incorrect token <"+toks[ptr].str+">");
|
||||
die(thisline,thiscol,thislen,"incorrect token <"+toks[ptr].str+">");
|
||||
next();
|
||||
break;
|
||||
}
|
||||
|
@ -531,28 +497,24 @@ ast parse::expr()
|
|||
}
|
||||
ast parse::exprs()
|
||||
{
|
||||
if(lookahead(tok_eof))
|
||||
{
|
||||
die(err_line,"expected expression block");
|
||||
if(lookahead(tok_eof)){
|
||||
die(thisline,thiscol,thislen,"expected expression block");
|
||||
return null();
|
||||
}
|
||||
ast node(toks[ptr].line,toks[ptr].col,ast_block);
|
||||
if(lookahead(tok_lbrace))
|
||||
{
|
||||
if(lookahead(tok_lbrace)){
|
||||
match(tok_lbrace);
|
||||
while(!lookahead(tok_rbrace) && !lookahead(tok_eof))
|
||||
{
|
||||
while(!lookahead(tok_rbrace) && !lookahead(tok_eof)){
|
||||
node.add(expr());
|
||||
if(lookahead(tok_semi))
|
||||
if(lookahead(tok_semi)){
|
||||
match(tok_semi);
|
||||
}else if(need_semi_check(node.child().back()) && !lookahead(tok_rbrace)){
|
||||
// the last expression can be recognized without semi
|
||||
else if(need_semi_check(node.child().back()) && !lookahead(tok_rbrace))
|
||||
die(err_line,"expected ';'",true);
|
||||
die(thisline,thiscol,thislen,"expected ';'",true);
|
||||
}
|
||||
}
|
||||
match(tok_rbrace,"expected '}' when generating expressions");
|
||||
}
|
||||
else
|
||||
{
|
||||
}else{
|
||||
node.add(expr());
|
||||
if(lookahead(tok_semi))
|
||||
match(tok_semi);
|
||||
|
@ -562,8 +524,7 @@ ast parse::exprs()
|
|||
ast parse::calc()
|
||||
{
|
||||
ast node=or_expr();
|
||||
if(lookahead(tok_quesmark))
|
||||
{
|
||||
if(lookahead(tok_quesmark)){
|
||||
// trinocular calculation
|
||||
ast tmp(toks[ptr].line,toks[ptr].col,ast_trino);
|
||||
match(tok_quesmark);
|
||||
|
@ -572,9 +533,7 @@ ast parse::calc()
|
|||
match(tok_colon);
|
||||
tmp.add(calc());
|
||||
node=std::move(tmp);
|
||||
}
|
||||
else if(tok_eq<=toks[ptr].type && toks[ptr].type<=tok_lnkeq)
|
||||
{
|
||||
}else if(tok_eq<=toks[ptr].type && toks[ptr].type<=tok_lnkeq){
|
||||
check_memory_reachable(node);
|
||||
// tok_eq~tok_lnkeq is 37 to 42,ast_equal~ast_lnkeq is 21~26
|
||||
ast tmp(toks[ptr].line,toks[ptr].col,toks[ptr].type-tok_eq+ast_equal);
|
||||
|
@ -588,8 +547,7 @@ ast parse::calc()
|
|||
ast parse::or_expr()
|
||||
{
|
||||
ast node=and_expr();
|
||||
while(lookahead(tok_or))
|
||||
{
|
||||
while(lookahead(tok_or)){
|
||||
ast tmp(toks[ptr].line,toks[ptr].col,ast_or);
|
||||
tmp.add(std::move(node));
|
||||
match(tok_or);
|
||||
|
@ -601,8 +559,7 @@ ast parse::or_expr()
|
|||
ast parse::and_expr()
|
||||
{
|
||||
ast node=cmp_expr();
|
||||
while(lookahead(tok_and))
|
||||
{
|
||||
while(lookahead(tok_and)){
|
||||
ast tmp(toks[ptr].line,toks[ptr].col,ast_and);
|
||||
tmp.add(std::move(node));
|
||||
match(tok_and);
|
||||
|
@ -614,8 +571,7 @@ ast parse::and_expr()
|
|||
ast parse::cmp_expr()
|
||||
{
|
||||
ast node=additive_expr();
|
||||
while(tok_cmpeq<=toks[ptr].type && toks[ptr].type<=tok_geq)
|
||||
{
|
||||
while(tok_cmpeq<=toks[ptr].type && toks[ptr].type<=tok_geq){
|
||||
// tok_cmpeq~tok_geq is 43~48,ast_cmpeq~ast_geq is 27~32
|
||||
ast tmp(toks[ptr].line,toks[ptr].col,toks[ptr].type-tok_cmpeq+ast_cmpeq);
|
||||
tmp.add(std::move(node));
|
||||
|
@ -628,11 +584,9 @@ ast parse::cmp_expr()
|
|||
ast parse::additive_expr()
|
||||
{
|
||||
ast node=multive_expr();
|
||||
while(lookahead(tok_add) || lookahead(tok_sub) || lookahead(tok_link))
|
||||
{
|
||||
while(lookahead(tok_add) || lookahead(tok_sub) || lookahead(tok_link)){
|
||||
ast tmp(toks[ptr].line,toks[ptr].col,ast_null);
|
||||
switch(toks[ptr].type)
|
||||
{
|
||||
switch(toks[ptr].type){
|
||||
case tok_add: tmp.set_type(ast_add); break;
|
||||
case tok_sub: tmp.set_type(ast_sub); break;
|
||||
case tok_link: tmp.set_type(ast_link); break;
|
||||
|
@ -647,8 +601,7 @@ ast parse::additive_expr()
|
|||
ast parse::multive_expr()
|
||||
{
|
||||
ast node=(lookahead(tok_sub) || lookahead(tok_not))?unary():scalar();
|
||||
while(lookahead(tok_mult) || lookahead(tok_div))
|
||||
{
|
||||
while(lookahead(tok_mult) || lookahead(tok_div)){
|
||||
ast tmp(toks[ptr].line,toks[ptr].col,toks[ptr].type-tok_mult+ast_mult);
|
||||
tmp.add(std::move(node));
|
||||
match(toks[ptr].type);
|
||||
|
@ -660,8 +613,7 @@ ast parse::multive_expr()
|
|||
ast parse::unary()
|
||||
{
|
||||
ast node(toks[ptr].line,toks[ptr].col,ast_null);
|
||||
switch(toks[ptr].type)
|
||||
{
|
||||
switch(toks[ptr].type){
|
||||
case tok_sub:node.set_type(ast_neg);match(tok_sub);break;
|
||||
case tok_not:node.set_type(ast_not);match(tok_not);break;
|
||||
}
|
||||
|
@ -671,47 +623,49 @@ ast parse::unary()
|
|||
ast parse::scalar()
|
||||
{
|
||||
ast node(toks[ptr].line,toks[ptr].col,ast_null);
|
||||
if(lookahead(tok_nil)) {node=nil();match(tok_nil);}
|
||||
else if(lookahead(tok_num)) node=num();
|
||||
else if(lookahead(tok_str)) node=str();
|
||||
else if(lookahead(tok_id)) node=id();
|
||||
else if(lookahead(tok_func)) node=func();
|
||||
else if(lookahead(tok_lbracket)) node=vec();
|
||||
else if(lookahead(tok_lbrace)) node=hash();
|
||||
else if(lookahead(tok_lcurve))
|
||||
{
|
||||
if(lookahead(tok_nil)){
|
||||
node=nil();
|
||||
match(tok_nil);
|
||||
}else if(lookahead(tok_num)){
|
||||
node=num();
|
||||
}else if(lookahead(tok_str)){
|
||||
node=str();
|
||||
}else if(lookahead(tok_id)){
|
||||
node=id();
|
||||
}else if(lookahead(tok_func)){
|
||||
node=func();
|
||||
}else if(lookahead(tok_lbracket)){
|
||||
node=vec();
|
||||
}else if(lookahead(tok_lbrace)){
|
||||
node=hash();
|
||||
}else if(lookahead(tok_lcurve)){
|
||||
match(tok_lcurve);
|
||||
node=calc();
|
||||
match(tok_rcurve);
|
||||
}
|
||||
else if(lookahead(tok_var))
|
||||
{
|
||||
}else if(lookahead(tok_var)){
|
||||
match(tok_var);
|
||||
node.set_type(ast_def);
|
||||
node.add(id());
|
||||
match(tok_eq);
|
||||
node.add(calc());
|
||||
}
|
||||
else
|
||||
{
|
||||
die(err_line,"expected scalar");
|
||||
}else{
|
||||
die(thisline,thiscol,thislen,"expected scalar");
|
||||
return node;
|
||||
}
|
||||
// check call and avoid ambiguous syntax
|
||||
if(is_call(toks[ptr].type) && !(lookahead(tok_lcurve) && toks[ptr+1].type==tok_var))
|
||||
{
|
||||
if(is_call(toks[ptr].type) && !(lookahead(tok_lcurve) && toks[ptr+1].type==tok_var)){
|
||||
ast tmp=std::move(node);
|
||||
node={toks[ptr].line,toks[ptr].col,ast_call};
|
||||
node.add(std::move(tmp));
|
||||
while(is_call(toks[ptr].type))
|
||||
while(is_call(toks[ptr].type)){
|
||||
node.add(call_scalar());
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
ast parse::call_scalar()
|
||||
{
|
||||
switch(toks[ptr].type)
|
||||
{
|
||||
switch(toks[ptr].type){
|
||||
case tok_lcurve: return callf(); break;
|
||||
case tok_lbracket: return callv(); break;
|
||||
case tok_dot: return callh(); break;
|
||||
|
@ -741,18 +695,19 @@ ast parse::callv()
|
|||
};
|
||||
ast node(toks[ptr].line,toks[ptr].col,ast_callv);
|
||||
match(tok_lbracket);
|
||||
while(!lookahead(tok_rbracket))
|
||||
{
|
||||
while(!lookahead(tok_rbracket)){
|
||||
node.add(subvec());
|
||||
if(lookahead(tok_comma))
|
||||
if(lookahead(tok_comma)){
|
||||
match(tok_comma);
|
||||
else if(lookahead(tok_eof))
|
||||
}else if(lookahead(tok_eof)){
|
||||
break;
|
||||
else if(!lookahead(tok_rbracket) && !check_comma(panic_set))
|
||||
}else if(!lookahead(tok_rbracket) && !check_comma(panic_set)){
|
||||
break;
|
||||
}
|
||||
if(node.size()==0)
|
||||
die(node.line(),"expected index value");
|
||||
}
|
||||
if(node.size()==0){
|
||||
die(node.line(),node.col(),1,"expected index value");
|
||||
}
|
||||
match(tok_rbracket,"expected ']' when calling vector");
|
||||
return node;
|
||||
}
|
||||
|
@ -770,8 +725,7 @@ ast parse::callf()
|
|||
ast node(toks[ptr].line,toks[ptr].col,ast_callf);
|
||||
bool special_call=check_special_call();
|
||||
match(tok_lcurve);
|
||||
while(!lookahead(tok_rcurve))
|
||||
{
|
||||
while(!lookahead(tok_rcurve)){
|
||||
node.add(special_call?pair():calc());
|
||||
if(lookahead(tok_comma))
|
||||
match(tok_comma);
|
||||
|
@ -786,8 +740,7 @@ ast parse::callf()
|
|||
ast parse::subvec()
|
||||
{
|
||||
ast node=lookahead(tok_colon)?nil():calc();
|
||||
if(lookahead(tok_colon))
|
||||
{
|
||||
if(lookahead(tok_colon)){
|
||||
ast tmp(node.line(),node.col(),ast_subvec);
|
||||
match(tok_colon);
|
||||
tmp.add(std::move(node));
|
||||
|
@ -799,27 +752,22 @@ ast parse::subvec()
|
|||
ast parse::definition()
|
||||
{
|
||||
ast node(toks[ptr].line,toks[ptr].col,ast_def);
|
||||
if(lookahead(tok_var))
|
||||
{
|
||||
if(lookahead(tok_var)){
|
||||
match(tok_var);
|
||||
switch(toks[ptr].type)
|
||||
{
|
||||
switch(toks[ptr].type){
|
||||
case tok_id: node.add(id());break;
|
||||
case tok_lcurve: node.add(outcurve_def());break;
|
||||
default: die(err_line,"expected identifier");break;
|
||||
default: die(thisline,thiscol,thislen,"expected identifier");break;
|
||||
}
|
||||
}
|
||||
else if(lookahead(tok_lcurve))
|
||||
}else if(lookahead(tok_lcurve)){
|
||||
node.add(incurve_def());
|
||||
}
|
||||
match(tok_eq);
|
||||
if(lookahead(tok_lcurve))
|
||||
if(lookahead(tok_lcurve)){
|
||||
node.add(check_tuple()?multi_scalar(false):calc());
|
||||
else
|
||||
}else{
|
||||
node.add(calc());
|
||||
if(node[0].type()==ast_id && node[1].type()==ast_tuple)
|
||||
die(node[1].line(),"one variable cannot accept too many values");
|
||||
else if(node[0].type()==ast_multi_id && node[1].type()==ast_tuple && node[0].size()!=node[1].size())
|
||||
die(node[0].line(),"too much or lack values in multi-definition");
|
||||
}
|
||||
return node;
|
||||
}
|
||||
ast parse::incurve_def()
|
||||
|
@ -840,21 +788,20 @@ ast parse::outcurve_def()
|
|||
ast parse::multi_id()
|
||||
{
|
||||
ast node(toks[ptr].line,toks[ptr].col,ast_multi_id);
|
||||
while(!lookahead(tok_eof))
|
||||
{
|
||||
while(!lookahead(tok_eof)){
|
||||
node.add(id());
|
||||
if(is_call(toks[ptr].type))
|
||||
{
|
||||
call_scalar();// recognize calls but this is still a syntax error
|
||||
die(err_line,"cannot call identifier in multi-definition");
|
||||
if(is_call(toks[ptr].type)){
|
||||
ast tmp=call_scalar();// recognize calls but this is still a syntax error
|
||||
die(tmp.line(),tmp.col(),1,"cannot call identifier in multi-definition");
|
||||
}
|
||||
if(lookahead(tok_comma))
|
||||
if(lookahead(tok_comma)){
|
||||
match(tok_comma);
|
||||
else if(lookahead(tok_id))// first set of identifier
|
||||
die(err_line,"expected ',' between identifiers",true);
|
||||
else
|
||||
}else if(lookahead(tok_id)){ // first set of identifier
|
||||
die(thisline,thiscol,thislen,"expected ',' between identifiers",true);
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
ast parse::multi_scalar(bool check_call_memory)
|
||||
|
@ -868,18 +815,19 @@ ast parse::multi_scalar(bool check_call_memory)
|
|||
};
|
||||
ast node(toks[ptr].line,toks[ptr].col,ast_tuple);
|
||||
match(tok_lcurve);
|
||||
while(!lookahead(tok_rcurve))
|
||||
{
|
||||
while(!lookahead(tok_rcurve)){
|
||||
node.add(calc());
|
||||
if(check_call_memory)
|
||||
if(check_call_memory){
|
||||
check_memory_reachable(node.child().back());
|
||||
if(lookahead(tok_comma))
|
||||
}
|
||||
if(lookahead(tok_comma)){
|
||||
match(tok_comma);
|
||||
else if(lookahead(tok_eof))
|
||||
}else if(lookahead(tok_eof)){
|
||||
break;
|
||||
else if(!lookahead(tok_rcurve) && !check_comma(panic_set))
|
||||
}else if(!lookahead(tok_rcurve) && !check_comma(panic_set)){
|
||||
break;
|
||||
}
|
||||
}
|
||||
match(tok_rcurve,"expected ')' after multi-scalar");
|
||||
return node;
|
||||
}
|
||||
|
@ -888,26 +836,22 @@ ast parse::multi_assgin()
|
|||
ast node(toks[ptr].line,toks[ptr].col,ast_multi_assign);
|
||||
node.add(multi_scalar(true));
|
||||
match(tok_eq);
|
||||
if(lookahead(tok_eof))
|
||||
{
|
||||
die(err_line,"expected value list");
|
||||
if(lookahead(tok_eof)){
|
||||
die(thisline,thiscol,thislen,"expected value list");
|
||||
return node;
|
||||
}
|
||||
if(lookahead(tok_lcurve))
|
||||
if(lookahead(tok_lcurve)){
|
||||
node.add(check_tuple()?multi_scalar(false):calc());
|
||||
else
|
||||
}else{
|
||||
node.add(calc());
|
||||
if(node[1].type()==ast_tuple
|
||||
&& node[0].size()!=node[1].size())
|
||||
die(node[0].line(),"too much or lack values in multi-assignment");
|
||||
}
|
||||
return node;
|
||||
}
|
||||
ast parse::loop()
|
||||
{
|
||||
++in_loop;
|
||||
ast node(0,0,ast_null);
|
||||
switch(toks[ptr].type)
|
||||
{
|
||||
switch(toks[ptr].type){
|
||||
case tok_while: node=while_loop(); break;
|
||||
case tok_for: node=for_loop(); break;
|
||||
case tok_forindex:
|
||||
|
@ -932,32 +876,38 @@ ast parse::for_loop()
|
|||
match(tok_for);
|
||||
match(tok_lcurve);
|
||||
// first expression
|
||||
if(lookahead(tok_eof))
|
||||
die(err_line,"expected definition");
|
||||
if(lookahead(tok_semi))
|
||||
if(lookahead(tok_eof)){
|
||||
die(thisline,thiscol,thislen,"expected definition");
|
||||
}
|
||||
if(lookahead(tok_semi)){
|
||||
node.add(null());
|
||||
else if(lookahead(tok_var))
|
||||
}else if(lookahead(tok_var)){
|
||||
node.add(definition());
|
||||
else if(lookahead(tok_lcurve))
|
||||
}else if(lookahead(tok_lcurve)){
|
||||
node.add(lcurve_expr());
|
||||
else
|
||||
}else{
|
||||
node.add(calc());
|
||||
}
|
||||
match(tok_semi,"expected ';' in for(;;)");
|
||||
// conditional expression
|
||||
if(lookahead(tok_eof))
|
||||
die(err_line,"expected conditional expr");
|
||||
if(lookahead(tok_semi))
|
||||
if(lookahead(tok_eof)){
|
||||
die(thisline,thiscol,thislen,"expected conditional expr");
|
||||
}
|
||||
if(lookahead(tok_semi)){
|
||||
node.add(null());
|
||||
else
|
||||
}else{
|
||||
node.add(calc());
|
||||
}
|
||||
match(tok_semi,"expected ';' in for(;;)");
|
||||
//after loop expression
|
||||
if(lookahead(tok_eof))
|
||||
die(err_line,"expected calculation");
|
||||
if(lookahead(tok_rcurve))
|
||||
if(lookahead(tok_eof)){
|
||||
die(thisline,thiscol,thislen,"expected calculation");
|
||||
}
|
||||
if(lookahead(tok_rcurve)){
|
||||
node.add(null());
|
||||
else
|
||||
}else{
|
||||
node.add(calc());
|
||||
}
|
||||
match(tok_rcurve);
|
||||
node.add(exprs());
|
||||
return node;
|
||||
|
@ -965,20 +915,21 @@ ast parse::for_loop()
|
|||
ast parse::forei_loop()
|
||||
{
|
||||
ast node(toks[ptr].line,toks[ptr].col,ast_null);
|
||||
switch(toks[ptr].type)
|
||||
{
|
||||
switch(toks[ptr].type){
|
||||
case tok_forindex:node.set_type(ast_forindex);match(tok_forindex);break;
|
||||
case tok_foreach: node.set_type(ast_foreach); match(tok_foreach); break;
|
||||
}
|
||||
match(tok_lcurve);
|
||||
// first expression
|
||||
// foreach/forindex must have an iterator to loop through
|
||||
if(!lookahead(tok_var) && !lookahead(tok_id))
|
||||
die(err_line,"expected iterator");
|
||||
if(!lookahead(tok_var) && !lookahead(tok_id)){
|
||||
die(thisline,thiscol,thislen,"expected iterator");
|
||||
}
|
||||
node.add(iter_gen());
|
||||
match(tok_semi,"expected ';' in foreach/forindex(iter;vector)");
|
||||
if(lookahead(tok_eof))
|
||||
die(err_line,"expected vector");
|
||||
if(lookahead(tok_eof)){
|
||||
die(thisline,thiscol,thislen,"expected vector");
|
||||
}
|
||||
node.add(calc());
|
||||
match(tok_rcurve);
|
||||
node.add(exprs());
|
||||
|
@ -987,18 +938,16 @@ ast parse::forei_loop()
|
|||
ast parse::iter_gen()
|
||||
{
|
||||
ast node(toks[ptr].line,toks[ptr].col,ast_null);
|
||||
if(lookahead(tok_var))
|
||||
{
|
||||
if(lookahead(tok_var)){
|
||||
match(tok_var);
|
||||
node.set_type(ast_iter);
|
||||
node.add(id());
|
||||
}
|
||||
else
|
||||
{
|
||||
}else{
|
||||
node.set_type(ast_call);
|
||||
node.add(id());
|
||||
while(is_call(toks[ptr].type))
|
||||
while(is_call(toks[ptr].type)){
|
||||
node.add(call_scalar());
|
||||
}
|
||||
check_memory_reachable(node);
|
||||
}
|
||||
return node;
|
||||
|
@ -1013,8 +962,7 @@ ast parse::cond()
|
|||
match(tok_rcurve);
|
||||
ifnode.add(exprs());
|
||||
node.add(std::move(ifnode));
|
||||
while(lookahead(tok_elsif))
|
||||
{
|
||||
while(lookahead(tok_elsif)){
|
||||
ast elsifnode(toks[ptr].line,toks[ptr].col,ast_elsif);
|
||||
match(tok_elsif);
|
||||
match(tok_lcurve);
|
||||
|
@ -1023,8 +971,7 @@ ast parse::cond()
|
|||
elsifnode.add(exprs());
|
||||
node.add(std::move(elsifnode));
|
||||
}
|
||||
if(lookahead(tok_else))
|
||||
{
|
||||
if(lookahead(tok_else)){
|
||||
ast elsenode(toks[ptr].line,toks[ptr].col,ast_else);
|
||||
match(tok_else);
|
||||
elsenode.add(exprs());
|
||||
|
@ -1049,11 +996,11 @@ ast parse::ret_expr()
|
|||
ast node(toks[ptr].line,toks[ptr].col,ast_ret);
|
||||
match(tok_ret);
|
||||
u32 type=toks[ptr].type;
|
||||
if(type==tok_nil || type==tok_num ||
|
||||
type==tok_str || type==tok_id ||
|
||||
type==tok_func || type==tok_sub ||
|
||||
type==tok_not || type==tok_lcurve ||
|
||||
type==tok_lbracket || type==tok_lbrace)
|
||||
if(type==tok_nil || type==tok_num || type==tok_str || type==tok_id ||
|
||||
type==tok_func || type==tok_sub || type==tok_not || type==tok_lcurve ||
|
||||
type==tok_lbracket || type==tok_lbrace
|
||||
){
|
||||
node.add(calc());
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
|
|
@ -51,19 +51,25 @@ libfib.close();
|
|||
|
||||
var speed_test=func(){
|
||||
var d=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
|
||||
println("[dylib ] ",d);
|
||||
var fd=d.quick_fib;
|
||||
var vec_call=dylib.dlcall;
|
||||
var invoke=dylib.limitcall(1);
|
||||
|
||||
var tm=maketimestamp();
|
||||
var duration=0;
|
||||
|
||||
for(var t=0;t<10;t+=1){
|
||||
tm.stamp();
|
||||
for(var i=0;i<1e7;i+=1)
|
||||
for(var i=0;i<5e6;i+=1)
|
||||
invoke(fd,40);
|
||||
println("[time ] limited call: ",tm.elapsedMSec()," ms");
|
||||
duration=tm.elapsedMSec();
|
||||
println("[time ] limited call: ",duration," ms avg ",5e6/duration," call/ms");
|
||||
tm.stamp();
|
||||
for(var i=0;i<1e7;i+=1)
|
||||
for(var i=0;i<5e6;i+=1)
|
||||
vec_call(fd,40);
|
||||
println("[time ] dynamic call: ",tm.elapsedMSec()," ms");
|
||||
duration=tm.elapsedMSec();
|
||||
println("[time ] dynamic call: ",duration," ms avg ",5e6/duration," call/ms");
|
||||
}
|
||||
}
|
||||
|
||||
speed_test();
|
Loading…
Reference in New Issue