diff --git a/parser/src/error.rs b/parser/src/error.rs new file mode 100644 index 0000000..a3bf8cc --- /dev/null +++ b/parser/src/error.rs @@ -0,0 +1,115 @@ +use crate::Rule; + +pub type AstResult<'a, T, ET = T> = Result>; + +#[derive(Debug, Clone)] +pub enum ParseError<'a, T> { + PreAst(pest::error::Error), + Ast(AstError<'a, T>), +} + +#[derive(Debug, Clone)] +pub struct AstError<'a, T> { + pub span: pest::Span<'a>, + pub error_code: ErrorCode, + pub error_message: String, + pub recovered: Option, +} + +#[derive(Debug, Clone)] +pub enum ErrorCode { + InvalidStatement = 200, +} + +impl From> for ParseError<'_, T> { + fn from(value: pest::error::Error) -> Self { + Self::PreAst(value) + } +} + +impl<'a, T> From> for ParseError<'a, T> { + fn from(value: AstError<'a, T>) -> Self { + Self::Ast(value) + } +} + +impl<'a, F> AstError<'a, F> { + pub fn get(self) -> AstError<'a, T> { + AstError { + span: self.span, + error_code: self.error_code, + error_message: self.error_message, + recovered: None, + } + } +} + +pub trait GetParseError<'a, F> { + fn get(self) -> AstResult<'a, F, T>; +} + +impl<'a, F> GetParseError<'a, F> for AstResult<'a, F> { + fn get(self) -> AstResult<'a, F, T> { + match self { + Ok(v) => Ok(v), + Err(e) => Err(e.get()), + } + } +} + +impl<'a, F> GetParseError<'a, Option> for Result, AstError<'a, F>> { + fn get(self) -> AstResult<'a, Option, T> { + match self { + Ok(v) => Ok(v), + Err(e) => Err(e.get()), + } + } +} + +impl<'a, F> GetParseError<'a, Option>> for Result>, AstError<'a, F>> { + fn get(self) -> AstResult<'a, Option>, T> { + match self { + Ok(v) => Ok(v), + Err(e) => Err(e.get()), + } + } +} + +pub fn collect_recovered<'a, T, ET>( + pairs: impl Iterator>, +) -> AstResult<'a, Vec, Vec> +where + T: TryFrom, Error = AstError<'a, ET>>, +{ + collect_recovered_map(pairs, T::try_from) +} + +pub fn collect_recovered_map<'a, T, F, ET>( + pairs: impl Iterator>, + f: F, +) -> AstResult<'a, Vec, Vec> +where + F: Fn(pest::iterators::Pair<'a, Rule>) -> AstResult<'a, T, ET>, +{ + let mut items = Vec::new(); + let mut last_error: Option> = None; + + for pair in pairs { + match f(pair) { + Ok(item) => items.push(item), + Err(e) => { + last_error = Some(e); + } + } + } + + match last_error { + Some(ast_err) => Err(AstError { + span: ast_err.span, + error_code: ast_err.error_code, + error_message: ast_err.error_message, + recovered: None, + }), + None => Ok(items), + } +} diff --git a/parser/src/grammar.pest b/parser/src/grammar.pest index 547e347..13b699f 100644 --- a/parser/src/grammar.pest +++ b/parser/src/grammar.pest @@ -52,6 +52,14 @@ visibility = { "pub" ~ ("(" ~ static_path ~ ")")? } mutable = { "mut" } var = { "var" } +// ====================================================== +// ERROR RECOVERY +// ====================================================== + +unexpected_statement = { + (!(semicolon | "}" | statement) ~ ANY)+ +} + // ====================================================== // GENERICS // ====================================================== @@ -299,11 +307,7 @@ top_level = { // ====================================================== block = { - "{" ~ statement_list ~ "}" -} - -statement_list = { - statement* + "{" ~ (statement | unexpected_statement)* ~ "}" } statement = _{ diff --git a/parser/src/lib.rs b/parser/src/lib.rs index e536c67..5ab2bbf 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -2,840 +2,27 @@ use pest::Parser; use pest_derive::Parser; pub mod ast; +pub mod error; +pub mod parser; use ast::*; +use crate::error::{GetParseError, ParseError}; + #[derive(Parser)] #[grammar = "./src/grammar.pest"] pub struct MistParser; -// convenience alias for pest errors -pub type ParseError = pest::error::Error; - -pub fn parse(source: &str) -> Result, ParseError> { +pub fn parse<'a>(source: &'a str) -> Result, ParseError<'a, Vec>> { let mut pairs = MistParser::parse(Rule::program, source)?; let mut statements = vec![]; for pair in pairs.next().unwrap().into_inner() { if pair.as_rule() != Rule::EOI { - statements.push(TopLevel::from(pair)); + statements.push(TopLevel::try_from(pair).get()?); } } Ok(statements) } - -impl From> for TypeExpr { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - let rule = pair.as_rule(); - let mut inner = pair.into_inner(); - - match rule { - Rule::type_expr => TypeExpr( - TypeExprKind::from(inner.next().unwrap()), - inner.map(TypePostfix::from).collect(), - ), - Rule::type_expr_param => TypeExpr::from(inner.next().unwrap()), - Rule::lifetime => TypeExpr( - TypeExprKind::Lifetime(Identifier::from(inner.next().unwrap())), - Vec::new(), - ), - _ => unimplemented!("{rule:#?}"), - } - } -} - -impl From> for TypePostfix { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - let rule = pair.as_rule(); - let mut inner = pair.into_inner(); - - match rule { - Rule::ref_type => { - let mutable = listen_rule(&mut inner, Rule::mutable); - let lifetime = consume_rule(&mut inner, Rule::lifetime) - .map(|pair| Identifier::from(pair.into_inner().next().unwrap())); - - if mutable { - if let Some(lifetime) = lifetime { - TypePostfix::RefMutLifetime(lifetime) - } else { - TypePostfix::RefMut - } - } else { - if let Some(lifetime) = lifetime { - TypePostfix::RefLifetime(lifetime) - } else { - TypePostfix::Ref - } - } - } - _ => unimplemented!("{rule:#?}"), - } - } -} - -impl From> for TypeExprKind { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - let rule = pair.as_rule(); - let mut inner = pair.into_inner(); - - match rule { - Rule::tuple_type => TypeExprKind::Tuple(inner.map(TypeExpr::from).collect()), - Rule::path_type => { - let path = Path::from(inner.next().unwrap()); - let params = inner.map(TypeExpr::from).collect::>(); - - if params.len() == 0 { - TypeExprKind::Path(path) - } else { - TypeExprKind::PathParams(path, params) - } - } - _ => unimplemented!("{rule:#?}"), - } - } -} - -impl From> for Path { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - match pair.as_rule() { - Rule::static_path => Path(pair.into_inner().map(Identifier::from).collect()), - _ => unimplemented!("{pair:#?}"), - } - } -} - -impl From> for ParamList { - fn from(pair: pest::iterators::Pair) -> Self { - ParamList(pair.into_inner().map(VarDecl::from).collect()) - } -} - -impl From> for Attribute { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - match pair.as_rule() { - Rule::attribute => { - // unwrap #[ ... ] - Attribute::from(pair.into_inner().next().unwrap()) - } - - Rule::meta => { - let mut inner = pair.into_inner(); - - // first item is always the path - let path = Path::from(inner.next().unwrap()); - - // check what comes next - match inner.next() { - None => { - // #[path] - Attribute::Path(path) - } - - Some(next) => match next.as_rule() { - Rule::primary => { - // #[path = literal] - Attribute::NameValue { - path, - value: Literal::from(next), - } - } - - Rule::meta_list => { - // #[path(...)] - let items = next.into_inner().map(Attribute::from).collect(); - - Attribute::List { path, items } - } - - _ => unreachable!("unexpected rule in meta: {:?}", next.as_rule()), - }, - } - } - - Rule::meta_list => { - // This case usually won't be hit directly, - // but it's nice to keep it safe if reused - let items = pair.into_inner().map(Attribute::from).collect::>(); - - // NOTE: this shouldn't normally construct an Attribute alone - // but you can panic or wrap depending on your design - panic!("meta_list should be handled inside meta: {:?}", items); - } - - _ => unreachable!("unexpected rule: {:?}", pair.as_rule()), - } - } -} - -impl From> for TopLevel { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - let mut inner = pair.into_inner(); - - let attributes = inner - .next() - .unwrap() - .into_inner() - .map(Attribute::from) - .collect::>(); - - TopLevel( - inner - .next() - .map(TopLevelKind::from) - .unwrap_or(TopLevelKind::ModAttribute), - attributes, - ) - } -} - -impl From> for StatementBranch { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - let mut inner = pair.into_inner(); - - let condition = Expression::from(inner.next().unwrap()); - let body = Statement::from(inner.next().unwrap()); - - StatementBranch { - condition, - body: Box::new(body), - } - } -} - -impl From> for ClassConstructor { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - let mut inner = pair.into_inner(); - - let visibility = Visibility::from(&mut inner); - - let generics = consume_rule(&mut inner, Rule::generics) - .map(Generics::from) - .unwrap_or_default(); - - let params = consume_rule(&mut inner, Rule::param_list) - .map(ParamList::from) - .unwrap_or_else(|| ParamList(Vec::new())); - - Self { - visibility, - generics, - params, - body: Block::from(inner.next().unwrap()), - } - } -} - -impl From> for Generics { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - let rule = pair.as_rule(); - let inner = pair.clone().into_inner(); - - match rule { - Rule::generics => Generics( - inner - .map(|pair| { - let mut inner = pair.into_inner(); - if let Some(pair) = consume_rule(&mut inner, Rule::lifetime) { - Generic::Lifetime(Identifier::from(pair.into_inner().next().unwrap())) - } else { - Generic::Type( - Identifier::from(inner.next().unwrap()), - inner.map(TypeExpr::from).collect(), - ) - } - }) - .collect(), - ), - _ => unimplemented!("{rule:#?}"), - } - } -} - -impl From> for TopLevelKind { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - let rule = pair.as_rule(); - let mut inner = pair.clone().into_inner(); - - match rule { - Rule::import => TopLevelKind::Import( - Visibility::from(&mut inner), - Path::from(inner.next().unwrap()), - ), - - Rule::function_decl => TopLevelKind::FunctionDecl(FunctionDecl::from(pair)), - - Rule::struct_decl => TopLevelKind::StructDecl { - visibility: Visibility::from(&mut inner), - name: Identifier::from(inner.next().unwrap()), - generics: consume_rule(&mut inner, Rule::generics) - .map(Generics::from) - .unwrap_or_default(), - fields: inner - .next() - .map(|pair| pair.into_inner().map(FieldDecl::from).collect()) - .unwrap_or_default(), - }, - - Rule::class_decl => TopLevelKind::ClassDecl { - visibility: Visibility::from(&mut inner), - name: Identifier::from(inner.next().unwrap()), - generics: consume_rule(&mut inner, Rule::generics) - .map(Generics::from) - .unwrap_or_default(), - fields: inner - .next() - .unwrap() - .into_inner() - .map(FieldDeclStmt::from) - .collect(), - constructor: ClassConstructor::from(inner.next().unwrap()), - items: inner.into_iter().map(ClassItem::from).collect(), - }, - - Rule::enum_decl => TopLevelKind::EnumDecl { - visibility: Visibility::from(&mut inner), - name: Identifier::from(inner.next().unwrap()), - generics: consume_rule(&mut inner, Rule::generics) - .map(Generics::from) - .unwrap_or_default(), - fields: inner.map(EnumItem::from).collect(), - }, - - Rule::mod_package => TopLevelKind::Mod( - Visibility::from(&mut inner), - Identifier::from(inner.next().unwrap()), - ), - - Rule::impl_for_decl | Rule::impl_decl => TopLevelKind::ImplDecl(ImplDecl::from(pair)), - - Rule::trait_decl => TopLevelKind::TraitDecl { - visibility: Visibility::from(&mut inner), - name: Identifier::from(inner.next().unwrap()), - generics: consume_rule(&mut inner, Rule::generics) - .map(Generics::from) - .unwrap_or_default(), - requirements: consume_rule(&mut inner, Rule::trait_requirements) - .map(|pair| pair.into_inner().map(TypeExpr::from).collect()) - .unwrap_or_default(), - items: inner.map(FunctionDecl::from).collect(), - }, - - _ => unimplemented!("{rule:#?}"), - } - } -} - -impl From> for ClassItem { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - let rule = pair.as_rule(); - - match rule { - Rule::impl_decl | Rule::impl_for_decl => ClassItem::ImplDecl(ImplDecl::from(pair)), - - Rule::method => ClassItem::Method(FunctionDecl::from(pair)), - - _ => unimplemented!("{rule:#?}"), - } - } -} - -impl From> for ImplDecl { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - let rule = pair.as_rule(); - let mut inner = pair.clone().into_inner(); - - match rule { - Rule::impl_for_decl => ImplDecl { - generics: consume_rule(&mut inner, Rule::generics) - .map(Generics::from) - .unwrap_or_default(), - trait_: Some(TypeExpr::from(inner.next().unwrap())), - target: TypeExpr::from(inner.next().unwrap()), - methods: inner.map(FunctionDecl::from).collect(), - }, - - Rule::impl_decl => ImplDecl { - generics: consume_rule(&mut inner, Rule::generics) - .map(Generics::from) - .unwrap_or_default(), - trait_: None, - target: TypeExpr::from(inner.next().unwrap()), - methods: inner.map(FunctionDecl::from).collect(), - }, - - _ => unimplemented!("{rule:#?}"), - } - } -} - -impl From> for EnumItem { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - let rule = pair.as_rule(); - let mut inner = pair.clone().into_inner(); - - match rule { - Rule::enum_named => EnumItem::Named(Identifier::from(inner.next().unwrap())), - - Rule::enum_tuple => EnumItem::Tuple( - Identifier::from(inner.next().unwrap()), - inner - .next() - .unwrap() - .into_inner() - .map(TypeExpr::from) - .collect(), - ), - - Rule::enum_struct => EnumItem::Struct( - Identifier::from(inner.next().unwrap()), - inner - .next() - .map(|pair| pair.into_inner().map(FieldDecl::from).collect()) - .unwrap_or_default(), - ), - - _ => unimplemented!("{rule:#?}"), - } - } -} - -impl From> for Block { - fn from(pair: pest::iterators::Pair) -> Self { - let statements = pair - .into_inner() - .flat_map(|pair| { - if pair.as_rule() == Rule::statement_list { - pair.into_inner().map(Statement::from).collect() - } else { - vec![Statement::from(pair)] - } - }) - .collect(); - Block(statements) - } -} - -impl From> for Statement { - fn from(pair: pest::iterators::Pair) -> Self { - let rule = pair.as_rule(); - let mut inner = pair.clone().into_inner(); - - match rule { - Rule::statement => Statement::from(inner.next().unwrap()), - - Rule::expr_stmt => Statement::Expression(Expression::from(inner.next().unwrap())), - - Rule::block => Statement::Block(Block::from(inner.next().unwrap())), - - Rule::var_decl_statement => Statement::VarDecl(VarDeclStmt::from(pair)), - - Rule::return_stmt => { - let expr = inner.next().map(Expression::from); - - Statement::Return(expr) - } - - Rule::break_stmt => Statement::Break, - - Rule::continue_stmt => Statement::Continue, - - Rule::if_stmt => { - let mut inner = inner.skip(2); - - Statement::If { - initial: pair.into(), - else_if: inner - .next() - .unwrap() - .into_inner() - .map(StatementBranch::from) - .collect(), - else_branch: inner.next().map(Statement::from).map(Box::new), - } - } - - Rule::while_stmt => Statement::While(pair.into()), - - Rule::c_for_stmt => Statement::CStyleFor { - init: Box::new(Statement::from(inner.next().unwrap())), - condition: inner.next().unwrap().into(), - update: Box::new(Statement::from(inner.next().unwrap())), - body: Box::new(Statement::from(inner.next().unwrap())), - }, - - Rule::for_stmt => Statement::For { - mutable: listen_rule(&mut inner, Rule::mutable), - pattern: Pattern::from(inner.next().unwrap()), - iterator: inner.next().unwrap().into(), - body: Box::new(Statement::from(inner.next().unwrap())), - }, - - Rule::assign_statement => Statement::VarAssign(VarAssignStmt { - target: Expression::from(inner.next().unwrap()), - value: Expression::from(inner.next().unwrap()), - }), - - Rule::match_stmt => Statement::Match( - Expression::from(inner.next().unwrap()), - inner - .map(|match_itms| { - let mut match_inner = match_itms.into_inner(); - ( - Pattern::from(match_inner.next().unwrap()), - Block::from(match_inner.next().unwrap()), - ) - }) - .collect(), - ), - - _ => unimplemented!("{rule:#?}"), - } - } -} - -impl From> for Literal { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - let rule = pair.as_rule(); - let mut inner = pair.clone().into_inner(); - - match rule { - Rule::primary => Self::from(inner.next().unwrap()), - Rule::literal => Self::from(inner.next().unwrap()), - Rule::integer => Literal::Int(pair.as_str().parse::().unwrap()), - Rule::float => Literal::Float(pair.as_str().parse::().unwrap()), - Rule::boolean => Literal::Bool(pair.as_str().parse::().unwrap()), - Rule::string_lit => Literal::String(inner.as_str().to_string()), - Rule::tuple => Literal::Tuple(inner.map(Expression::from).collect()), - _ => unimplemented!("{rule:#?}"), - } - } -} - -impl From> for Expression { - fn from(pair: pest::iterators::Pair) -> Self { - let rule = pair.as_rule(); - let mut inner = pair.clone().into_inner(); - - match rule { - Rule::expr => { - let prefixes: Vec = inner - .next() - .map(|p| p.into_inner().into_iter().map(Prefix::from).collect()) - .unwrap_or_default(); - - let exp = Expression::from(inner.next().unwrap()); - - if inner.len() > 0 || prefixes.len() > 0 { - Expression::Fix { - initial: Box::new(exp), - prefixes, - postfixes: inner.map(|p| Postfix::from(p)).collect(), - } - } else { - exp - } - } - Rule::primary => Expression::from(inner.next().unwrap()), - Rule::static_path => Expression::Path(Path::from(pair)), - Rule::literal => Expression::Literal(Literal::from(pair)), - _ => unimplemented!("{rule:#?}"), - } - } -} - -impl From> for Prefix { - fn from(pair: pest::iterators::Pair) -> Self { - match pair.as_rule() { - Rule::prefix => Self::from(pair.into_inner().next().unwrap()), - Rule::deref_px => Self::Deref, - Rule::mut_ref_px => Self::RefMut, - Rule::ref_px => Self::Ref, - Rule::new_px => Self::New, - Rule::not_px => Self::Not, - _ => unimplemented!("{pair:#?}"), - } - } -} - -impl From> for Postfix { - fn from(pair: pest::iterators::Pair) -> Self { - let rule = pair.as_rule(); - let mut inner = pair.into_inner(); - - match rule { - Rule::postfix => Postfix::from(inner.next().unwrap()), - - Rule::field_px => Postfix::FieldAccess(Identifier::from(inner.next().unwrap())), - - Rule::call_px => Postfix::Call(inner.map(Expression::from).collect()), - - Rule::struct_px => Postfix::StructCall( - inner - .map(|p| { - let mut pi = p.into_inner(); - ( - Identifier::from(pi.next().unwrap()), - Expression::from(pi.next().unwrap()), - ) - }) - .collect(), - ), - - Rule::index_px => Postfix::Index(Expression::from(inner.next().unwrap())), - - Rule::binary_px => { - let op_pair = inner.next().unwrap(); - let op = match op_pair.as_str() { - "+" => BinaryOp::Plus, - "-" => BinaryOp::Minus, - "*" => BinaryOp::Multiply, - "/" => BinaryOp::Divide, - "%" => BinaryOp::Modulo, - "==" => BinaryOp::Equal, - "!=" => BinaryOp::NotEqual, - "<" => BinaryOp::LessThan, - ">" => BinaryOp::GreaterThan, - "<=" => BinaryOp::LessThanOrEqual, - ">=" => BinaryOp::GreaterThanOrEqual, - "&&" => BinaryOp::And, - "||" => BinaryOp::Or, - - _ => { - unimplemented!("Binary operator not implemented yet: {}", op_pair.as_str()) - } - }; - Postfix::Binary(op, Expression::from(inner.next().unwrap())) - } - - Rule::macro_call_px => Postfix::MacroCall(inner.as_str().to_string()), - - _ => unimplemented!("{rule:#?}"), - } - } -} - -impl From> for VarDeclStmt { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - match pair.as_rule() { - Rule::var_decl_statement => { - let mut inner = pair.into_inner(); - - let decl = VarDecl::from(inner.next().unwrap()); - - let init = inner.next().map(Expression::from); - - VarDeclStmt { decl, init } - } - - _ => unimplemented!(), - } - } -} - -impl From> for FieldDeclStmt { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - match pair.as_rule() { - Rule::class_field => { - let mut inner = pair.into_inner(); - - let decl = FieldDecl::from(inner.next().unwrap()); - - let init = inner.next().map(Expression::from); - - FieldDeclStmt { decl, init } - } - - _ => unimplemented!(), - } - } -} - -impl From> for Pattern { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - let rule = pair.as_rule(); - let mut inner = pair.clone().into_inner(); - - match rule { - Rule::tuple_pattern => Pattern::Tuple(inner.map(Identifier::from).collect()), - - Rule::named_tuple_pattern => Pattern::NamedTuple( - Path::from(inner.next().unwrap()), - inner.map(Identifier::from).collect(), - ), - - Rule::struct_pattern => Pattern::Struct( - Path::from(inner.next().unwrap()), - inner.map(Identifier::from).collect(), - ), - - Rule::literal => Pattern::Literal(Literal::from(pair)), - - Rule::identifier => Pattern::Id(Identifier::from(pair)), - - Rule::static_path => Pattern::Path(Path::from(pair)), - - _ => unimplemented!("{rule:?}"), - } - } -} - -impl From> for VarDecl { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - match pair.as_rule() { - 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::from(pair)) - } - }); - let mutable = listen_rule(&mut inner, Rule::mutable); - - let name = Pattern::from(inner.next().unwrap()); - - VarDecl { - mutable, - name, - type_, - } - } - - _ => unimplemented!("{:?}", pair.as_rule()), - } - } -} - -impl From> for FieldDecl { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - match pair.as_rule() { - Rule::field => { - let mut inner = pair.into_inner(); - - let visibility = Visibility::from(&mut inner); - let type_ = TypeExpr::from(inner.next().unwrap()); - let name = Identifier::from(inner.next().unwrap()); - - FieldDecl { - visibility, - type_, - name, - } - } - - _ => unimplemented!("{:?}", pair.as_rule()), - } - } -} - -impl From> for FunctionDecl { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - let mut inner = pair.into_inner(); - let visibility = Visibility::from(&mut inner); - let return_type = TypeExpr::from(inner.next().unwrap()); - let name = Identifier::from(inner.next().unwrap()); - let generics = consume_rule(&mut inner, Rule::generics) - .map(Generics::from) - .unwrap_or_default(); - - let self_param = consume_rule(&mut inner, Rule::self_param).map(|param| { - let mut param_inner = param.into_inner(); - let name = Pattern::Id(Identifier(String::from("self"))); - - let mutable = listen_rule(&mut param_inner, Rule::mutable); - - let is_ref = listen_rule(&mut param_inner, Rule::deref_px); - - VarDecl { - mutable: mutable && !is_ref, - name: name.clone(), - type_: Some(TypeExpr( - TypeExprKind::Path(Path(vec![Identifier("Self".to_string())])), - if is_ref { - vec![if mutable { - TypePostfix::RefMut - } else { - TypePostfix::Ref - }] - } else { - Vec::new() - }, - )), - } - }); - - let params = consume_rule(&mut inner, Rule::param_list) - .map({ - let self_param = self_param.clone(); - |params_pair| { - let mut params = ParamList::from(params_pair); - if let Some(x) = self_param { - params.0.insert(0, x); - } - params - } - }) - .unwrap_or_else(|| ParamList(self_param.into_iter().collect())); - - let body = inner.next().map(Block::from); - - Self { - visibility, - name, - generics, - params, - return_type, - body, - } - } -} - -impl From<&mut pest::iterators::Pairs<'_, Rule>> for Visibility { - fn from(pairs: &mut pest::iterators::Pairs<'_, Rule>) -> Self { - consume_rule(pairs, Rule::visibility) - .map(|pair| { - if let Some(path) = pair.into_inner().next() { - Visibility::PublicTarget(Path::from(path)) - } else { - Visibility::Public - } - }) - .unwrap_or_else(|| Visibility::Private) - } -} - -pub fn listen_rule(pairs: &mut pest::iterators::Pairs<'_, Rule>, rule: Rule) -> bool { - let consumed = pairs - .peek() - .map(|p| p.as_rule() == rule) - .unwrap_or_default(); - - if consumed { - pairs.next(); - } - - consumed -} - -pub fn consume_rule<'a>( - pairs: &mut pest::iterators::Pairs<'a, Rule>, - rule: Rule, -) -> Option> { - let consumed = pairs - .peek() - .map(|p| p.as_rule() == rule) - .unwrap_or_default(); - - if consumed { pairs.next() } else { None } -} - -impl From> for Identifier { - fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - Identifier(pair.as_str().to_string()) - } -} diff --git a/parser/src/parser/common/decl.rs b/parser/src/parser/common/decl.rs new file mode 100644 index 0000000..d9a3dc5 --- /dev/null +++ b/parser/src/parser/common/decl.rs @@ -0,0 +1,106 @@ +use crate::{ + Rule, + ast::*, + error::{AstError, GetParseError}, + parser::listen_rule, +}; + +impl<'a> TryFrom> for VarDeclStmt { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + match pair.as_rule() { + Rule::var_decl_statement => { + let mut inner = pair.into_inner(); + + let decl = VarDecl::try_from(inner.next().unwrap()).get()?; + + let init = inner.next().map(Expression::try_from).transpose().get()?; + + Ok(VarDeclStmt { decl, init }) + } + + _ => unimplemented!(), + } + } +} + +impl<'a> TryFrom> for FieldDeclStmt { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + match pair.as_rule() { + Rule::class_field => { + let mut inner = pair.into_inner(); + + let decl = FieldDecl::try_from(inner.next().unwrap()).get()?; + + let init = inner.next().map(Expression::try_from).transpose().get()?; + + Ok(FieldDeclStmt { decl, init }) + } + + _ => unimplemented!(), + } + } +} + +impl<'a> TryFrom> for VarDecl { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + match pair.as_rule() { + 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()?; + + let mutable = listen_rule(&mut inner, Rule::mutable); + + let name = Pattern::try_from(inner.next().unwrap()).get()?; + + Ok(VarDecl { + mutable, + name, + type_, + }) + } + + _ => unimplemented!("{:?}", pair.as_rule()), + } + } +} + +impl<'a> TryFrom> for FieldDecl { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + match pair.as_rule() { + 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, + }) + } + + _ => unimplemented!("{:?}", pair.as_rule()), + } + } +} diff --git a/parser/src/parser/common/expr.rs b/parser/src/parser/common/expr.rs new file mode 100644 index 0000000..ff0ccd9 --- /dev/null +++ b/parser/src/parser/common/expr.rs @@ -0,0 +1,122 @@ +use crate::{ + Rule, + ast::*, + error::{AstError, AstResult, GetParseError, collect_recovered, collect_recovered_map}, +}; + +impl<'a> TryFrom> for Expression { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.clone().into_inner(); + + match rule { + Rule::expr => { + let prefixes = inner + .next() + .map(|p| { + p.into_inner() + .into_iter() + .map(Prefix::try_from) + .collect::, _>>() + }) + .transpose() + .get()? + .unwrap_or_default(); + + let exp = Expression::try_from(inner.next().unwrap())?; + + if inner.len() > 0 || prefixes.len() > 0 { + Ok(Expression::Fix { + initial: Box::new(exp), + prefixes, + postfixes: collect_recovered(inner).get()?, + }) + } else { + Ok(exp) + } + } + Rule::primary => Expression::try_from(inner.next().unwrap()), + Rule::static_path => Ok(Expression::Path(Path::try_from(pair).get()?)), + Rule::literal => Ok(Expression::Literal(Literal::try_from(pair).get()?)), + _ => unimplemented!("{rule:#?}"), + } + } +} + +impl<'a> TryFrom> for Prefix { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + Ok(match pair.as_rule() { + Rule::prefix => Self::try_from(pair.into_inner().next().unwrap())?, + Rule::deref_px => Self::Deref, + Rule::mut_ref_px => Self::RefMut, + Rule::ref_px => Self::Ref, + Rule::new_px => Self::New, + Rule::not_px => Self::Not, + _ => unimplemented!("{pair:#?}"), + }) + } +} + +impl<'a> TryFrom> for Postfix { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.into_inner(); + + Ok(match rule { + Rule::postfix => Postfix::try_from(inner.next().unwrap())?, + + Rule::field_px => { + Postfix::FieldAccess(Identifier::try_from(inner.next().unwrap()).get()?) + } + + Rule::call_px => Postfix::Call(collect_recovered(inner).get()?), + + Rule::struct_px => Postfix::StructCall( + collect_recovered_map(inner, |p| { + let mut pi = p.into_inner(); + Ok(( + Identifier::try_from(pi.next().unwrap())?, + Expression::try_from(pi.next().unwrap()).get()?, + )) + }) + .get()?, + ), + + Rule::index_px => Postfix::Index(Expression::try_from(inner.next().unwrap()).get()?), + + Rule::binary_px => { + let op_pair = inner.next().unwrap(); + let op = match op_pair.as_str() { + "+" => BinaryOp::Plus, + "-" => BinaryOp::Minus, + "*" => BinaryOp::Multiply, + "/" => BinaryOp::Divide, + "%" => BinaryOp::Modulo, + "==" => BinaryOp::Equal, + "!=" => BinaryOp::NotEqual, + "<" => BinaryOp::LessThan, + ">" => BinaryOp::GreaterThan, + "<=" => BinaryOp::LessThanOrEqual, + ">=" => BinaryOp::GreaterThanOrEqual, + "&&" => BinaryOp::And, + "||" => BinaryOp::Or, + + _ => { + unimplemented!("Binary operator not implemented yet: {}", op_pair.as_str()) + } + }; + Postfix::Binary(op, Expression::try_from(inner.next().unwrap()).get()?) + } + + Rule::macro_call_px => Postfix::MacroCall(inner.as_str().to_string()), + + _ => unimplemented!("{rule:#?}"), + }) + } +} diff --git a/parser/src/parser/common/mod.rs b/parser/src/parser/common/mod.rs new file mode 100644 index 0000000..067dba2 --- /dev/null +++ b/parser/src/parser/common/mod.rs @@ -0,0 +1,98 @@ +pub mod decl; +pub mod expr; +pub mod statement; +pub mod types; + +use crate::{ + Rule, + ast::*, + error::{AstError, GetParseError, collect_recovered}, + parser::consume_rule, +}; + +impl<'a> TryFrom> for Identifier { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + Ok(Identifier(pair.as_str().to_string())) + } +} + +impl<'a> TryFrom> for Path { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + match pair.as_rule() { + Rule::static_path => Ok(Path(collect_recovered(pair.into_inner()).get()?)), + _ => unimplemented!("{pair:#?}"), + } + } +} + +impl<'a> TryFrom> for Literal { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.clone().into_inner(); + + Ok(match rule { + Rule::primary => Self::try_from(inner.next().unwrap())?, + Rule::literal => Self::try_from(inner.next().unwrap())?, + Rule::integer => Literal::Int(pair.as_str().parse::().unwrap()), + Rule::float => Literal::Float(pair.as_str().parse::().unwrap()), + Rule::boolean => Literal::Bool(pair.as_str().parse::().unwrap()), + Rule::string_lit => Literal::String(inner.as_str().to_string()), + Rule::tuple => Literal::Tuple(collect_recovered(inner).get()?), + _ => unimplemented!("{rule:#?}"), + }) + } +} + +impl<'a> TryFrom> for Pattern { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.clone().into_inner(); + + Ok(match rule { + Rule::tuple_pattern => Pattern::Tuple(collect_recovered(pair.into_inner()).get()?), + + Rule::named_tuple_pattern => Pattern::NamedTuple( + Path::try_from(inner.next().unwrap()).get()?, + collect_recovered(inner).get()?, + ), + + Rule::struct_pattern => Pattern::Struct( + Path::try_from(inner.next().unwrap()).get()?, + collect_recovered(inner).get()?, + ), + + Rule::literal => Pattern::Literal(Literal::try_from(pair).get()?), + + Rule::identifier => Pattern::Id(Identifier::try_from(pair).get()?), + + Rule::static_path => Pattern::Path(Path::try_from(pair).get()?), + + _ => unimplemented!("{rule:?}"), + }) + } +} + +impl<'a> TryFrom<&mut pest::iterators::Pairs<'a, Rule>> for Visibility { + type Error = AstError<'a, Self>; + + fn try_from(pairs: &mut pest::iterators::Pairs<'a, Rule>) -> Result { + Ok(consume_rule(pairs, Rule::visibility) + .map(|pair| -> Result> { + if let Some(path) = pair.into_inner().next() { + Ok(Visibility::PublicTarget(Path::try_from(path).get()?)) + } else { + Ok(Visibility::Public) + } + }) + .transpose()? + .unwrap_or_else(|| Visibility::Private)) + } +} diff --git a/parser/src/parser/common/statement.rs b/parser/src/parser/common/statement.rs new file mode 100644 index 0000000..3f5afd5 --- /dev/null +++ b/parser/src/parser/common/statement.rs @@ -0,0 +1,131 @@ +use crate::{ + Rule, + ast::*, + error::{AstError, AstResult, ErrorCode, GetParseError, collect_recovered}, + parser::listen_rule, +}; + +impl<'a> TryFrom> for Block { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + if pair.as_rule() == Rule::block { + Ok(Block(collect_recovered(pair.into_inner()).get()?)) + } else { + Err(AstError { + span: pair.as_span(), + error_code: ErrorCode::InvalidStatement, + error_message: format!( + "BUG: AST requires a block, this isn't a block, it's a {:?}", + pair.as_rule() + ), + recovered: None, + }) + } + } +} + +impl<'a> TryFrom> for Statement { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.clone().into_inner(); + + Ok(match rule { + Rule::statement => Statement::try_from(inner.next().unwrap())?, + + Rule::expr_stmt => { + Statement::Expression(Expression::try_from(inner.next().unwrap()).get()?) + } + + Rule::block => Statement::Block(pair.try_into().get()?), + + Rule::var_decl_statement => Statement::VarDecl(VarDeclStmt::try_from(pair).get()?), + + Rule::return_stmt => { + Statement::Return(inner.next().map(Expression::try_from).transpose().get()?) + } + + Rule::break_stmt => Statement::Break, + + Rule::continue_stmt => Statement::Continue, + + Rule::if_stmt => { + let mut inner = inner.skip(2); + + Statement::If { + initial: StatementBranch::try_from(pair).get()?, + else_if: collect_recovered(inner.next().unwrap().into_inner()).get()?, + else_branch: inner + .next() + .map(Statement::try_from) + .transpose()? + .map(Box::new), + } + } + + Rule::while_stmt => Statement::While(pair.try_into().get()?), + + Rule::c_for_stmt => Statement::CStyleFor { + init: Box::new(inner.next().unwrap().try_into().get()?), + condition: inner.next().unwrap().try_into().get()?, + update: Box::new(inner.next().unwrap().try_into().get()?), + body: Box::new(inner.next().unwrap().try_into().get()?), + }, + + Rule::for_stmt => Statement::For { + mutable: listen_rule(&mut inner, Rule::mutable), + pattern: inner.next().unwrap().try_into().get()?, + iterator: inner.next().unwrap().try_into().get()?, + body: Box::new(Statement::try_from(inner.next().unwrap())?), + }, + + Rule::assign_statement => Statement::VarAssign(VarAssignStmt { + target: inner.next().unwrap().try_into().get()?, + value: inner.next().unwrap().try_into().get()?, + }), + + Rule::match_stmt => Statement::Match( + inner.next().unwrap().try_into().get()?, + inner + .map(|match_itms| { + let mut match_inner = match_itms.into_inner(); + Ok(( + Pattern::try_from(match_inner.next().unwrap()).get()?, + Block::try_from(match_inner.next().unwrap()).get()?, + )) + }) + .collect::>>() + .get()?, + ), + + Rule::unexpected_statement => { + return Err(AstError { + span: pair.as_span(), + error_code: ErrorCode::InvalidStatement, + error_message: "Invalid Statement".to_string(), + recovered: None, + }); + } + + _ => unimplemented!("{rule:#?}"), + }) + } +} + +impl<'a> TryFrom> for StatementBranch { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let mut inner = pair.into_inner(); + + let condition = inner.next().unwrap().try_into().get()?; + let body = inner.next().unwrap().try_into().get()?; + + Ok(StatementBranch { + condition, + body: Box::new(body), + }) + } +} diff --git a/parser/src/parser/common/types.rs b/parser/src/parser/common/types.rs new file mode 100644 index 0000000..19a91c9 --- /dev/null +++ b/parser/src/parser/common/types.rs @@ -0,0 +1,119 @@ +use crate::{ + Rule, + ast::*, + error::{AstError, GetParseError, collect_recovered}, + parser::{consume_rule, listen_rule}, +}; + +impl<'a> TryFrom> for TypePostfix { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.into_inner(); + + match rule { + Rule::ref_type => { + let mutable = listen_rule(&mut inner, Rule::mutable); + let lifetime = consume_rule(&mut inner, Rule::lifetime) + .map(|pair| Identifier::try_from(pair.into_inner().next().unwrap())) + .transpose() + .get()?; + + Ok(if mutable { + if let Some(lifetime) = lifetime { + TypePostfix::RefMutLifetime(lifetime) + } else { + TypePostfix::RefMut + } + } else { + if let Some(lifetime) = lifetime { + TypePostfix::RefLifetime(lifetime) + } else { + TypePostfix::Ref + } + }) + } + _ => unimplemented!("{rule:#?}"), + } + } +} + +impl<'a> TryFrom> for TypeExprKind { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.into_inner(); + + match rule { + Rule::tuple_type => Ok(TypeExprKind::Tuple(collect_recovered(inner).get()?)), + Rule::path_type => { + let path = Path::try_from(inner.next().unwrap()).get()?; + let params = collect_recovered(inner).get()?; + + if params.len() == 0 { + Ok(TypeExprKind::Path(path)) + } else { + Ok(TypeExprKind::PathParams(path, params)) + } + } + _ => unimplemented!("{rule:#?}"), + } + } +} + +impl<'a> TryFrom> for TypeExpr { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.into_inner(); + + match rule { + Rule::type_expr => Ok(TypeExpr( + inner.next().unwrap().try_into().get()?, + collect_recovered(inner).get()?, + )), + Rule::type_expr_param => Self::try_from(inner.next().unwrap()), + Rule::lifetime => Ok(TypeExpr( + TypeExprKind::Lifetime(inner.next().unwrap().try_into().get()?), + Vec::new(), + )), + _ => unimplemented!("{rule:#?}"), + } + } +} + +impl<'a> TryFrom> for Generics { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let inner = pair.clone().into_inner(); + + match rule { + Rule::generics => Ok(Generics(collect_recovered(inner).get()?)), + _ => unimplemented!("{rule:#?}"), + } + } +} + +impl<'a> TryFrom> for Generic { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let mut inner = pair.clone().into_inner(); + + if let Some(pair) = consume_rule(&mut inner, Rule::lifetime) { + Ok(Generic::Lifetime( + pair.into_inner().next().unwrap().try_into().get()?, + )) + } else { + Ok(Generic::Type( + inner.next().unwrap().try_into().get()?, + collect_recovered(inner).get()?, + )) + } + } +} diff --git a/parser/src/parser/items/attribute.rs b/parser/src/parser/items/attribute.rs new file mode 100644 index 0000000..5f64605 --- /dev/null +++ b/parser/src/parser/items/attribute.rs @@ -0,0 +1,68 @@ +use crate::{ + Rule, + ast::*, + error::{AstError, GetParseError, collect_recovered}, +}; + +impl<'a> TryFrom> for Attribute { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + match pair.as_rule() { + Rule::attribute => { + // unwrap #[ ... ] + Attribute::try_from(pair.into_inner().next().unwrap()) + } + + Rule::meta => { + let mut inner = pair.into_inner(); + + // first item is always the path + let path = inner.next().unwrap().try_into().get()?; + + // check what comes next + match inner.next() { + None => { + // #[path] + Ok(Attribute::Path(path)) + } + + Some(next) => match next.as_rule() { + Rule::primary => { + // #[path = literal] + Ok(Attribute::NameValue { + path, + value: inner.next().unwrap().try_into().get()?, + }) + } + + Rule::meta_list => { + // #[path(...)] + Ok(Attribute::List { + path, + items: collect_recovered(next.into_inner()).get()?, + }) + } + + _ => unreachable!("unexpected rule in meta: {:?}", next.as_rule()), + }, + } + } + + Rule::meta_list => { + // This case usually won't be hit directly, + // but it's nice to keep it safe if reused + let items = pair + .into_inner() + .map(Attribute::try_from) + .collect::>(); + + // NOTE: this shouldn't normally construct an Attribute alone + // but you can panic or wrap depending on your design + panic!("meta_list should be handled inside meta: {:?}", items); + } + + _ => unreachable!("unexpected rule: {:?}", pair.as_rule()), + } + } +} diff --git a/parser/src/parser/items/class.rs b/parser/src/parser/items/class.rs new file mode 100644 index 0000000..88b2944 --- /dev/null +++ b/parser/src/parser/items/class.rs @@ -0,0 +1,50 @@ +use crate::{ + Rule, + ast::*, + error::{AstError, GetParseError}, + parser::consume_rule, +}; + +impl<'a> TryFrom> for ClassConstructor { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let mut inner = pair.into_inner(); + + Ok(Self { + visibility: Visibility::try_from(&mut inner).get()?, + + generics: consume_rule(&mut inner, Rule::generics) + .map(Generics::try_from) + .transpose() + .get()? + .unwrap_or_default(), + + params: consume_rule(&mut inner, Rule::param_list) + .map(ParamList::try_from) + .transpose() + .get()? + .unwrap_or_default(), + + body: inner.next().unwrap().try_into().get()?, + }) + } +} + +impl<'a> TryFrom> for ClassItem { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + + match rule { + Rule::impl_decl | Rule::impl_for_decl => { + Ok(ClassItem::ImplDecl(pair.try_into().get()?)) + } + + Rule::method => Ok(ClassItem::Method(pair.try_into().get()?)), + + _ => unimplemented!("{rule:#?}"), + } + } +} diff --git a/parser/src/parser/items/enums.rs b/parser/src/parser/items/enums.rs new file mode 100644 index 0000000..ad8c87e --- /dev/null +++ b/parser/src/parser/items/enums.rs @@ -0,0 +1,35 @@ +use crate::{ + Rule, + ast::*, + error::{AstError, GetParseError, collect_recovered}, +}; + +impl<'a> TryFrom> for EnumItem { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.clone().into_inner(); + + match rule { + Rule::enum_named => Ok(EnumItem::Named(inner.next().unwrap().try_into().get()?)), + + Rule::enum_tuple => Ok(EnumItem::Tuple( + inner.next().unwrap().try_into().get()?, + collect_recovered(inner.next().unwrap().into_inner()).get()?, + )), + + Rule::enum_struct => Ok(EnumItem::Struct( + inner.next().unwrap().try_into().get()?, + inner + .next() + .map(|pair| collect_recovered::(pair.into_inner())) + .transpose() + .get::()? + .unwrap_or_default(), + )), + + _ => unimplemented!("{rule:#?}"), + } + } +} diff --git a/parser/src/parser/items/function.rs b/parser/src/parser/items/function.rs new file mode 100644 index 0000000..0787d52 --- /dev/null +++ b/parser/src/parser/items/function.rs @@ -0,0 +1,82 @@ +use crate::{ + Rule, + ast::*, + error::{AstError, AstResult, GetParseError, collect_recovered}, + parser::{consume_rule, listen_rule}, +}; + +impl<'a> TryFrom> for FunctionDecl { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let mut inner = pair.into_inner(); + let visibility = Visibility::try_from(&mut inner).get()?; + let return_type = TypeExpr::try_from(inner.next().unwrap()).get()?; + let name = Identifier::try_from(inner.next().unwrap()).get()?; + let generics = consume_rule(&mut inner, Rule::generics) + .map(Generics::try_from) + .transpose() + .get()? + .unwrap_or_default(); + + let self_param = consume_rule(&mut inner, Rule::self_param).map(|param| { + let mut param_inner = param.into_inner(); + let name = Pattern::Id(Identifier(String::from("self"))); + + let mutable = listen_rule(&mut param_inner, Rule::mutable); + + let is_ref = listen_rule(&mut param_inner, Rule::deref_px); + + VarDecl { + mutable: mutable && !is_ref, + name: name.clone(), + type_: Some(TypeExpr( + TypeExprKind::Path(Path(vec![Identifier("Self".to_string())])), + if is_ref { + vec![if mutable { + TypePostfix::RefMut + } else { + TypePostfix::Ref + }] + } else { + Vec::new() + }, + )), + } + }); + + let params = consume_rule(&mut inner, Rule::param_list) + .map({ + let self_param = self_param.clone(); + |params_pair| -> AstResult<'a, ParamList> { + let mut params = ParamList::try_from(params_pair)?; + if let Some(x) = self_param { + params.0.insert(0, x); + } + Ok(params) + } + }) + .transpose() + .get()? + .unwrap_or_else(|| ParamList(self_param.into_iter().collect())); + + let body = inner.next().map(Block::try_from).transpose().get()?; + + Ok(Self { + visibility, + name, + generics, + params, + return_type, + body, + }) + } +} + +impl<'a> TryFrom> for ParamList { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + Ok(ParamList(collect_recovered(pair.into_inner()).get()?)) + } +} diff --git a/parser/src/parser/items/impl_decl.rs b/parser/src/parser/items/impl_decl.rs new file mode 100644 index 0000000..98aa43e --- /dev/null +++ b/parser/src/parser/items/impl_decl.rs @@ -0,0 +1,41 @@ +use crate::{ + Rule, + ast::*, + error::{AstError, GetParseError, collect_recovered}, + parser::consume_rule, +}; + +impl<'a> TryFrom> for ImplDecl { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.clone().into_inner(); + + match rule { + Rule::impl_for_decl => Ok(ImplDecl { + generics: consume_rule(&mut inner, Rule::generics) + .map(Generics::try_from) + .transpose() + .get()? + .unwrap_or_default(), + trait_: Some(inner.next().unwrap().try_into().get()?), + target: inner.next().unwrap().try_into().get()?, + methods: collect_recovered(inner).get()?, + }), + + Rule::impl_decl => Ok(ImplDecl { + generics: consume_rule(&mut inner, Rule::generics) + .map(Generics::try_from) + .transpose() + .get()? + .unwrap_or_default(), + trait_: None, + target: inner.next().unwrap().try_into().get()?, + methods: collect_recovered(inner).get()?, + }), + + _ => unimplemented!("{rule:#?}"), + } + } +} diff --git a/parser/src/parser/items/mod.rs b/parser/src/parser/items/mod.rs new file mode 100644 index 0000000..9eba00e --- /dev/null +++ b/parser/src/parser/items/mod.rs @@ -0,0 +1,129 @@ +pub mod attribute; +pub mod class; +pub mod enums; +pub mod function; +pub mod impl_decl; + +use crate::{ + Rule, + ast::*, + error::{AstError, GetParseError, collect_recovered}, + parser::consume_rule, +}; + +impl<'a> TryFrom> for TopLevel { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let mut inner = pair.into_inner(); + + let attributes = collect_recovered(inner.next().unwrap().into_inner()).get()?; + + Ok(TopLevel( + inner + .next() + .map(TopLevelKind::try_from) + .unwrap_or(Ok(TopLevelKind::ModAttribute)) + .get()?, + attributes, + )) + } +} + +impl<'a> TryFrom> for TopLevelKind { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let rule = pair.as_rule(); + let mut inner = pair.clone().into_inner(); + + Ok(match rule { + Rule::import => TopLevelKind::Import( + Visibility::try_from(&mut inner).get()?, + Path::try_from(inner.next().unwrap()).get()?, + ), + + Rule::function_decl => TopLevelKind::FunctionDecl(pair.try_into().get()?), + + Rule::struct_decl => TopLevelKind::StructDecl { + visibility: Visibility::try_from(&mut inner).get()?, + + name: inner.next().unwrap().try_into().get()?, + + generics: consume_rule(&mut inner, Rule::generics) + .map(Generics::try_from) + .transpose() + .get()? + .unwrap_or_default(), + + fields: inner + .next() + .map(|pair| collect_recovered::(pair.into_inner())) + .transpose() + .get()? + .unwrap_or_default(), + }, + + Rule::class_decl => TopLevelKind::ClassDecl { + visibility: Visibility::try_from(&mut inner).get()?, + + name: inner.next().unwrap().try_into().get()?, + + generics: consume_rule(&mut inner, Rule::generics) + .map(Generics::try_from) + .transpose() + .get()? + .unwrap_or_default(), + + fields: collect_recovered(inner.next().unwrap().into_inner()).get()?, + + constructor: inner.next().unwrap().try_into().get()?, + + items: collect_recovered(inner).get()?, + }, + + Rule::enum_decl => TopLevelKind::EnumDecl { + visibility: Visibility::try_from(&mut inner).get()?, + + name: inner.next().unwrap().try_into().get()?, + + generics: consume_rule(&mut inner, Rule::generics) + .map(Generics::try_from) + .transpose() + .get()? + .unwrap_or_default(), + + fields: collect_recovered(inner).get()?, + }, + + Rule::mod_package => TopLevelKind::Mod( + Visibility::try_from(&mut inner).get()?, + inner.next().unwrap().try_into().get()?, + ), + + Rule::impl_for_decl | Rule::impl_decl => TopLevelKind::ImplDecl(pair.try_into().get()?), + + Rule::trait_decl => TopLevelKind::TraitDecl { + visibility: Visibility::try_from(&mut inner).get()?, + + name: inner.next().unwrap().try_into().get()?, + + generics: consume_rule(&mut inner, Rule::generics) + .map(Generics::try_from) + .transpose() + .get()? + .unwrap_or_default(), + + requirements: consume_rule(&mut inner, Rule::trait_requirements) + .map(|pair| collect_recovered::(pair.into_inner())) + .transpose() + .get()? + .unwrap_or_default(), + + items: collect_recovered(inner).get()?, + }, + + _ => unimplemented!("{rule:#?}"), + }) + } +} diff --git a/parser/src/parser/mod.rs b/parser/src/parser/mod.rs new file mode 100644 index 0000000..d7dad09 --- /dev/null +++ b/parser/src/parser/mod.rs @@ -0,0 +1,29 @@ +pub mod common; +pub mod items; + +use crate::Rule; + +pub fn listen_rule(pairs: &mut pest::iterators::Pairs<'_, Rule>, rule: Rule) -> bool { + let consumed = pairs + .peek() + .map(|p| p.as_rule() == rule) + .unwrap_or_default(); + + if consumed { + pairs.next(); + } + + consumed +} + +pub fn consume_rule<'a>( + pairs: &mut pest::iterators::Pairs<'a, Rule>, + rule: Rule, +) -> Option> { + let consumed = pairs + .peek() + .map(|p| p.as_rule() == rule) + .unwrap_or_default(); + + if consumed { pairs.next() } else { None } +} diff --git a/src/compiler.rs b/src/compiler.rs index f6e7d7e..7b8f585 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -100,7 +100,7 @@ fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path) { } }; - let parser_result = mist_parser::parse(&source).map_err(|e| e.to_string()); + let parser_result = mist_parser::parse(&source).map_err(|e| format!("{e:?}")); let ast = match parser_result { Ok(ast) => ast,