✨ fix old ambiguous syntax
This commit is contained in:
parent
98b0086656
commit
6f259dc1ea
|
@ -13,7 +13,7 @@ const error& parse::compile(const lexer& lexer) {
|
||||||
match(tok::semi);
|
match(tok::semi);
|
||||||
} else if (need_semi_check(root->get_expressions().back()) && !lookahead(tok::eof)) {
|
} else if (need_semi_check(root->get_expressions().back()) && !lookahead(tok::eof)) {
|
||||||
// the last expression can be recognized without semi
|
// the last expression can be recognized without semi
|
||||||
die(prevspan, "expected \";\"");
|
die(prevspan, "expected \";\" after this token");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
update_location(root);
|
update_location(root);
|
||||||
|
@ -60,6 +60,13 @@ void parse::die(const span& loc, std::string info) {
|
||||||
err.err("parse", loc, info);
|
err.err("parse", loc, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void parse::next() {
|
||||||
|
if (lookahead(tok::eof)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
++ptr;
|
||||||
|
}
|
||||||
|
|
||||||
void parse::match(tok type, const char* info) {
|
void parse::match(tok type, const char* info) {
|
||||||
if (!lookahead(type)) {
|
if (!lookahead(type)) {
|
||||||
if (info) {
|
if (info) {
|
||||||
|
@ -70,13 +77,10 @@ void parse::match(tok type, const char* info) {
|
||||||
case tok::num:die(thisspan, "expected number"); break;
|
case tok::num:die(thisspan, "expected number"); break;
|
||||||
case tok::str:die(thisspan, "expected string"); break;
|
case tok::str:die(thisspan, "expected string"); break;
|
||||||
case tok::id: die(thisspan, "expected identifier");break;
|
case tok::id: die(thisspan, "expected identifier");break;
|
||||||
default: die(thisspan, "expected '"+tokname.at(type)+"'"); break;
|
default: die(thisspan, "expected \""+tokname.at(type)+"\""); break;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (lookahead(tok::eof)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +95,7 @@ bool parse::is_call(tok type) {
|
||||||
bool parse::check_comma(const tok* panic_set) {
|
bool parse::check_comma(const tok* panic_set) {
|
||||||
for(u32 i=0;panic_set[i]!=tok::null;++i) {
|
for(u32 i=0;panic_set[i]!=tok::null;++i) {
|
||||||
if (lookahead(panic_set[i])) {
|
if (lookahead(panic_set[i])) {
|
||||||
die(prevspan, "expected ',' between scalars");
|
die(prevspan, "expected \",\" between scalars");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,9 +137,21 @@ bool parse::check_func_end(expr* node) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool parse::check_in_curve_multi_definition() {
|
||||||
|
// we do not allow syntax like:
|
||||||
|
// func {}(var a, b, c)
|
||||||
|
// but we still allow syntax like:
|
||||||
|
// func {}(var a = 1)
|
||||||
|
// in fact, this syntax is not recommended
|
||||||
|
if (!lookahead(tok::lcurve) || toks[ptr+1].type!=tok::var) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return toks[ptr+2].type==tok::id && toks[ptr+3].type==tok::comma;
|
||||||
|
}
|
||||||
|
|
||||||
bool parse::check_special_call() {
|
bool parse::check_special_call() {
|
||||||
// special call means like this: function_name(a:1,b:2,c:3);
|
// special call means like this: function_name(a:1,b:2,c:3);
|
||||||
u32 check_ptr=ptr, curve=1, bracket=0, brace=0;
|
u32 check_ptr = ptr, curve = 1, bracket = 0, brace = 0;
|
||||||
while(toks[++check_ptr].type!=tok::eof && curve) {
|
while(toks[++check_ptr].type!=tok::eof && curve) {
|
||||||
switch(toks[check_ptr].type) {
|
switch(toks[check_ptr].type) {
|
||||||
case tok::lcurve: ++curve; break;
|
case tok::lcurve: ++curve; break;
|
||||||
|
@ -236,7 +252,7 @@ vector_expr* parse::vec() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
update_location(node);
|
update_location(node);
|
||||||
match(tok::rbracket, "expected ']' when generating vector");
|
match(tok::rbracket, "expected \"]\" when generating vector");
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,13 +264,13 @@ hash_expr* parse::hash() {
|
||||||
if (lookahead(tok::comma)) {
|
if (lookahead(tok::comma)) {
|
||||||
match(tok::comma);
|
match(tok::comma);
|
||||||
} else if (lookahead(tok::id) || lookahead(tok::str)) { // first set of hashmember
|
} else if (lookahead(tok::id) || lookahead(tok::str)) { // first set of hashmember
|
||||||
die(prevspan, "expected ',' between hash members");
|
die(prevspan, "expected \",\" between hash members");
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
update_location(node);
|
update_location(node);
|
||||||
match(tok::rbrace, "expected '}' when generating hash");
|
match(tok::rbrace, "expected \"}\" when generating hash");
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,13 +325,13 @@ void parse::params(function* func_node) {
|
||||||
if (lookahead(tok::comma)) {
|
if (lookahead(tok::comma)) {
|
||||||
match(tok::comma);
|
match(tok::comma);
|
||||||
} else if (lookahead(tok::id)) { // first set of identifier
|
} else if (lookahead(tok::id)) { // first set of identifier
|
||||||
die(prevspan, "expected ',' between identifiers");
|
die(prevspan, "expected \",\" between identifiers");
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
update_location(func_node);
|
update_location(func_node);
|
||||||
match(tok::rcurve, "expected ')' after parameter list");
|
match(tok::rcurve, "expected \")\" after parameter list");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,10 +397,10 @@ code_block* parse::expression_block() {
|
||||||
match(tok::semi);
|
match(tok::semi);
|
||||||
} else if (need_semi_check(node->get_expressions().back()) && !lookahead(tok::rbrace)) {
|
} else if (need_semi_check(node->get_expressions().back()) && !lookahead(tok::rbrace)) {
|
||||||
// the last expression can be recognized without semi
|
// the last expression can be recognized without semi
|
||||||
die(prevspan, "expected ';'");
|
die(prevspan, "expected \";\" after this token");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match(tok::rbrace, "expected '}' when generating expressions");
|
match(tok::rbrace, "expected \"}\" when generating expressions");
|
||||||
} else {
|
} else {
|
||||||
node->add_expression(expression());
|
node->add_expression(expression());
|
||||||
if (lookahead(tok::semi)) {
|
if (lookahead(tok::semi)) {
|
||||||
|
@ -634,10 +650,12 @@ expr* parse::scalar() {
|
||||||
die(thisspan, "expected scalar");
|
die(thisspan, "expected scalar");
|
||||||
return null();
|
return null();
|
||||||
}
|
}
|
||||||
// check call and avoid ambiguous syntax
|
// check call and avoid ambiguous syntax:
|
||||||
// i don't know why using `&& !(lookahead(tok::lcurve) && toks[ptr+1].type==tok::var)`
|
// var f = func(){}
|
||||||
// here, maybe we'll find the reason XD
|
// (var a, b, c) = (1, 2, 3);
|
||||||
if (is_call(toks[ptr].type)) {
|
// will be incorrectly recognized like:
|
||||||
|
// var f = func(){}(var a, b, c)
|
||||||
|
if (is_call(toks[ptr].type) && !check_in_curve_multi_definition()) {
|
||||||
auto call_node = new call_expr(toks[ptr].loc);
|
auto call_node = new call_expr(toks[ptr].loc);
|
||||||
call_node->set_first(node);
|
call_node->set_first(node);
|
||||||
while(is_call(toks[ptr].type)) {
|
while(is_call(toks[ptr].type)) {
|
||||||
|
@ -695,7 +713,7 @@ call_vector* parse::callv() {
|
||||||
die(thisspan, "expected index value");
|
die(thisspan, "expected index value");
|
||||||
}
|
}
|
||||||
update_location(node);
|
update_location(node);
|
||||||
match(tok::rbracket, "expected ']' when calling vector");
|
match(tok::rbracket, "expected \"]\" when calling vector");
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -722,7 +740,7 @@ call_function* parse::callf() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
update_location(node);
|
update_location(node);
|
||||||
match(tok::rcurve, "expected ')' when calling function");
|
match(tok::rcurve, "expected \")\" when calling function");
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -790,7 +808,7 @@ multi_identifier* parse::multi_id() {
|
||||||
if (lookahead(tok::comma)) {
|
if (lookahead(tok::comma)) {
|
||||||
match(tok::comma);
|
match(tok::comma);
|
||||||
} else if (lookahead(tok::id)) { // first set of identifier
|
} else if (lookahead(tok::id)) { // first set of identifier
|
||||||
die(prevspan, "expected ',' between identifiers");
|
die(prevspan, "expected \",\" between identifiers");
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -820,7 +838,7 @@ tuple_expr* parse::multi_scalar() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
update_location(node);
|
update_location(node);
|
||||||
match(tok::rcurve, "expected ')' after multi-scalar");
|
match(tok::rcurve, "expected \")\" after multi-scalar");
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -887,7 +905,7 @@ for_expr* parse::for_loop() {
|
||||||
} else {
|
} else {
|
||||||
node->set_initial(calc());
|
node->set_initial(calc());
|
||||||
}
|
}
|
||||||
match(tok::semi, "expected ';' in for(;;)");
|
match(tok::semi, "expected \";\" in for(;;)");
|
||||||
|
|
||||||
// conditional expression
|
// conditional expression
|
||||||
if (lookahead(tok::eof)) {
|
if (lookahead(tok::eof)) {
|
||||||
|
@ -898,7 +916,7 @@ for_expr* parse::for_loop() {
|
||||||
} else {
|
} else {
|
||||||
node->set_condition(calc());
|
node->set_condition(calc());
|
||||||
}
|
}
|
||||||
match(tok::semi, "expected ';' in for(;;)");
|
match(tok::semi, "expected \";\" in for(;;)");
|
||||||
|
|
||||||
//after loop expression
|
//after loop expression
|
||||||
if (lookahead(tok::eof)) {
|
if (lookahead(tok::eof)) {
|
||||||
|
@ -935,7 +953,7 @@ forei_expr* parse::forei_loop() {
|
||||||
die(thisspan, "expected iterator");
|
die(thisspan, "expected iterator");
|
||||||
}
|
}
|
||||||
node->set_iterator(iter_gen());
|
node->set_iterator(iter_gen());
|
||||||
match(tok::semi, "expected ';' in foreach/forindex(iter;vector)");
|
match(tok::semi, "expected \";\" in foreach/forindex(iter;vector)");
|
||||||
if (lookahead(tok::eof)) {
|
if (lookahead(tok::eof)) {
|
||||||
die(thisspan, "expected vector");
|
die(thisspan, "expected vector");
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,13 +77,14 @@ private:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void die(const span&,std::string);
|
void die(const span&,std::string);
|
||||||
void next() {++ptr;}
|
void next();
|
||||||
void match(tok type, const char* info=nullptr);
|
void match(tok, const char* info=nullptr);
|
||||||
bool lookahead(tok);
|
bool lookahead(tok);
|
||||||
bool is_call(tok);
|
bool is_call(tok);
|
||||||
bool check_comma(const tok*);
|
bool check_comma(const tok*);
|
||||||
bool check_tuple();
|
bool check_tuple();
|
||||||
bool check_func_end(expr*);
|
bool check_func_end(expr*);
|
||||||
|
bool check_in_curve_multi_definition();
|
||||||
bool check_special_call();
|
bool check_special_call();
|
||||||
bool need_semi_check(expr*);
|
bool need_semi_check(expr*);
|
||||||
void update_location(expr*);
|
void update_location(expr*);
|
||||||
|
|
Loading…
Reference in New Issue