I'm attempting to use pomelo in rust to parse a scripting language and have reached a roadblock in the backus-naur representation of the language, it cannot parse if-else statements the way i've defined them. for example, if it were to parse the statement
if (1) {
return;
}
the parser would succeed, but if I were to add an else statment to the code, like
if (1) {
return;
} else {
return;
}
it will throw a syntax error at the else token, specifically, the output I get is
gettin If
gettin LParen
gettin Num(1)
gettin RParen
gettin LBrace
gettin Return
gettin Semicolon
gettin RBrace
gettin Else
should not execute this
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "syntax Some(Else)"', src/main.rs:122:24
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
It doesn't seem obvious to me why this is failing when looking at the bnf form. Im sorry for the large amount of code for this minimal reproducible example but I don't know the exact cause of the error in the bnf form and thus I don't know how to condense it to produce the same errors.
extern crate pomelo;
use pomelo::pomelo;
pomelo!{
%error String;
%syntax_error{
Err(format!("syntax {:?}",token))
}
%parse_fail {
"Giving up. Parser is hopelessly lost...".to_string()
}
%token #[derive(Debug)] pub enum Token {};
//define types to make the compiler happy
%type Ident String;
%type Type String;
%type Num i64;
%type String String;
%type expr Vec<String>;
%type expr_list Vec<Vec<String>>;
%type stmt Vec<String>;
%type input Option<Vec<Vec<String>>>;
%type block Vec<Vec<String>>;
%type decl_list Vec<Vec<String>>;
%type stmt_list Vec<Vec<String>>;
%type func_list Vec<Vec<String>>;
%type arg_list Vec<String>;
%type type_list Vec<String>;
%type package String;
%type imports Vec<String>;
%type f_decl Vec<String>;
%type type_t Vec<Vec<String>>;
%type type_s Vec<Vec<String>>;
%type decl Vec<Vec<String>>;
%type assignment String;
%type CheckMark String;
%type Todo String;
%left Else;
%right Eq;
%left Or;
%left And;
%nonassoc Equal Neq;
%nonassoc Less LessEq Greater GreaterEq;
%left Add Sub;
%left Mul Div;
%nonassoc Not;
input ::= type_s?(v) {v /*assigning worthless values to make the compiler happy*/};
type_t ::= stmt(a) {vec![a]}
type_s ::= type_t(t) {t}
type_s ::= type_s(mut a) type_t(b) {a.extend(b);a}
stmt ::= KeyFunction Ident(name) LParen arg_list?(args) RParen block(code) {vec![name]}
assignment ::= Ident(a) Eq expr(b) {a}
arg_list ::= Ident(n) [Semicolon] { vec![n] }
arg_list ::= assignment(n) {vec![n]}
arg_list ::= arg_list(mut args) Comma Ident(n) { args.push(n); args }
block ::= LBrace stmt_list?(ss) RBrace { ss.unwrap_or(Vec::new()) }
stmt_list ::= stmt(s) { vec![s] }
stmt_list ::= stmt_list(mut ss) stmt(s) { ss.push(s); ss }
stmt ::= block(ss) { ss.get(0).unwrap_or(&Vec::new()).clone() }
stmt ::= expr(e) Semicolon {e}
stmt ::= Ident(a) Eq expr(b) Semicolon { vec![a] }
stmt ::= Var Ident(a) Eq expr(b) Semicolon { vec![a]}
stmt ::= If LParen expr(e) RParen stmt(s1) Else stmt(s2) {println!("should execute this"); s1 }
stmt ::= If LParen expr(e) RParen stmt(s1) [Else] {println!("should not execute this"); s1 }
stmt ::= While LParen expr(e) RParen stmt(s) { s }
stmt ::= Return expr(e) Semicolon { e }
stmt ::= Return Semicolon { vec!["".to_string()] }
stmt ::= Break Semicolon { vec!["".to_string()] }
stmt ::= Continue Semicolon {vec!["".to_string()] }
stmt ::= Todo(a) expr(b) Semicolon {vec![a]}
stmt ::= CheckMark(a) {vec![a]}
expr ::= Num(n) { vec!["".to_string()] }
expr ::= String(n) {vec!["".to_string()]}
expr ::= Ident(n) {vec!["".to_string()] }
expr ::= Ident(n) LParen expr_list?(es) RParen {vec![n]}
expr ::= LParen expr(e) RParen { e }
expr ::= expr(a) Add expr(b) { a}
expr ::= expr(a) Sub expr(b) { a }
expr ::= expr(a) Mul expr(b) {a}
expr ::= expr(a) Div expr(b) {a}
expr ::= Sub expr(a) [Not] { a }
expr ::= expr(a) Equal expr(b) { a }
expr ::= expr(a) Neq expr(b) { a }
expr ::= expr(a) And expr(b) { a }
expr ::= expr(a) Or expr(b) {a }
expr ::= Not expr(a) { a }
expr ::= expr(a) Less expr(b) { a }
expr ::= expr(a) Greater expr(b) { a }
expr ::= expr(a) LessEq expr(b) { a }
expr ::= expr(a) GreaterEq expr(b) { a }
expr_list ::= expr(e) { vec![e] }
expr_list ::= expr_list(mut es) Comma expr(e) { es.push(e); es }
}
fn main() {
let mut parse = parser::Parser::new();
let code = vec![
parser::Token::If,
parser::Token::LParen,
parser::Token::Num(1),
parser::Token::RParen,
parser::Token::LBrace,
parser::Token::Return,
parser::Token::Semicolon,
parser::Token::RBrace,
parser::Token::Else,
parser::Token::LBrace,
parser::Token::Return,
parser::Token::Semicolon,
parser::Token::RBrace
];
for i in code {
println!("gettin {:?}",i);
parse.parse(i).unwrap();
}
parse.end_of_input().unwrap();
}
For anyone who stumbles across a similar problem, the issue was the associativity of the else token, changing the else token from left association to right association did the trick