update error report for parser&codegen

This commit is contained in:
ValKmjolnir 2023-03-08 23:53:02 +08:00
parent 1678567c5d
commit dbc2c365b4
5 changed files with 157 additions and 46 deletions

View File

@ -185,6 +185,8 @@ public:
const span& location() const {return loc;}
const std::vector<ast>& child() const {return nd_child;}
std::vector<ast>& child() {return nd_child;}
void update_span();
void update_span(const span&);
};
void ast::set_begin(const u32 l,const u32 c) {
@ -198,7 +200,7 @@ void ast::set_end(const u32 l,const u32 c) {
}
void ast::clear() {
loc={0,0,0,0};
loc={0,0,0,0,""};
nd_num=0;
nd_str.clear();
nd_type=ast_null;
@ -250,3 +252,41 @@ void ast::print(u32 depth,bool last,std::vector<string>& indent) const{
indent.pop_back();
}
}
void ast::update_span() {
if (!nd_child.size()) {
return;
}
for(const auto& i:nd_child) {
if (loc.begin_line>i.loc.begin_line) {
loc.begin_line=i.loc.begin_line;
loc.begin_column=i.loc.begin_column;
} else if (loc.begin_line==i.loc.begin_line && loc.begin_column>i.loc.begin_column) {
loc.begin_column=i.loc.begin_column;
}
if (loc.end_line<i.loc.end_line) {
loc.end_line=i.loc.end_line;
loc.end_column=i.loc.end_column;
} else if (loc.end_line==i.loc.end_line && loc.end_column<i.loc.end_column) {
loc.end_column=i.loc.end_column;
}
loc.file=i.loc.file;
}
}
void ast::update_span(const span& tloc) {
update_span();
if (loc.begin_line>tloc.begin_line) {
loc.begin_line=tloc.begin_line;
loc.begin_column=tloc.begin_column;
} else if (loc.begin_line==tloc.begin_line && loc.begin_column>tloc.begin_column) {
loc.begin_column=tloc.begin_column;
}
if (loc.end_line<tloc.end_line) {
loc.end_line=tloc.end_line;
loc.end_column=tloc.end_column;
} else if (loc.end_line==tloc.end_line && loc.end_column<tloc.end_column) {
loc.end_column=tloc.end_column;
}
loc.file=tloc.file;
}

View File

@ -223,7 +223,10 @@ private:
bool check_memory_reachable(const ast&);
void die(const string&,const u32,const u32,const u32);
void die(const string& info,const span& loc) {
err.err("code",loc,info);
}
void regist_num(const f64);
void regist_str(const string&);
void find_symbol(const ast&);
@ -279,25 +282,20 @@ bool codegen::check_memory_reachable(const ast& node) {
if (node.type()==ast_call) {
const ast& tmp=node.child().back();
if (tmp.type()==ast_callf) {
die("bad left-value",tmp.line(),tmp.col(),1);
die("bad left-value with function call",node.location());
return false;
}
if (tmp.type()==ast_callv && (tmp.size()==0 || tmp.size()>1 || tmp[0].type()==ast_subvec)) {
die("bad left-value",tmp.line(),tmp.col(),1);
die("bad left-value with subvec",node.location());
return false;
}
} else if (node.type()!=ast_id) {
die("bad left-value",node.line(),node.col(),1);
die("bad left-value",node.location());
return false;
}
return true;
}
void codegen::die(const string& info,const u32 line,const u32 col,const u32 len=1) {
err.load(file[fileindex]);
err.err("code",{line,col-len,line,col,file[fileindex]},info);
}
void codegen::regist_num(const f64 num) {
if (!num_table.count(num)) {
u32 size=num_table.size();
@ -431,15 +429,15 @@ void codegen::func_gen(const ast& node) {
}
// 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());
die("must use default parameters here",tmp.location());
}
if (checked_dynamic && &tmp!=&node[0].child().back()) {
die("dynamic parameter must be the last one",tmp.line(),tmp.col(),tmp.str().length());
die("dynamic parameter must be the last one",tmp.location());
}
// check redefinition
string name=tmp.str();
if (argname.count(name)) {
die("redefinition of parameter: "+name,tmp.line(),tmp.col(),name.length());
die("redefinition of parameter: "+name,tmp.location());
} else {
argname[name]=true;
}
@ -461,7 +459,7 @@ void codegen::func_gen(const ast& node) {
for(auto& tmp:node[0].child()) {
const string& str=tmp.str();
if (str=="me") {
die("\"me\" should not be a parameter",tmp.line(),tmp.col(),tmp.str().length());
die("\"me\" should not be a parameter",tmp.location());
}
regist_str(str);
switch(tmp.type()) {
@ -488,7 +486,7 @@ void codegen::func_gen(const ast& node) {
in_iterloop.pop();
code[lsize].num=local.back().size();
if (local.back().size()>=STACK_DEPTH) {
die("too many local variants: "+std::to_string(local.back().size()),block.line(),0);
die("too many local variants: "+std::to_string(local.back().size()),block.location());
}
local.pop_back();
@ -520,7 +518,7 @@ void codegen::call_id(const ast& node) {
if (builtin[i].name==str) {
gen(op_callb,i,node.line());
if (local.empty()) {
die("should warp native function in local scope",node.line(),node.col(),node.str().length());
die("should warp native function in local scope",node.location());
}
return;
}
@ -538,7 +536,7 @@ void codegen::call_id(const ast& node) {
gen(op_callg,index,node.line());
return;
}
die("undefined symbol \""+str+"\"",node.line(),node.col(),node.str().length());
die("undefined symbol \""+str+"\"",node.location());
}
void codegen::call_hash(const ast& node) {
@ -622,7 +620,7 @@ void codegen::mcall_id(const ast& node) {
const string& str=node.str();
for(u32 i=0;builtin[i].name;++i) {
if (builtin[i].name==str) {
die("cannot modify native function",node.line(),node.col(),node.str().length());
die("cannot modify native function",node.location());
return;
}
}
@ -639,7 +637,7 @@ void codegen::mcall_id(const ast& node) {
gen(op_mcallg,index,node.line());
return;
}
die("undefined symbol \""+str+"\"",node.line(),node.col(),node.str().length());
die("undefined symbol \""+str+"\"",node.location());
}
void codegen::mcall_vec(const ast& node) {
@ -665,6 +663,11 @@ void codegen::multi_def(const ast& node) {
if (node[1].type()==ast_tuple) { // (var a,b,c)=(c,b,a);
auto& vals=node[1].child();
for(usize i=0;i<size;++i) {
// check node type, only identifier is allowed
if (ids[i].type()!=ast_id) {
die("cannot call identifier in multi-definition",ids[i].location());
continue;
}
calc_gen(vals[i]);
const string& str=ids[i].str();
local.empty()?
@ -674,6 +677,11 @@ void codegen::multi_def(const ast& node) {
} else { // (var a,b,c)=[0,1,2];
calc_gen(node[1]);
for(usize i=0;i<size;++i) {
// check node type, only identifier is allowed
if (ids[i].type()!=ast_id) {
die("cannot call identifier in multi-definition",ids[i].location());
continue;
}
gen(op_callvi,i,node[1].line());
const string& str=ids[i].str();
local.empty()?
@ -686,20 +694,20 @@ 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);
die("cannot accept too many values",node[1].location());
} 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);
die("lack values in multi-definition",node[1].location());
} 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);
die("too many values in multi-definition",node[1].location());
}
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);
die("lack values in multi-assignment",node[1].location());
} 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);
die("too many values in multi-assignment",node[1].location());
}
i32 size=node[0].size();
if (node[1].type()==ast_tuple) {

View File

@ -100,11 +100,11 @@ private:
return string(len,' ');
}
string leftpad(u32 num,usize len) {
string res=std::to_string(num);
while(res.length()<len) {
res=" "+res;
string tmp=std::to_string(num);
while(tmp.length()<len) {
tmp=" "+tmp;
}
return res;
return tmp;
}
public:
error():cnt(0) {}
@ -175,7 +175,7 @@ void error::err(const string& stage,const span& loc,const string& info) {
const string iden=identation(maxlen);
for(u32 line=loc.begin_line;line<=loc.end_line;++line) {
if (!line || !res[line-1].length()) {
if (!line) {
continue;
}
@ -186,30 +186,35 @@ void error::err(const string& stage,const span& loc,const string& info) {
continue;
}
// if this line has nothing, skip
if (!res[line-1].length() && line!=loc.end_line) {
continue;
}
const string& code=res[line-1];
std::cerr<<cyan<<leftpad(line,maxlen)<<" | "<<reset<<code<<"\n";
// output underline
std::cerr<<cyan<<iden<<" | "<<reset;
if (loc.begin_line==loc.end_line) {
for(i32 i=0;i<loc.begin_column;++i) {
for(u32 i=0;i<loc.begin_column;++i) {
std::cerr<<char(" \t"[code[i]=='\t']);
}
for(i32 i=loc.begin_column;i<loc.end_column;++i) {
for(u32 i=loc.begin_column;i<loc.end_column;++i) {
std::cerr<<red<<(code[i]=='\t'?"^^^^":"^")<<reset;
}
} else if (line==loc.begin_line) {
for(i32 i=0;i<loc.begin_column;++i) {
for(u32 i=0;i<loc.begin_column;++i) {
std::cerr<<char(" \t"[code[i]=='\t']);
}
for(i32 i=loc.begin_column;i<code.size();++i) {
for(u32 i=loc.begin_column;i<code.size();++i) {
std::cerr<<red<<(code[i]=='\t'?"^^^^":"^")<<reset;
}
} else if (loc.begin_line<line && line<loc.end_line) {
for(i32 i=0;i<code.size();++i) {
for(u32 i=0;i<code.size();++i) {
std::cerr<<red<<(code[i]=='\t'?"^^^^":"^");
}
} else {
for(i32 i=0;i<loc.end_column;++i) {
for(u32 i=0;i<loc.end_column;++i) {
std::cerr<<red<<(code[i]=='\t'?"^^^^":"^");
}
}

View File

@ -176,7 +176,7 @@ const error& parse::compile(const lexer& lexer) {
toks=lexer.result().data();
ptr=in_func=in_loop=0;
root={{0,0,0,0,toks[0].loc.file},ast_root};
root={toks[0].loc,ast_root};
while(!lookahead(tok::eof)) {
root.add(expr());
if (lookahead(tok::semi)) {
@ -186,6 +186,7 @@ const error& parse::compile(const lexer& lexer) {
die(prevspan,"expected \";\"");
}
}
root.update_span();
return err;
}
@ -368,6 +369,7 @@ ast parse::vec() {
break;
}
}
node.update_span(thisspan);
match(tok::rbracket,"expected ']' when generating vector");
return node;
}
@ -385,6 +387,7 @@ ast parse::hash() {
break;
}
}
node.update_span(thisspan);
match(tok::rbrace,"expected '}' when generating hash");
return node;
}
@ -400,6 +403,7 @@ ast parse::pair() {
}
match(tok::colon);
node.add(calc());
node.update_span();
return node;
}
@ -414,6 +418,7 @@ ast parse::func() {
}
node.add(exprs());
--in_func;
node.update_span();
return node;
}
@ -446,6 +451,7 @@ ast parse::params() {
break;
}
}
node.update_span(thisspan);
match(tok::rcurve,"expected ')' after parameter list");
return node;
}
@ -493,6 +499,8 @@ ast parse::expr() {
next();
break;
}
// unreachable
return {toks[ptr].loc,ast_null};
}
@ -519,6 +527,7 @@ ast parse::exprs() {
if (lookahead(tok::semi))
match(tok::semi);
}
node.update_span();
return node;
}
@ -547,6 +556,7 @@ ast parse::calc() {
tmp.add(calc());
node=std::move(tmp);
}
node.update_span();
return node;
}
@ -557,8 +567,10 @@ ast parse::bitwise_or() {
tmp.add(std::move(node));
match(tok::btor);
tmp.add(bitwise_xor());
tmp.update_span();
node=std::move(tmp);
}
node.update_span();
return node;
}
@ -569,8 +581,10 @@ ast parse::bitwise_xor() {
tmp.add(std::move(node));
match(tok::btxor);
tmp.add(bitwise_and());
tmp.update_span();
node=std::move(tmp);
}
node.update_span();
return node;
}
@ -581,8 +595,10 @@ ast parse::bitwise_and() {
tmp.add(std::move(node));
match(tok::btand);
tmp.add(or_expr());
tmp.update_span();
node=std::move(tmp);
}
node.update_span();
return node;
}
@ -593,8 +609,10 @@ ast parse::or_expr() {
tmp.add(std::move(node));
match(tok::opor);
tmp.add(and_expr());
tmp.update_span();
node=std::move(tmp);
}
node.update_span();
return node;
}
@ -605,8 +623,10 @@ ast parse::and_expr() {
tmp.add(std::move(node));
match(tok::opand);
tmp.add(cmp_expr());
tmp.update_span();
node=std::move(tmp);
}
node.update_span();
return node;
}
@ -618,8 +638,10 @@ ast parse::cmp_expr() {
tmp.add(std::move(node));
match(toks[ptr].type);
tmp.add(additive_expr());
tmp.update_span();
node=std::move(tmp);
}
node.update_span();
return node;
}
@ -636,8 +658,10 @@ ast parse::additive_expr() {
tmp.add(std::move(node));
match(toks[ptr].type);
tmp.add(multive_expr());
tmp.update_span();
node=std::move(tmp);
}
node.update_span();
return node;
}
@ -648,8 +672,10 @@ ast parse::multive_expr() {
tmp.add(std::move(node));
match(toks[ptr].type);
tmp.add((lookahead(tok::sub) || lookahead(tok::opnot) || lookahead(tok::floater))?unary():scalar());
tmp.update_span();
node=std::move(tmp);
}
node.update_span();
return node;
}
@ -662,6 +688,7 @@ ast parse::unary() {
default: break;
}
node.add((lookahead(tok::sub) || lookahead(tok::opnot) || lookahead(tok::floater))?unary():scalar());
node.update_span();
return node;
}
@ -685,8 +712,11 @@ ast parse::scalar() {
} else if (lookahead(tok::lbrace)) {
node=hash();
} else if (lookahead(tok::lcurve)) {
const auto& loc=toks[ptr].loc;
match(tok::lcurve);
node=calc();
node.set_begin(loc.begin_line,loc.begin_column);
node.update_span(thisspan);
match(tok::rcurve);
} else if (lookahead(tok::var)) {
match(tok::var);
@ -707,6 +737,7 @@ ast parse::scalar() {
node.add(call_scalar());
}
}
node.update_span();
return node;
}
@ -717,7 +748,7 @@ ast parse::call_scalar() {
case tok::dot: return callh(); break;
default: break;
}
// should never run this expression
// unreachable
return {toks[ptr].loc,ast_nil};
}
@ -725,6 +756,7 @@ ast parse::callh() {
ast node(toks[ptr].loc,ast_callh);
match(tok::dot);
node.set_str(toks[ptr].str);
node.set_end(toks[ptr].loc.end_line,toks[ptr].loc.end_column);
match(tok::id,"expected hashmap key"); // get key
return node;
}
@ -752,8 +784,9 @@ ast parse::callv() {
}
}
if (node.size()==0) {
die(node.location(),"expected index value");
die(thisspan,"expected index value");
}
node.update_span(thisspan);
match(tok::rbracket,"expected ']' when calling vector");
return node;
}
@ -780,6 +813,7 @@ ast parse::callf() {
else if (!lookahead(tok::rcurve) && !check_comma(panic))
break;
}
node.update_span(thisspan);
match(tok::rcurve,"expected ')' when calling function");
return node;
}
@ -793,6 +827,7 @@ ast parse::subvec() {
tmp.add((lookahead(tok::comma) || lookahead(tok::rbracket))?nil():calc());
node=std::move(tmp);
}
node.update_span();
return node;
}
@ -814,32 +849,37 @@ ast parse::definition() {
} else {
node.add(calc());
}
node.update_span();
return node;
}
ast parse::incurve_def() {
const auto& loc=toks[ptr].loc;
match(tok::lcurve);
match(tok::var);
ast node=multi_id();
node.update_span(thisspan);
match(tok::rcurve);
node.set_begin(loc.begin_line,loc.begin_column);
return node;
}
ast parse::outcurve_def() {
const auto& loc=toks[ptr].loc;
match(tok::lcurve);
ast node=multi_id();
node.update_span(thisspan);
match(tok::rcurve);
node.set_begin(loc.begin_line,loc.begin_column);
return node;
}
ast parse::multi_id() {
ast node(toks[ptr].loc,ast_multi_id);
while(!lookahead(tok::eof)) {
node.add(id());
if (is_call(toks[ptr].type)) {
ast tmp=call_scalar();// recognize calls but this is still a syntax error
die(tmp.location(),"cannot call identifier in multi-definition");
}
// only identifier is allowed here
// but we check it at codegen stage
node.add(calc());
if (lookahead(tok::comma)) {
match(tok::comma);
} else if (lookahead(tok::id)) { // first set of identifier
@ -848,6 +888,7 @@ ast parse::multi_id() {
break;
}
}
node.update_span();
return node;
}
@ -871,6 +912,7 @@ ast parse::multi_scalar() {
break;
}
}
node.update_span(thisspan);
match(tok::rcurve,"expected ')' after multi-scalar");
return node;
}
@ -888,6 +930,7 @@ ast parse::multi_assgin() {
} else {
node.add(calc());
}
node.update_span();
return node;
}
@ -912,6 +955,7 @@ ast parse::while_loop() {
node.add(calc());
match(tok::rcurve);
node.add(exprs());
node.update_span();
return node;
}
@ -954,6 +998,7 @@ ast parse::for_loop() {
}
match(tok::rcurve);
node.add(exprs());
node.update_span();
return node;
}
@ -978,6 +1023,7 @@ ast parse::forei_loop() {
node.add(calc());
match(tok::rcurve);
node.add(exprs());
node.update_span();
return node;
}
@ -994,18 +1040,24 @@ ast parse::iter_gen() {
node.add(call_scalar());
}
}
node.update_span();
return node;
}
ast parse::cond() {
ast node(toks[ptr].loc,ast_cond);
// generate if
ast ifnode(toks[ptr].loc,ast_if);
match(tok::rif);
match(tok::lcurve);
ifnode.add(calc());
match(tok::rcurve);
ifnode.add(exprs());
ifnode.update_span();
node.add(std::move(ifnode));
// generate elsif
while(lookahead(tok::elsif)) {
ast elsifnode(toks[ptr].loc,ast_elsif);
match(tok::elsif);
@ -1013,14 +1065,19 @@ ast parse::cond() {
elsifnode.add(calc());
match(tok::rcurve);
elsifnode.add(exprs());
elsifnode.update_span();
node.add(std::move(elsifnode));
}
// generate else
if (lookahead(tok::relse)) {
ast elsenode(toks[ptr].loc,ast_else);
match(tok::relse);
elsenode.add(exprs());
elsenode.update_span();
node.add(std::move(elsenode));
}
node.update_span();
return node;
}
@ -1046,5 +1103,6 @@ ast parse::ret_expr() {
) {
node.add(calc());
}
node.update_span();
return node;
}

View File

@ -194,9 +194,9 @@ var bp_example=func() {
# last 2 column is useless, only used to make sure bp runs correctly
var expect=[
{width:3,height:1,mat:[0,0,0]},
{width:3,height:1,mat:[1,0,0]},
{width:3,height:1,mat:[1,0,0]},
{width:3,height:1,mat:[0,0,0]}
{width:3,height:1,mat:[1,0,1]},
{width:3,height:1,mat:[1,1,0]},
{width:3,height:1,mat:[0,1,1]}
];
var hidden={
weight:mat(4,2),