use lalrpop_util; use itertools::*; use pest::Parser; use pest::iterators::Pair; use dhall_parser::{DhallParser, Rule}; use crate::grammar; use crate::grammar_util::{BoxExpr, ParsedExpr}; use crate::lexer::{Lexer, LexicalError, Tok}; use crate::core::{bx, Expr, Builtin, V}; pub fn parse_expr_lalrpop(s: &str) -> Result> { grammar::ExprParser::new().parse(Lexer::new(s)) } pub type ParseError = pest::error::Error; pub type ParseResult = Result; pub fn custom_parse_error(pair: &Pair, msg: String) -> ParseError { let e = pest::error::ErrorVariant::CustomError{ message: msg }; pest::error::Error::new_from_span(e, pair.as_span()) } macro_rules! parse_aux { ($inner:expr, true, $x:ident : $ty:ident $($rest:tt)*) => { let $x = concat_idents!(parse_, $ty)($inner.next().unwrap())?; parse_aux!($inner, true $($rest)*) }; ($inner:expr, true, $x:ident? : $ty:ident $($rest:tt)*) => { let $x = $inner.next().map(concat_idents!(parse_, $ty)).transpose()?; parse_aux!($inner, true $($rest)*) }; ($inner:expr, true, $x:ident* : $ty:ident $($rest:tt)*) => { #[allow(unused_mut)] let mut $x = $inner.map(concat_idents!(parse_, $ty)); parse_aux!($inner, false $($rest)*) }; ($inner:expr, false) => {}; ($inner:expr, true) => { $inner.next().ok_or(()).expect_err("Some parsed values remain unused") }; } macro_rules! parse { ($pair:expr; ($($args:tt)*) => $body:expr) => { { #[allow(unused_mut)] let mut inner = $pair.into_inner(); parse_aux!(inner, true, $($args)*); Ok($body) } }; } fn parse_binop<'a, F>(pair: Pair<'a, Rule>, mut f: F) -> ParseResult> where F: FnMut(BoxExpr<'a>, BoxExpr<'a>) -> ParsedExpr<'a> { parse!(pair; (first: expression, rest*: expression) => { rest.fold_results(first, |acc, e| bx(f(acc, e)))? }) } fn skip_expr(pair: Pair) -> ParseResult { parse!(pair; (expr: expression) => { expr }) } fn parse_str(pair: Pair) -> ParseResult<&str> { Ok(pair.as_str().trim()) } fn parse_natural(pair: Pair) -> ParseResult { parse_str(pair.clone())? .parse() .map_err(|e: std::num::ParseIntError| custom_parse_error(&pair, format!("{}", e))) } fn parse_expression(pair: Pair) -> ParseResult { match pair.as_rule() { Rule::natural_literal_raw => Ok(bx(Expr::NaturalLit(parse_natural(pair)?))), Rule::annotated_expression => { parse_binop(pair, Expr::Annot) } Rule::import_alt_expression => { skip_expr(pair) } Rule::or_expression => { parse_binop(pair, Expr::BoolOr) } Rule::plus_expression => { parse_binop(pair, Expr::NaturalPlus) } Rule::text_append_expression => { parse_binop(pair, Expr::TextAppend) } Rule::list_append_expression => { skip_expr(pair) } Rule::and_expression => { parse_binop(pair, Expr::BoolAnd) } Rule::combine_expression => { skip_expr(pair) } Rule::prefer_expression => { skip_expr(pair) } Rule::combine_types_expression => { skip_expr(pair) } Rule::times_expression => { parse_binop(pair, Expr::NaturalTimes) } Rule::equal_expression => { parse_binop(pair, Expr::BoolEQ) } Rule::not_equal_expression => { parse_binop(pair, Expr::BoolNE) } Rule::application_expression => { parse_binop(pair, Expr::App) } Rule::selector_expression_raw => parse!(pair; (first: expression, rest*: str) => { rest.fold_results(first, |acc, e| bx(Expr::Field(acc, e)))? }), Rule::identifier_raw => parse!(pair; (name: str, idx?: natural) => { match Builtin::parse(name) { Some(b) => bx(Expr::Builtin(b)), None => match name { "True" => bx(Expr::BoolLit(true)), "False" => bx(Expr::BoolLit(false)), name => bx(Expr::Var(V(name, idx.unwrap_or(0)))), } } }), Rule::ifthenelse_expression => parse!(pair; (cond: expression, left: expression, right: expression) => { bx(Expr::BoolIf(cond, left, right)) }), // Rule::record_type_or_literal => { // let mut inner = pair.into_inner(); // let first_expr = parse_expression(inner.next().unwrap()); // inner.fold(first_expr, |acc, e| bx(Expr::Field(acc, e.as_str()))) // } _ => { let rulename = format!("{:?}", pair.as_rule()); parse!(pair; (exprs*: expression) => { bx(Expr::FailedParse(rulename, exprs.map_results(|x| *x).collect::>()?)) }) } } } pub fn parse_expr_pest(s: &str) -> ParseResult { let parsed_expr = DhallParser::parse(Rule::final_expression, s)?.next().unwrap(); parse_expression(parsed_expr) } #[test] fn test_parse() { use crate::core::Expr::*; // let expr = r#"{ x = "foo", y = 4 }.x"#; // let expr = r#"(1 + 2) * 3"#; let expr = r#"if True then 1 + 3 * 5 else 2"#; println!("{:?}", parse_expr_lalrpop(expr)); match parse_expr_pest(expr) { Err(e) => { println!("{:?}", e); println!("{}", e); }, ok => println!("{:?}", ok), } assert_eq!(parse_expr_pest(expr).unwrap(), parse_expr_lalrpop(expr).unwrap()); assert!(false); println!("test {:?}", parse_expr_lalrpop("3 + 5 * 10")); assert!(parse_expr_lalrpop("22").is_ok()); assert!(parse_expr_lalrpop("(22)").is_ok()); assert_eq!(parse_expr_lalrpop("3 + 5 * 10").ok(), Some(Box::new(NaturalPlus(Box::new(NaturalLit(3)), Box::new(NaturalTimes(Box::new(NaturalLit(5)), Box::new(NaturalLit(10)))))))); // The original parser is apparently right-associative assert_eq!(parse_expr_lalrpop("2 * 3 * 4").ok(), Some(Box::new(NaturalTimes(Box::new(NaturalLit(2)), Box::new(NaturalTimes(Box::new(NaturalLit(3)), Box::new(NaturalLit(4)))))))); assert!(parse_expr_lalrpop("((((22))))").is_ok()); assert!(parse_expr_lalrpop("((22)").is_err()); println!("{:?}", parse_expr_lalrpop("\\(b : Bool) -> b == False")); assert!(parse_expr_lalrpop("\\(b : Bool) -> b == False").is_ok()); println!("{:?}", parse_expr_lalrpop("foo.bar")); assert!(parse_expr_lalrpop("foo.bar").is_ok()); assert!(parse_expr_lalrpop("[] : List Bool").is_ok()); // println!("{:?}", parse_expr_lalrpop("< Left = True | Right : Natural >")); // println!("{:?}", parse_expr_lalrpop(r#""bl${42}ah""#)); // assert!(parse_expr_lalrpop("< Left = True | Right : Natural >").is_ok()); }