use super::*; use crate::error::{ Error, ErrorKind::{self, *}, PResult, Parsing, }; use cl_ast::*; use conlang::lexer::Lexer; /// Parses a sequence of [Tokens](Token) into an [AST](cl_ast) pub struct Parser<'t> { /// Lazy tokenizer lexer: Lexer<'t>, /// Look-ahead buffer next: Option, /// The location of the current token loc: Loc, } /// Basic parser functionality impl<'t> Parser<'t> { pub fn new(lexer: Lexer<'t>) -> Self { Self { loc: Loc::from(&lexer), lexer, next: None } } /// Gets the location of the last consumed [Token] pub fn loc(&self) -> Loc { self.loc } /// Constructs an [Error] fn error(&self, reason: ErrorKind, while_parsing: Parsing) -> Error { Error { reason, while_parsing, loc: self.loc } } /// Internal impl of peek and consume fn consume_from_lexer(&mut self, while_parsing: Parsing) -> PResult { loop { match self .lexer .scan() .map_err(|e| self.error(e.into(), while_parsing))? { t if t.ty() == Type::Invalid => continue, t if t.ty() == Type::Comment => continue, t => break Ok(t), } } } /// Looks ahead one token /// /// Stores the token in an internal lookahead buffer pub fn peek(&mut self, while_parsing: Parsing) -> PResult<&Token> { if self.next.is_none() { self.next = Some(self.consume_from_lexer(while_parsing)?); } self.next.as_ref().ok_or_else(|| unreachable!()) } /// Consumes a previously peeked [Token], returning it. /// Returns [None] when there is no peeked token. /// /// This avoids the overhead of constructing an [Error] pub fn consume_peeked(&mut self) -> Option { // location must be updated whenever a token is pulled from the lexer self.loc = Loc::from(&self.lexer); self.next.take() } /// Looks ahead at the next [Token]'s [Type] pub fn peek_type(&mut self, while_parsing: Parsing) -> PResult { self.peek(while_parsing).map(|t| t.ty()) } /// Consumes one [Token] pub fn consume(&mut self, while_parsing: Parsing) -> PResult { self.loc = Loc::from(&self.lexer); match self.next.take() { Some(token) => Ok(token), None => self.consume_from_lexer(while_parsing), } } /// Consumes the next [Token] if it matches the pattern [Type] pub fn match_type(&mut self, want: Type, while_parsing: Parsing) -> PResult { let got = self.peek_type(while_parsing)?; if got == want { Ok(self.consume_peeked().expect("should not fail after peek")) } else { Err(self.error(Expected { want, got }, while_parsing)) } } /// Consumes the next token if it matches the pattern [Keyword] pub fn match_kw(&mut self, pat: Keyword, while_parsing: Parsing) -> PResult { self.match_type(Type::Keyword(pat), while_parsing) } } // the three matched delimiter pairs /// Square brackets: `[` `]` const BRACKETS: (Type, Type) = (Type::LBrack, Type::RBrack); /// Curly braces: `{` `}` const CURLIES: (Type, Type) = (Type::LCurly, Type::RCurly); /// Parentheses: `(` `)` const PARENS: (Type, Type) = (Type::LParen, Type::RParen); /// Parses constructions of the form `delim.0 f delim.1` (i.e. `(` `foobar` `)`) const fn delim<'t, T>( f: impl Fn(&mut Parser<'t>) -> PResult, delim: (Type, Type), while_parsing: Parsing, ) -> impl Fn(&mut Parser<'t>) -> PResult { move |parser| { parser.match_type(delim.0, while_parsing)?; let out = f(parser)?; parser.match_type(delim.1, while_parsing)?; Ok(out) } } /// Parses constructions of the form `(f sep ~until)*` /// /// where `~until` is a negative lookahead assertion const fn sep<'t, T>( f: impl Fn(&mut Parser<'t>) -> PResult, sep: Type, until: Type, while_parsing: Parsing, ) -> impl Fn(&mut Parser<'t>) -> PResult> { move |parser| { let mut args = vec![]; while until != parser.peek_type(while_parsing)? { args.push(f(parser)?); if sep != parser.peek_type(while_parsing)? { break; } parser.consume_peeked(); } Ok(args) } } /// Parses constructions of the form `(f ~until)*` /// /// where `~until` is a negative lookahead assertion #[allow(dead_code)] const fn rep<'t, T>( f: impl Fn(&mut Parser<'t>) -> PResult, until: Type, while_parsing: Parsing, ) -> impl Fn(&mut Parser<'t>) -> PResult> { move |parser| { let mut out = vec![]; while until != parser.peek_type(while_parsing)? { out.push(f(parser)?) } Ok(out) } } /// Expands to a pattern which matches item-like [Token] [Type]s macro item_like() { Type::Hash | Type::Keyword( Keyword::Pub | Keyword::Type | Keyword::Const | Keyword::Static | Keyword::Mod | Keyword::Fn | Keyword::Struct | Keyword::Enum | Keyword::Impl, ) } /// Top level parsing impl<'t> Parser<'t> { /// Parses a [File] pub fn file(&mut self) -> PResult { let mut items = vec![]; while match self.peek_type(Parsing::File) { Ok(Type::RCurly) | Err(Error { reason: EndOfInput, .. }) => false, Ok(_) => true, Err(e) => Err(e)?, } { items.push(self.item()?) } Ok(File { items }) } /// Parses an [Item] /// /// See also: [Parser::itemkind] pub fn item(&mut self) -> PResult { let start = self.loc(); Ok(Item { vis: self.visibility()?, attrs: self.attributes()?, kind: self.itemkind()?, extents: Span(start, self.loc()), }) } /// Parses a [Ty] /// /// See also: [Parser::tykind] pub fn ty(&mut self) -> PResult { let start = self.loc(); Ok(Ty { kind: self.tykind()?, extents: Span(start, self.loc()) }) } /// Parses a [Path] /// /// See also: [Parser::path_part], [Parser::identifier] pub fn path(&mut self) -> PResult { const PARSING: Parsing = Parsing::PathExpr; let absolute = matches!(self.peek_type(PARSING)?, Type::ColonColon); if absolute { self.consume_peeked(); } let mut parts = vec![self.path_part()?]; while let Ok(Type::ColonColon) = self.peek_type(PARSING) { self.consume_peeked(); parts.push(self.path_part()?); } Ok(Path { absolute, parts }) } /// Parses a [Stmt] /// /// See also: [Parser::stmtkind] pub fn stmt(&mut self) -> PResult { const PARSING: Parsing = Parsing::Stmt; let start = self.loc(); Ok(Stmt { kind: self.stmtkind()?, semi: match self.peek_type(PARSING) { Ok(Type::Semi) => { self.consume_peeked(); Semi::Terminated } _ => Semi::Unterminated, }, extents: Span(start, self.loc()), }) } /// Parses an [Expr] /// /// See also: [Parser::exprkind] pub fn expr(&mut self) -> PResult { self.expr_from(Self::exprkind) } } /// Attribute parsing impl<'t> Parser<'t> { /// Parses an [attribute set](Attrs) pub fn attributes(&mut self) -> PResult { if self.match_type(Type::Hash, Parsing::Attrs).is_err() { return Ok(Attrs { meta: vec![] }); } let meta = delim( sep(Self::meta, Type::Comma, BRACKETS.1, Parsing::Attrs), BRACKETS, Parsing::Attrs, ); Ok(Attrs { meta: meta(self)? }) } pub fn meta(&mut self) -> PResult { Ok(Meta { name: self.identifier()?, kind: self.meta_kind()? }) } pub fn meta_kind(&mut self) -> PResult { const PARSING: Parsing = Parsing::Meta; let lit_tuple = delim( sep(Self::literal, Type::Comma, PARENS.1, PARSING), PARENS, PARSING, ); Ok(match self.peek_type(PARSING) { Ok(Type::Eq) => { self.consume_peeked(); MetaKind::Equals(self.literal()?) } Ok(Type::LParen) => MetaKind::Func(lit_tuple(self)?), _ => MetaKind::Plain, }) } } /// Item parsing impl<'t> Parser<'t> { /// Parses an [ItemKind] /// /// See also: [Parser::item] pub fn itemkind(&mut self) -> PResult { Ok(match self.peek_type(Parsing::Item)? { Type::Keyword(Keyword::Type) => self.parse_alias()?.into(), Type::Keyword(Keyword::Const) => self.parse_const()?.into(), Type::Keyword(Keyword::Static) => self.parse_static()?.into(), Type::Keyword(Keyword::Mod) => self.parse_module()?.into(), Type::Keyword(Keyword::Fn) => self.parse_function()?.into(), Type::Keyword(Keyword::Struct) => self.parse_struct()?.into(), Type::Keyword(Keyword::Enum) => self.parse_enum()?.into(), Type::Keyword(Keyword::Impl) => self.parse_impl()?.into(), t => Err(self.error(Unexpected(t), Parsing::Item))?, }) } pub fn parse_alias(&mut self) -> PResult { const PARSING: Parsing = Parsing::Alias; self.match_kw(Keyword::Type, PARSING)?; let out = Ok(Alias { to: self.ty()?.into(), from: if self.match_type(Type::Eq, PARSING).is_ok() { Some(self.ty()?.into()) } else { None }, }); self.match_type(Type::Semi, PARSING)?; out } pub fn parse_const(&mut self) -> PResult { const PARSING: Parsing = Parsing::Const; self.match_kw(Keyword::Const, PARSING)?; let out = Ok(Const { name: self.identifier()?, ty: { self.match_type(Type::Colon, PARSING)?; self.ty()?.into() }, init: { self.match_type(Type::Eq, PARSING)?; self.expr()?.into() }, }); self.match_type(Type::Semi, PARSING)?; out } pub fn parse_static(&mut self) -> PResult { const PARSING: Parsing = Parsing::Static; self.match_kw(Keyword::Static, PARSING)?; let out = Ok(Static { mutable: self.mutability()?, name: self.identifier()?, ty: { self.match_type(Type::Colon, PARSING)?; self.ty()?.into() }, init: { self.match_type(Type::Eq, PARSING)?; self.expr()?.into() }, }); self.match_type(Type::Semi, PARSING)?; out } pub fn parse_module(&mut self) -> PResult { const PARSING: Parsing = Parsing::Module; self.match_kw(Keyword::Mod, PARSING)?; Ok(Module { name: self.identifier()?, kind: self.modulekind()? }) } pub fn modulekind(&mut self) -> PResult { const PARSING: Parsing = Parsing::ModuleKind; let inline = delim(Self::file, CURLIES, PARSING); match self.peek_type(PARSING)? { Type::LCurly => Ok(ModuleKind::Inline(inline(self)?)), Type::Semi => { self.consume_peeked(); Ok(ModuleKind::Outline) } got => Err(self.error(Expected { want: Type::Semi, got }, PARSING)), } } pub fn parse_function(&mut self) -> PResult { const PARSING: Parsing = Parsing::Function; self.match_kw(Keyword::Fn, PARSING)?; Ok(Function { name: self.identifier()?, args: self.parse_params()?, rety: match self.peek_type(PARSING)? { Type::LCurly | Type::Semi => None, Type::Arrow => { self.consume_peeked(); Some(self.ty()?.into()) } got => Err(self.error(Expected { want: Type::Arrow, got }, PARSING))?, }, body: match self.peek_type(PARSING)? { Type::LCurly => Some(self.block()?), Type::Semi => { self.consume_peeked(); None } t => Err(self.error(Unexpected(t), PARSING))?, }, }) } pub fn parse_params(&mut self) -> PResult> { const PARSING: Parsing = Parsing::Function; delim( sep(Self::parse_param, Type::Comma, PARENS.1, PARSING), PARENS, PARSING, )(self) } pub fn parse_param(&mut self) -> PResult { Ok(Param { mutability: self.mutability()?, name: self.identifier()?, ty: { self.match_type(Type::Colon, Parsing::Param)?; self.ty()?.into() }, }) } pub fn parse_struct(&mut self) -> PResult { const PARSING: Parsing = Parsing::Struct; self.match_kw(Keyword::Struct, PARSING)?; Ok(Struct { name: self.identifier()?, kind: match self.peek_type(PARSING)? { Type::LParen => self.structkind_tuple()?, Type::LCurly => self.structkind_struct()?, Type::Semi => { self.consume_peeked(); StructKind::Empty } got => Err(self.error(Expected { want: Type::Semi, got }, PARSING))?, }, }) } pub fn structkind_tuple(&mut self) -> PResult { const PARSING: Parsing = Parsing::StructKind; Ok(StructKind::Tuple(delim( sep(Self::ty, Type::Comma, PARENS.1, PARSING), PARENS, PARSING, )(self)?)) } pub fn structkind_struct(&mut self) -> PResult { const PARSING: Parsing = Parsing::StructKind; Ok(StructKind::Struct(delim( sep(Self::struct_member, Type::Comma, CURLIES.1, PARSING), CURLIES, PARSING, )(self)?)) } pub fn struct_member(&mut self) -> PResult { const PARSING: Parsing = Parsing::StructMember; Ok(StructMember { vis: self.visibility()?, name: self.identifier()?, ty: { self.match_type(Type::Colon, PARSING)?; self.ty()? }, }) } pub fn parse_enum(&mut self) -> PResult { const PARSING: Parsing = Parsing::Enum; self.match_kw(Keyword::Enum, PARSING)?; Err(self.error(Todo, PARSING)) } pub fn parse_impl(&mut self) -> PResult { const PARSING: Parsing = Parsing::Impl; self.match_kw(Keyword::Impl, PARSING)?; Err(self.error(Todo, PARSING)) } pub fn visibility(&mut self) -> PResult { if let Type::Keyword(Keyword::Pub) = self.peek_type(Parsing::Visibility)? { self.consume_peeked(); return Ok(Visibility::Public); }; Ok(Visibility::Private) } pub fn mutability(&mut self) -> PResult { if let Type::Keyword(Keyword::Mut) = self.peek_type(Parsing::Mutability)? { self.consume_peeked(); return Ok(Mutability::Mut); }; Ok(Mutability::Not) } } /// # Type parsing impl<'t> Parser<'t> { /// Parses a [TyKind] /// /// See also: [Parser::ty] pub fn tykind(&mut self) -> PResult { const PARSING: Parsing = Parsing::TyKind; let out = match self.peek_type(PARSING)? { Type::Bang => { self.consume_peeked(); TyKind::Never } Type::Keyword(Keyword::SelfTy) => { self.consume_peeked(); TyKind::SelfTy } Type::Amp | Type::AmpAmp => self.tyref()?.into(), Type::LParen => self.tytuple()?.into(), Type::Keyword(Keyword::Fn) => self.tyfn()?.into(), path_like!() => self.path()?.into(), t => Err(self.error(Unexpected(t), PARSING))?, }; Ok(out) } /// [TyTuple] = `(` ([Ty] `,`)* [Ty]? `)` pub fn tytuple(&mut self) -> PResult { const PARSING: Parsing = Parsing::TyTuple; Ok(TyTuple { types: delim( sep(Self::ty, Type::Comma, PARENS.1, PARSING), PARENS, PARSING, )(self)?, }) } /// [TyRef] = (`&`|`&&`)* [Path] pub fn tyref(&mut self) -> PResult { const PARSING: Parsing = Parsing::TyRef; let mut count = 0; loop { match self.peek_type(PARSING)? { Type::Amp => count += 1, Type::AmpAmp => count += 2, _ => break, } self.consume_peeked(); } Ok(TyRef { count, to: self.path()? }) } /// [TyFn] = `fn` [TyTuple] (-> [Ty])? pub fn tyfn(&mut self) -> PResult { const PARSING: Parsing = Parsing::TyFn; self.match_type(Type::Keyword(Keyword::Fn), PARSING)?; Ok(TyFn { args: self.tytuple()?, rety: { match self.peek_type(PARSING)? { Type::Arrow => { self.consume_peeked(); Some(self.ty()?.into()) } _ => None, } }, }) } } /// Expands to a pattern which matches literal-like [Type]s macro literal_like() { Type::Keyword(Keyword::True | Keyword::False) | Type::String | Type::Character | Type::Integer | Type::Float } /// Expands to a pattern which matches path-like [token Types](Type) macro path_like() { Type::Keyword(Keyword::Super | Keyword::SelfKw) | Type::Identifier | Type::ColonColon } /// # Path parsing impl<'t> Parser<'t> { /// [PathPart] = `super` | `self` | [Identifier] pub fn path_part(&mut self) -> PResult { const PARSING: Parsing = Parsing::PathPart; let out = match self.peek_type(PARSING)? { Type::Keyword(Keyword::Super) => PathPart::SuperKw, Type::Keyword(Keyword::SelfKw) => PathPart::SelfKw, Type::Identifier => PathPart::Ident(self.identifier()?), t => return Err(self.error(Unexpected(t), PARSING)), }; self.consume_peeked(); Ok(out) } /// [Identifier] = [`Identifier`](Type::Identifier) pub fn identifier(&mut self) -> PResult { let tok = self.match_type(Type::Identifier, Parsing::Identifier)?; match tok.data() { Data::Identifier(ident) => Ok(ident.into()), _ => panic!("Expected token data for {tok:?}"), } } } /// # Statement parsing impl<'t> Parser<'t> { /// Parses a [StmtKind] /// /// See also: [Parser::stmt] pub fn stmtkind(&mut self) -> PResult { Ok(match self.peek_type(Parsing::StmtKind)? { Type::Semi => StmtKind::Empty, Type::Keyword(Keyword::Let) => self.parse_let()?.into(), item_like!() => self.item()?.into(), _ => self.expr()?.into(), }) } pub fn parse_let(&mut self) -> PResult { self.match_kw(Keyword::Let, Parsing::Let)?; Ok(Let { mutable: self.mutability()?, name: self.identifier()?, ty: if Ok(Type::Colon) == self.peek_type(Parsing::Let) { self.consume_peeked(); Some(self.ty()?.into()) } else { None }, init: if Ok(Type::Eq) == self.peek_type(Parsing::Let) { self.consume_peeked(); Some(self.expr()?.into()) } else { None }, }) } } macro binary($($name:ident {$lower:ident, $op:ident})*) { $(pub fn $name(&mut self) -> PResult { let head = self.expr_from(Self::$lower)?; let mut tail = vec![]; loop { match self.$op() { Ok(op) => tail.push((op, self.expr_from(Self::$lower)?)), Err(Error { reason: Unexpected(_) | EndOfInput, ..}) => break, Err(e) => Err(e)?, } } if tail.is_empty() { return Ok(head.kind); } Ok(Binary { head: head.into(), tail }.into()) })* } /// # Expression parsing impl<'t> Parser<'t> { /// Parses an [ExprKind] /// /// See also: [Parser::expr], [Parser::exprkind_primary] pub fn exprkind(&mut self) -> PResult { self.exprkind_assign() } /// Creates an [Expr] with the given [ExprKind]-parser pub fn expr_from(&mut self, f: impl Fn(&mut Self) -> PResult) -> PResult { let start = self.loc(); Ok(Expr { kind: f(self)?, extents: Span(start, self.loc()) }) } pub fn optional_expr(&mut self) -> PResult> { match self.expr() { Ok(v) => Ok(Some(v)), Err(Error { reason: Nothing, .. }) => Ok(None), Err(e) => Err(e), } } /// [Assign] = [Path] ([AssignKind] [Assign]) | [Compare](Binary) pub fn exprkind_assign(&mut self) -> PResult { let head = self.expr_from(Self::exprkind_compare)?; // TODO: Formalize the concept of a "place expression" if !matches!( head.kind, ExprKind::Path(_) | ExprKind::Call(_) | ExprKind::Member(_) | ExprKind::Index(_) ) { return Ok(head.kind); } let Ok(op) = self.assign_op() else { return Ok(head.kind); }; Ok(Assign { head, op, tail: self.expr_from(Self::exprkind_assign)?.into() }.into()) } // TODO: use a pratt parser for binary expressions, to simplify this binary! { exprkind_compare {exprkind_range, compare_op} exprkind_range {exprkind_logic, range_op} exprkind_logic {exprkind_bitwise, logic_op} exprkind_bitwise {exprkind_shift, bitwise_op} exprkind_shift {exprkind_factor, shift_op} exprkind_factor {exprkind_term, factor_op} exprkind_term {exprkind_unary, term_op} } /// [Unary] = [UnaryKind]* [Member] pub fn exprkind_unary(&mut self) -> PResult { let mut ops = vec![]; loop { match self.unary_op() { Ok(v) => ops.push(v), Err(Error { reason: Unexpected(_), .. }) => break, Err(e) => Err(e)?, } } let tail = self.expr_from(Self::exprkind_member)?; if ops.is_empty() { return Ok(tail.kind); } Ok(Unary { ops, tail: Box::new(tail) }.into()) } /// [Member] = [Call] `.` [Call] pub fn exprkind_member(&mut self) -> PResult { let head = self.expr_from(Self::exprkind_call)?; let mut tail = vec![]; while self.member_op().is_ok() { tail.push(self.expr_from(Self::exprkind_call)?) } if tail.is_empty() { Ok(head.kind) } else { Ok(Member { head: head.into(), tail }.into()) } } /// Call = [Index] (`(` [Tuple]? `)`)* pub fn exprkind_call(&mut self) -> PResult { const PARSING: Parsing = Parsing::Call; let callee = self.expr_from(Self::exprkind_index)?; let mut args = vec![]; while Ok(Type::LParen) == self.peek_type(PARSING) { self.consume_peeked(); args.push(self.tuple()?); self.match_type(Type::RParen, PARSING)?; } if args.is_empty() { Ok(callee.kind) } else { Ok(Call { callee: callee.into(), args }.into()) } } /// [Index] = [Primary](Parser::exprkind_primary) (`[` [Indices] `]`)* pub fn exprkind_index(&mut self) -> PResult { const PARSING: Parsing = Parsing::Index; let head = self.expr_from(Self::exprkind_primary)?; if Ok(Type::LBrack) != self.peek_type(PARSING) { return Ok(head.kind); } let mut indices = vec![]; while Ok(Type::LBrack) == self.peek_type(PARSING) { indices.push(delim(Self::tuple, BRACKETS, PARSING)(self)?.into()); } Ok(Index { head: head.into(), indices }.into()) } /// Delegates to the set of highest-priority rules based on unambiguous pattern matching pub fn exprkind_primary(&mut self) -> PResult { match self.peek_type(Parsing::Expr)? { Type::Amp | Type::AmpAmp => self.exprkind_addrof(), Type::LCurly => self.exprkind_block(), Type::LBrack => self.exprkind_array(), Type::LParen => self.exprkind_empty_group_or_tuple(), literal_like!() => Ok(self.literal()?.into()), path_like!() => Ok(self.path()?.into()), Type::Keyword(Keyword::If) => Ok(self.parse_if()?.into()), Type::Keyword(Keyword::For) => Ok(self.parse_for()?.into()), Type::Keyword(Keyword::While) => Ok(self.parse_while()?.into()), Type::Keyword(Keyword::Break) => Ok(self.parse_break()?.into()), Type::Keyword(Keyword::Return) => Ok(self.parse_return()?.into()), Type::Keyword(Keyword::Continue) => Ok(self.parse_continue()?.into()), _ => Err(self.error(Nothing, Parsing::Expr)), } } /// [Array] = '[' ([Expr] ',')* [Expr]? ']' /// /// Array and ArrayRef are ambiguous until the second token, /// so they can't be independent subexpressions pub fn exprkind_array(&mut self) -> PResult { const PARSING: Parsing = Parsing::Array; const START: Type = Type::LBrack; const END: Type = Type::RBrack; self.match_type(START, PARSING)?; match self.peek_type(PARSING)? { END => { self.consume_peeked(); Ok(Array { values: vec![] }.into()) } _ => self.exprkind_array_rep(), } } /// [ArrayRep] = `[` [Expr] `;` [Expr] `]` pub fn exprkind_array_rep(&mut self) -> PResult { const PARSING: Parsing = Parsing::Array; const END: Type = Type::RBrack; let first = self.expr()?; let out: ExprKind = match self.peek_type(PARSING)? { Type::Semi => ArrayRep { value: first.into(), repeat: { self.consume_peeked(); Box::new(self.expr()?) }, } .into(), Type::RBrack => Array { values: vec![first] }.into(), Type::Comma => Array { values: { self.consume_peeked(); let mut out = vec![first]; out.extend(sep(Self::expr, Type::Comma, END, PARSING)(self)?); out }, } .into(), ty => Err(self.error(Unexpected(ty), PARSING))?, }; self.match_type(END, PARSING)?; Ok(out) } /// [AddrOf] = (`&`|`&&`)* [Expr] pub fn exprkind_addrof(&mut self) -> PResult { const PARSING: Parsing = Parsing::AddrOf; let mut count = 0; loop { match self.peek_type(PARSING)? { Type::Amp => count += 1, Type::AmpAmp => count += 2, _ => break, } self.consume_peeked(); } Ok(AddrOf { count, mutable: self.mutability()?, expr: self.expr()?.into() }.into()) } /// [Block] = `{` [Stmt]* `}` pub fn exprkind_block(&mut self) -> PResult { self.block().map(Into::into) } /// [Group] = `(`([Empty](ExprKind::Empty)|[Expr]|[Tuple])`)` /// /// [ExprKind::Empty] and [Group] are special cases of [Tuple] pub fn exprkind_empty_group_or_tuple(&mut self) -> PResult { self.match_type(Type::LParen, Parsing::Group)?; let out = match self.peek_type(Parsing::Group)? { Type::RParen => Ok(ExprKind::Empty), _ => self.exprkind_group(), }; match self.peek_type(Parsing::Group) { Ok(Type::RParen) => self.consume_peeked(), _ => Err(self.error(UnmatchedParentheses, Parsing::Group))?, }; out } /// [Group] = `(`([Empty](ExprKind::Empty)|[Expr]|[Tuple])`)` pub fn exprkind_group(&mut self) -> PResult { let first = self.expr()?; match self.peek_type(Parsing::Group)? { Type::Comma => { let mut exprs = vec![first]; self.consume_peeked(); while Type::RParen != self.peek_type(Parsing::Tuple)? { exprs.push(self.expr()?); match self.peek_type(Parsing::Tuple)? { Type::Comma => self.consume_peeked(), _ => break, }; } Ok(Tuple { exprs }.into()) } _ => Ok(Group { expr: first.into() }.into()), } } } /// ## Subexpressions impl<'t> Parser<'t> { /// [Literal] = [String](Type::String) | [Character](Type::Character) /// | [Float](Type::Float) (TODO) | [Integer](Type::Integer) | `true` | `false` pub fn literal(&mut self) -> PResult { let tok = self.consume(Parsing::Literal)?; // keyword literals true and false match tok.ty() { Type::Keyword(Keyword::True) => return Ok(Literal::Bool(true)), Type::Keyword(Keyword::False) => return Ok(Literal::Bool(false)), Type::String | Type::Character | Type::Integer | Type::Float => (), t => return Err(self.error(Unexpected(t), Parsing::Literal)), } Ok(match tok.data() { Data::String(v) => Literal::from(v.as_str()), Data::Character(v) => Literal::from(*v), Data::Integer(v) => Literal::from(*v), Data::Float(v) => todo!("Literal::Float({v})"), _ => panic!("Expected token data for {tok:?}"), }) } /// [Tuple] = ([Expr] `,`)* [Expr]? pub fn tuple(&mut self) -> PResult { let mut exprs = vec![]; while let Some(expr) = match self.expr() { Ok(v) => Some(v), Err(Error { reason: Nothing, .. }) => None, Err(e) => return Err(e), } { exprs.push(expr); match self.peek_type(Parsing::Tuple)? { Type::Comma => self.consume_peeked(), _ => break, }; } Ok(Tuple { exprs }) } /// [Block] = `{` [Stmt]* `}` pub fn block(&mut self) -> PResult { const PARSING: Parsing = Parsing::Block; Ok( Block { stmts: delim(rep(Self::stmt, CURLIES.1, PARSING), CURLIES, PARSING)(self)?, }, ) } } /// ## Control flow subexpressions impl<'t> Parser<'t> { /// [Break] = `break` [Expr]? pub fn parse_break(&mut self) -> PResult { self.match_kw(Keyword::Break, Parsing::Break)?; Ok(Break { body: self.optional_expr()?.map(Into::into) }) } /// [Return] = `return` [Expr]? pub fn parse_return(&mut self) -> PResult { self.match_kw(Keyword::Return, Parsing::Return)?; Ok(Return { body: self.optional_expr()?.map(Into::into) }) } /// [Continue] = `continue` pub fn parse_continue(&mut self) -> PResult { self.match_kw(Keyword::Continue, Parsing::Continue)?; Ok(Continue) } /// [While] = `while` [Expr] [Block] [Else]? pub fn parse_while(&mut self) -> PResult { self.match_kw(Keyword::While, Parsing::While)?; Ok(While { cond: self.expr()?.into(), pass: self.block()?.into(), fail: self.parse_else()?, }) } /// [If] = `if` [Expr] [Block] [Else]? #[rustfmt::skip] // second line is barely not long enough pub fn parse_if(&mut self) -> PResult { self.match_kw(Keyword::If, Parsing::If)?; Ok(If { cond: self.expr()?.into(), pass: self.block()?.into(), fail: self.parse_else()?, }) } /// [For]: `for` Pattern (TODO) `in` [Expr] [Block] [Else]? pub fn parse_for(&mut self) -> PResult { self.match_kw(Keyword::For, Parsing::For)?; let bind = self.identifier()?; self.match_kw(Keyword::In, Parsing::For)?; Ok(For { bind, cond: self.expr()?.into(), pass: self.block()?.into(), fail: self.parse_else()?, }) } /// [Else]: (`else` [Block])? pub fn parse_else(&mut self) -> PResult { match self.peek_type(Parsing::Else) { Ok(Type::Keyword(Keyword::Else)) => { self.consume_peeked(); Ok(self.expr()?.into()) } Ok(_) | Err(Error { reason: EndOfInput, .. }) => Ok(None.into()), Err(e) => Err(e), } } } macro operator($($name:ident ($returns:ident) {$($t:ident => $p:ident),*$(,)?};)*) {$( pub fn $name (&mut self) -> PResult<$returns> { const PARSING: Parsing = Parsing::$returns; let out = Ok(match self.peek_type(PARSING) { $(Ok(Type::$t) => $returns::$p,)* Err(e) => Err(e)?, Ok(t) => Err(self.error(Unexpected(t), PARSING))?, }); self.consume_peeked(); out } )*} /// ## Operator Kinds impl<'t> Parser<'t> { operator! { assign_op (AssignKind) { Eq => Plain, // = AmpEq => And, // &= BarEq => Or, // |= XorEq => Xor, // ^= LtLtEq => Shl, // <<= GtGtEq => Shr, // >>= PlusEq => Add, // += MinusEq => Sub, // -= StarEq => Mul, // *= SlashEq => Div, // /= RemEq => Rem, // %= }; compare_op (BinaryKind) { Lt => Lt, // < LtEq => LtEq, // <= EqEq => Equal, // == BangEq => NotEq,// != GtEq => GtEq, // >= Gt => Gt, // > }; range_op (BinaryKind) { DotDot => RangeExc, // .. DotDotEq => RangeInc,// ..= }; logic_op (BinaryKind) { AmpAmp => LogAnd, // && BarBar => LogOr, // || XorXor => LogXor, // ^^ }; bitwise_op (BinaryKind) { Amp => BitAnd, // & Bar => BitOr, // | Xor => BitXor, // ^ }; shift_op (BinaryKind) { LtLt => Shl, // << GtGt => Shr, // >> }; factor_op (BinaryKind) { Plus => Add, // + Minus => Sub, // - }; term_op (BinaryKind) { Star => Mul, // * Slash => Div, // / Rem => Rem, // % }; unary_op (UnaryKind) { Star => Deref, // * Minus => Neg, // - Bang => Not, // ! At => At, // @ Tilde => Tilde, // ~ }; } pub fn member_op(&mut self) -> PResult<()> { const PARSING: Parsing = Parsing::Member; match self.peek(PARSING)?.ty() { Type::Dot => {} t => Err(self.error(Unexpected(t), PARSING))?, } self.consume_peeked(); Ok(()) } }