diff --git a/parser/src/error.rs b/parser/src/error.rs index 5b12dc7..74974d1 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -16,3 +16,9 @@ pub enum ParseError<'a> { pub enum ErrorCode { InvalidStatement = 200, } + +impl From> for ParseError<'_> { + fn from(value: pest::error::Error) -> Self { + Self::PreAst(value) + } +} diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 03e9347..f72ada3 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -3,11 +3,14 @@ use pest_derive::Parser; pub mod ast; pub mod error; +pub mod parser; use ast::*; use crate::error::{ErrorCode, ParseError, ParseResult}; +use crate::parser::{consume_rule, listen_rule}; + #[derive(Parser)] #[grammar = "./src/grammar.pest"] pub struct MistParser; @@ -26,36 +29,6 @@ pub fn parse<'a>(source: &'a str) -> ParseResult<'a, Vec> { Ok(statements) } -impl From> for ParseError<'_> { - fn from(value: pest::error::Error) -> Self { - Self::PreAst(value) - } -} - -impl<'a> TryFrom> for TypeExpr { - type Error = ParseError<'a>; - - 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( - TypeExprKind::try_from(inner.next().unwrap())?, - inner - .map(TypePostfix::try_from) - .collect::>()?, - )), - Rule::type_expr_param => Self::try_from(inner.next().unwrap()), - Rule::lifetime => Ok(TypeExpr( - TypeExprKind::Lifetime(Identifier::try_from(inner.next().unwrap())?), - Vec::new(), - )), - _ => unimplemented!("{rule:#?}"), - } - } -} - impl<'a> TryFrom> for TypePostfix { type Error = ParseError<'a>; @@ -119,21 +92,6 @@ impl<'a> TryFrom> for TypeExprKind { } } -impl<'a> TryFrom> for Path { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - match pair.as_rule() { - Rule::static_path => Ok(Path( - pair.into_inner() - .map(Identifier::try_from) - .collect::>>()?, - )), - _ => unimplemented!("{pair:#?}"), - } - } -} - impl<'a> TryFrom> for ParamList { type Error = ParseError<'a>; @@ -614,30 +572,6 @@ impl<'a> TryFrom> for Statement { } } -impl<'a> TryFrom> for Literal { - type Error = ParseError<'a>; - - 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( - inner - .map(Expression::try_from) - .collect::>>()?, - ), - _ => unimplemented!("{rule:#?}"), - }) - } -} - impl<'a> TryFrom> for Expression { type Error = ParseError<'a>; @@ -896,118 +830,3 @@ impl<'a> TryFrom> for FieldDecl { } } } - -impl<'a> TryFrom> for FunctionDecl { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - let mut inner = pair.into_inner(); - let visibility = Visibility::try_from(&mut inner)?; - let return_type = TypeExpr::try_from(inner.next().unwrap())?; - let name = Identifier::try_from(inner.next().unwrap())?; - let generics = consume_rule(&mut inner, Rule::generics) - .map(Generics::try_from) - .transpose()? - .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| -> ParseResult<'a, ParamList> { - let mut params = ParamList::try_from(params_pair)?; - if let Some(x) = self_param { - params.0.insert(0, x); - } - Ok(params) - } - }) - .transpose()? - .unwrap_or_else(|| ParamList(self_param.into_iter().collect())); - - let body = inner.next().map(Block::try_from).transpose()?; - - Ok(Self { - visibility, - name, - generics, - params, - return_type, - body, - }) - } -} -impl<'a> TryFrom<&mut pest::iterators::Pairs<'a, Rule>> for Visibility { - type Error = ParseError<'a>; - - 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)?)) - } else { - Ok(Visibility::Public) - } - }) - .transpose()? - .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<'a> TryFrom> for Identifier { - type Error = ParseError<'a>; - - fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { - Ok(Identifier(pair.as_str().to_string())) - } -} diff --git a/parser/src/parser/common.rs b/parser/src/parser/common.rs new file mode 100644 index 0000000..d4d274c --- /dev/null +++ b/parser/src/parser/common.rs @@ -0,0 +1,94 @@ +use crate::{ + Rule, + ast::*, + error::{ParseError, ParseResult}, + parser::consume_rule, +}; + +impl<'a> TryFrom> for Identifier { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + Ok(Identifier(pair.as_str().to_string())) + } +} + +impl<'a> TryFrom> for Path { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + match pair.as_rule() { + Rule::static_path => Ok(Path( + pair.into_inner() + .map(Identifier::try_from) + .collect::>>()?, + )), + _ => unimplemented!("{pair:#?}"), + } + } +} + +impl<'a> TryFrom<&mut pest::iterators::Pairs<'a, Rule>> for Visibility { + type Error = ParseError<'a>; + + 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)?)) + } else { + Ok(Visibility::Public) + } + }) + .transpose()? + .unwrap_or_else(|| Visibility::Private)) + } +} + +impl<'a> TryFrom> for Literal { + type Error = ParseError<'a>; + + 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( + inner + .map(Expression::try_from) + .collect::>>()?, + ), + _ => unimplemented!("{rule:#?}"), + }) + } +} + +impl<'a> TryFrom> for TypeExpr { + type Error = ParseError<'a>; + + 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( + TypeExprKind::try_from(inner.next().unwrap())?, + inner + .map(TypePostfix::try_from) + .collect::>()?, + )), + Rule::type_expr_param => Self::try_from(inner.next().unwrap()), + Rule::lifetime => Ok(TypeExpr( + TypeExprKind::Lifetime(Identifier::try_from(inner.next().unwrap())?), + Vec::new(), + )), + _ => unimplemented!("{rule:#?}"), + } + } +} diff --git a/parser/src/parser/items/function.rs b/parser/src/parser/items/function.rs new file mode 100644 index 0000000..4de9d45 --- /dev/null +++ b/parser/src/parser/items/function.rs @@ -0,0 +1,72 @@ +use crate::{ + Rule, + ast::*, + error::{ParseError, ParseResult}, + parser::{consume_rule, listen_rule}, +}; + +impl<'a> TryFrom> for FunctionDecl { + type Error = ParseError<'a>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let mut inner = pair.into_inner(); + let visibility = Visibility::try_from(&mut inner)?; + let return_type = TypeExpr::try_from(inner.next().unwrap())?; + let name = Identifier::try_from(inner.next().unwrap())?; + let generics = consume_rule(&mut inner, Rule::generics) + .map(Generics::try_from) + .transpose()? + .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| -> ParseResult<'a, ParamList> { + let mut params = ParamList::try_from(params_pair)?; + if let Some(x) = self_param { + params.0.insert(0, x); + } + Ok(params) + } + }) + .transpose()? + .unwrap_or_else(|| ParamList(self_param.into_iter().collect())); + + let body = inner.next().map(Block::try_from).transpose()?; + + Ok(Self { + visibility, + name, + generics, + params, + return_type, + body, + }) + } +} diff --git a/parser/src/parser/items/mod.rs b/parser/src/parser/items/mod.rs new file mode 100644 index 0000000..7fd349b --- /dev/null +++ b/parser/src/parser/items/mod.rs @@ -0,0 +1 @@ +pub mod function; \ No newline at end of file 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 } +}