diff --git a/parser/src/error.rs b/parser/src/error.rs index a5d50dc..9724c31 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -10,10 +10,10 @@ pub enum ParseError<'a, T> { #[derive(Debug, Clone)] pub struct AstError<'a, T> { - span: pest::Span<'a>, - error_code: ErrorCode, - error_message: String, - recovered: Option, + pub span: pest::Span<'a>, + pub error_code: ErrorCode, + pub error_message: String, + pub recovered: Option, } #[derive(Debug, Clone)] @@ -89,7 +89,7 @@ where span: ast_err.span, error_code: ast_err.error_code, error_message: ast_err.error_message, - recovered: None, + recovered: Some(items), }), None => Ok(items), } diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 5ab2bbf..429daf8 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -26,3 +26,51 @@ pub fn parse<'a>(source: &'a str) -> Result, ParseError<'a, Vec {{ + $( + let $name = $crate::_ast_t!($t $crate::_ast_ti!($inner, $val $($val2)?)); + )* + + $item { $($name,)* } + }}; +} + +#[macro_export] +macro_rules! _ast_t { + (: $val:expr) => { + $val.get()? + }; + + (? $val:expr) => { + $val.or_else(|e| { + if let Some(recovered) = e.recovered { + Ok(recovered) + } else { + Err(e) + } + }) + .get()? + }; +} + +#[macro_export] +macro_rules! _ast_ti { + ($inner:ident, ! $val:ident) => { + $val::try_from(&mut $inner) + }; + + ($inner:ident, @ $val:ident) => { + $val::try_from($inner.next().unwrap()) + }; + + ($inner:ident, ? ($rule:path)) => { + $crate::parser::listen_rule(&mut $inner, $rule) + }; + + ($inner:ident, & $val:expr) => { + $val + }; +} diff --git a/parser/src/parser/common/decl.rs b/parser/src/parser/common/decl.rs index d9a3dc5..ca8d438 100644 --- a/parser/src/parser/common/decl.rs +++ b/parser/src/parser/common/decl.rs @@ -1,8 +1,8 @@ use crate::{ Rule, ast::*, + ast_expr, error::{AstError, GetParseError}, - parser::listen_rule, }; impl<'a> TryFrom> for VarDeclStmt { @@ -53,27 +53,22 @@ impl<'a> TryFrom> for VarDecl { Rule::var_decl => { let mut inner = pair.into_inner(); - let type_ = inner - .next() - .and_then(|pair| { - if pair.as_str().trim() == "var" { - None - } else { - Some(TypeExpr::try_from(pair)) - } - }) - .transpose() - .get()?; + Ok(ast_expr!(inner@VarDecl { + type_: & (inner + .next() + .and_then(|pair| { + if pair.as_str().trim() == "var" { + None + } else { + Some(TypeExpr::try_from(pair)) + } + }) + .transpose()), - let mutable = listen_rule(&mut inner, Rule::mutable); + mutable: ?(Rule::mutable), - let name = Pattern::try_from(inner.next().unwrap()).get()?; - - Ok(VarDecl { - mutable, - name, - type_, - }) + name: @Pattern + })) } _ => unimplemented!("{:?}", pair.as_rule()), @@ -89,15 +84,11 @@ impl<'a> TryFrom> for FieldDecl { Rule::field => { let mut inner = pair.into_inner(); - let visibility = Visibility::try_from(&mut inner).get()?; - let type_ = TypeExpr::try_from(inner.next().unwrap()).get()?; - let name = Identifier::try_from(inner.next().unwrap()).get()?; - - Ok(FieldDecl { - visibility, - type_, - name, - }) + Ok(ast_expr!(inner@FieldDecl { + visibility: !Visibility, + type_: @TypeExpr, + name: @Identifier + })) } _ => unimplemented!("{:?}", pair.as_rule()), diff --git a/parser/src/parser/common/expr.rs b/parser/src/parser/common/expr.rs index 0d25e58..44a942f 100644 --- a/parser/src/parser/common/expr.rs +++ b/parser/src/parser/common/expr.rs @@ -1,7 +1,7 @@ use crate::{ Rule, ast::*, - error::{AstError, AstResult}, + error::{AstError, AstResult, GetParseError}, }; impl<'a> TryFrom> for Expression { @@ -72,7 +72,7 @@ impl<'a> TryFrom> for Postfix { Ok(match rule { Rule::postfix => Postfix::try_from(inner.next().unwrap())?, - Rule::field_px => Postfix::FieldAccess(Identifier::try_from(inner.next().unwrap())?), + Rule::field_px => Postfix::FieldAccess(Identifier::try_from(inner.next().unwrap()).get()?), Rule::call_px => Postfix::Call(inner.map(Expression::try_from).collect::, rule: Rule) -> bool { +pub fn listen_rule<'a>( + pairs: &mut pest::iterators::Pairs<'_, Rule>, + rule: Rule, +) -> AstResult<'a, bool> { let consumed = pairs .peek() .map(|p| p.as_rule() == rule) @@ -13,7 +16,7 @@ pub fn listen_rule(pairs: &mut pest::iterators::Pairs<'_, Rule>, rule: Rule) -> pairs.next(); } - consumed + Ok(consumed) } pub fn consume_rule<'a>(