From ab17ebbadc66571ccb4de95b281e0e87084bc9b8 Mon Sep 17 00:00:00 2001 From: John Date: Thu, 29 Feb 2024 20:43:40 -0600 Subject: [PATCH] cl-parser: break parser into inline module --- cl-parser/src/lib.rs | 1940 +++++++++++++++++++++--------------------- 1 file changed, 974 insertions(+), 966 deletions(-) diff --git a/cl-parser/src/lib.rs b/cl-parser/src/lib.rs index ea0206e..287a64f 100644 --- a/cl-parser/src/lib.rs +++ b/cl-parser/src/lib.rs @@ -5,17 +5,11 @@ //! [1]: https://git.soft.fish/j/Conlang/src/branch/main/grammar.ebnf #![feature(decl_macro)] +pub use parser::Parser; + use cl_structures::span::*; use cl_token::*; -use crate::error::{ - Error, - ErrorKind::{self, *}, - PResult, Parsing, -}; -use cl_ast::*; -use conlang::lexer::Lexer; - pub mod error { use super::*; @@ -228,625 +222,634 @@ pub mod error { } } +pub mod parser { + 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 + /// 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, } - /// 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), - } + /// Basic parser functionality + impl<'t> Parser<'t> { + pub fn new(lexer: Lexer<'t>) -> Self { + Self { loc: Loc::from(&lexer), lexer, next: None } } - } - /// 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(); + /// Gets the location of the last consumed [Token] + pub fn loc(&self) -> Loc { + self.loc } - let mut parts = vec![self.path_part()?]; - while let Ok(Type::ColonColon) = self.peek_type(PARSING) { - self.consume_peeked(); - parts.push(self.path_part()?); + /// Constructs an [Error] + fn error(&self, reason: ErrorKind, while_parsing: Parsing) -> Error { + Error { reason, while_parsing, loc: self.loc } } - 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 + /// 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), } - _ => 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()) + } + /// 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 { - 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) + Err(self.error(Expected { want, got }, while_parsing)) } - got => Err(self.error(Expected { want: Type::Semi, got }, 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) } } - 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)) + // 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) + } } - 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] + /// Parses constructions of the form `(f sep ~until)*` /// - /// 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 + /// 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(); } - 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) + Ok(args) + } } - /// [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), + + /// 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, - )(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(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, + }) } - 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)? { + + /// 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()) } - _ => None, - } - }, - }) - } -} + 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; -/// 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:?}"), + 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) } } -} -/// # 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(), - }) + /// # 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, + } + }, + }) + } } - 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 - }, - }) + /// 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:?}"), + } + } } -} -macro binary($($name:ident {$lower:ident, $op:ident})*) { + /// # 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![]; @@ -863,302 +866,306 @@ macro binary($($name:ident {$lower:ident, $op:ident})*) { 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), + /// # 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() } - } - - /// [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); + /// 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()) }) } - 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)?, + 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), } } - 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()) + /// [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); } - _ => 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, + 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()), + } } - 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)? }) + + /// ## 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 { + /// ## 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(), @@ -1166,32 +1173,32 @@ impl<'t> Parser<'t> { 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()) + /// [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), } - Ok(_) | Err(Error { reason: EndOfInput, .. }) => Ok(None.into()), - Err(e) => Err(e), } } -} -macro operator($($name:ident ($returns:ident) {$($t:ident => $p:ident),*$(,)?};)*) {$( + 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) { @@ -1204,72 +1211,73 @@ macro operator($($name:ident ($returns:ident) {$($t:ident => $p:ident),*$(,)?};) } )*} -/// ## 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))?, + /// ## 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(()) } - self.consume_peeked(); - Ok(()) } }