From abf00f383c0205457fc4039197f19e0e73e67bbf Mon Sep 17 00:00:00 2001 From: John Date: Thu, 29 Feb 2024 20:44:49 -0600 Subject: [PATCH] cl-parser: Move inline modules out of line --- cl-parser/src/error.rs | 209 +++++++ cl-parser/src/lib.rs | 1272 +-------------------------------------- cl-parser/src/parser.rs | 1057 ++++++++++++++++++++++++++++++++ 3 files changed, 1268 insertions(+), 1270 deletions(-) create mode 100644 cl-parser/src/error.rs create mode 100644 cl-parser/src/parser.rs diff --git a/cl-parser/src/error.rs b/cl-parser/src/error.rs new file mode 100644 index 0000000..97eedfe --- /dev/null +++ b/cl-parser/src/error.rs @@ -0,0 +1,209 @@ +use super::*; + +use conlang::lexer::error::{Error as LexError, Reason}; +use std::fmt::Display; +pub type PResult = Result; + +/// Contains information about [Parser] errors +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Error { + pub reason: ErrorKind, + pub while_parsing: Parsing, + pub loc: Loc, +} +impl std::error::Error for Error {} + +/// Represents the reason for parse failure +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum ErrorKind { + Lexical(LexError), + EndOfInput, + UnmatchedParentheses, + UnmatchedCurlyBraces, + UnmatchedSquareBrackets, + Unexpected(Type), + Expected { + want: Type, + got: Type, + }, + /// No rules matched + Nothing, + /// Indicates unfinished code + Todo, +} +impl From for ErrorKind { + fn from(value: LexError) -> Self { + match value.reason() { + Reason::EndOfFile => Self::EndOfInput, + _ => Self::Lexical(value), + } + } +} + +/// Compactly represents the stage of parsing an [Error] originated in +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Parsing { + File, + + Attrs, + Meta, + + Item, + Visibility, + Mutability, + ItemKind, + Alias, + Const, + Static, + Module, + ModuleKind, + Function, + Param, + Struct, + StructKind, + StructMember, + Enum, + EnumKind, + Variant, + VariantKind, + Impl, + + Ty, + TyKind, + TyTuple, + TyRef, + TyFn, + + Stmt, + StmtKind, + Let, + + Expr, + ExprKind, + Assign, + AssignKind, + Binary, + BinaryKind, + Unary, + UnaryKind, + Index, + Call, + Member, + PathExpr, + PathPart, + Identifier, + Literal, + Array, + ArrayRep, + AddrOf, + Block, + Group, + Tuple, + While, + If, + For, + Else, + Break, + Return, + Continue, +} + +impl Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { reason, while_parsing, loc } = self; + match reason { + // TODO entries are debug-printed + ErrorKind::Todo => write!(f, "{loc} {reason} {while_parsing:?}"), + // lexical errors print their own higher-resolution loc info + ErrorKind::Lexical(e) => write!(f, "{e} (while parsing {while_parsing})"), + _ => write!(f, "{loc} {reason} while parsing {while_parsing}"), + } + } +} +impl Display for ErrorKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ErrorKind::Lexical(e) => e.fmt(f), + ErrorKind::EndOfInput => write!(f, "End of input"), + ErrorKind::UnmatchedParentheses => write!(f, "Unmatched parentheses"), + ErrorKind::UnmatchedCurlyBraces => write!(f, "Unmatched curly braces"), + ErrorKind::UnmatchedSquareBrackets => write!(f, "Unmatched square brackets"), + ErrorKind::Unexpected(t) => write!(f, "Encountered unexpected token `{t}`"), + ErrorKind::Expected { want: e, got: g } => { + write!(f, "Expected {e}, but got {g}") + } + ErrorKind::Nothing => write!(f, "Nothing found"), + ErrorKind::Todo => write!(f, "TODO:"), + } + } +} +impl Display for Parsing { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Parsing::File => "a file", + + Parsing::Attrs => "an attribute-set", + Parsing::Meta => "an attribute", + + Parsing::Item => "an item", + Parsing::Visibility => "a visibility qualifier", + Parsing::Mutability => "a mutability qualifier", + Parsing::ItemKind => "an item", + Parsing::Alias => "a type alias", + Parsing::Const => "a const item", + Parsing::Static => "a static variable", + Parsing::Module => "a module", + Parsing::ModuleKind => "a module", + Parsing::Function => "a function", + Parsing::Param => "a function parameter", + Parsing::Struct => "a struct", + Parsing::StructKind => "a struct", + Parsing::StructMember => "a struct member", + Parsing::Enum => "an enum", + Parsing::EnumKind => "an enum", + Parsing::Variant => "an enum variant", + Parsing::VariantKind => "an enum variant", + Parsing::Impl => "an impl block", + + Parsing::Ty => "a type", + Parsing::TyKind => "a type", + Parsing::TyTuple => "a tuple of types", + Parsing::TyRef => "a reference type", + Parsing::TyFn => "a function pointer type", + + Parsing::Stmt => "a statement", + Parsing::StmtKind => "a statement", + Parsing::Let => "a local variable declaration", + + Parsing::Expr => "an expression", + Parsing::ExprKind => "an expression", + Parsing::Assign => "an assignment", + Parsing::AssignKind => "an assignment operator", + Parsing::Binary => "a binary expression", + Parsing::BinaryKind => "a binary operator", + Parsing::Unary => "a unary expression", + Parsing::UnaryKind => "a unary operator", + Parsing::Index => "an indexing expression", + Parsing::Call => "a call expression", + Parsing::Member => "a member access expression", + Parsing::PathExpr => "a path", + Parsing::PathPart => "a path component", + Parsing::Identifier => "an identifier", + Parsing::Literal => "a literal", + Parsing::Array => "an array", + Parsing::ArrayRep => "an array of form [k;N]", + Parsing::AddrOf => "a borrow op", + Parsing::Block => "a block", + Parsing::Group => "a grouped expression", + Parsing::Tuple => "a tuple", + Parsing::While => "a while expression", + Parsing::If => "an if expression", + Parsing::For => "a for expression", + Parsing::Else => "an else block", + Parsing::Break => "a break expression", + Parsing::Return => "a return expression", + Parsing::Continue => "a continue expression", + } + .fmt(f) + } +} diff --git a/cl-parser/src/lib.rs b/cl-parser/src/lib.rs index 287a64f..e4e7524 100644 --- a/cl-parser/src/lib.rs +++ b/cl-parser/src/lib.rs @@ -10,1274 +10,6 @@ pub use parser::Parser; use cl_structures::span::*; use cl_token::*; -pub mod error { - use super::*; +pub mod error; - use conlang::lexer::error::{Error as LexError, Reason}; - use std::fmt::Display; - pub type PResult = Result; - - /// Contains information about [Parser] errors - #[derive(Clone, Debug, PartialEq, Eq)] - pub struct Error { - pub reason: ErrorKind, - pub while_parsing: Parsing, - pub loc: Loc, - } - impl std::error::Error for Error {} - - /// Represents the reason for parse failure - #[derive(Clone, Debug, PartialEq, Eq)] - pub enum ErrorKind { - Lexical(LexError), - EndOfInput, - UnmatchedParentheses, - UnmatchedCurlyBraces, - UnmatchedSquareBrackets, - Unexpected(Type), - Expected { - want: Type, - got: Type, - }, - /// No rules matched - Nothing, - /// Indicates unfinished code - Todo, - } - impl From for ErrorKind { - fn from(value: LexError) -> Self { - match value.reason() { - Reason::EndOfFile => Self::EndOfInput, - _ => Self::Lexical(value), - } - } - } - - /// Compactly represents the stage of parsing an [Error] originated in - #[derive(Clone, Copy, Debug, PartialEq, Eq)] - pub enum Parsing { - File, - - Attrs, - Meta, - - Item, - Visibility, - Mutability, - ItemKind, - Alias, - Const, - Static, - Module, - ModuleKind, - Function, - Param, - Struct, - StructKind, - StructMember, - Enum, - EnumKind, - Variant, - VariantKind, - Impl, - - Ty, - TyKind, - TyTuple, - TyRef, - TyFn, - - Stmt, - StmtKind, - Let, - - Expr, - ExprKind, - Assign, - AssignKind, - Binary, - BinaryKind, - Unary, - UnaryKind, - Index, - Call, - Member, - PathExpr, - PathPart, - Identifier, - Literal, - Array, - ArrayRep, - AddrOf, - Block, - Group, - Tuple, - While, - If, - For, - Else, - Break, - Return, - Continue, - } - - impl Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let Self { reason, while_parsing, loc } = self; - match reason { - // TODO entries are debug-printed - ErrorKind::Todo => write!(f, "{loc} {reason} {while_parsing:?}"), - // lexical errors print their own higher-resolution loc info - ErrorKind::Lexical(e) => write!(f, "{e} (while parsing {while_parsing})"), - _ => write!(f, "{loc} {reason} while parsing {while_parsing}"), - } - } - } - impl Display for ErrorKind { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - ErrorKind::Lexical(e) => e.fmt(f), - ErrorKind::EndOfInput => write!(f, "End of input"), - ErrorKind::UnmatchedParentheses => write!(f, "Unmatched parentheses"), - ErrorKind::UnmatchedCurlyBraces => write!(f, "Unmatched curly braces"), - ErrorKind::UnmatchedSquareBrackets => write!(f, "Unmatched square brackets"), - ErrorKind::Unexpected(t) => write!(f, "Encountered unexpected token `{t}`"), - ErrorKind::Expected { want: e, got: g } => { - write!(f, "Expected {e}, but got {g}") - } - ErrorKind::Nothing => write!(f, "Nothing found"), - ErrorKind::Todo => write!(f, "TODO:"), - } - } - } - impl Display for Parsing { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Parsing::File => "a file", - - Parsing::Attrs => "an attribute-set", - Parsing::Meta => "an attribute", - - Parsing::Item => "an item", - Parsing::Visibility => "a visibility qualifier", - Parsing::Mutability => "a mutability qualifier", - Parsing::ItemKind => "an item", - Parsing::Alias => "a type alias", - Parsing::Const => "a const item", - Parsing::Static => "a static variable", - Parsing::Module => "a module", - Parsing::ModuleKind => "a module", - Parsing::Function => "a function", - Parsing::Param => "a function parameter", - Parsing::Struct => "a struct", - Parsing::StructKind => "a struct", - Parsing::StructMember => "a struct member", - Parsing::Enum => "an enum", - Parsing::EnumKind => "an enum", - Parsing::Variant => "an enum variant", - Parsing::VariantKind => "an enum variant", - Parsing::Impl => "an impl block", - - Parsing::Ty => "a type", - Parsing::TyKind => "a type", - Parsing::TyTuple => "a tuple of types", - Parsing::TyRef => "a reference type", - Parsing::TyFn => "a function pointer type", - - Parsing::Stmt => "a statement", - Parsing::StmtKind => "a statement", - Parsing::Let => "a local variable declaration", - - Parsing::Expr => "an expression", - Parsing::ExprKind => "an expression", - Parsing::Assign => "an assignment", - Parsing::AssignKind => "an assignment operator", - Parsing::Binary => "a binary expression", - Parsing::BinaryKind => "a binary operator", - Parsing::Unary => "a unary expression", - Parsing::UnaryKind => "a unary operator", - Parsing::Index => "an indexing expression", - Parsing::Call => "a call expression", - Parsing::Member => "a member access expression", - Parsing::PathExpr => "a path", - Parsing::PathPart => "a path component", - Parsing::Identifier => "an identifier", - Parsing::Literal => "a literal", - Parsing::Array => "an array", - Parsing::ArrayRep => "an array of form [k;N]", - Parsing::AddrOf => "a borrow op", - Parsing::Block => "a block", - Parsing::Group => "a grouped expression", - Parsing::Tuple => "a tuple", - Parsing::While => "a while expression", - Parsing::If => "an if expression", - Parsing::For => "a for expression", - Parsing::Else => "an else block", - Parsing::Break => "a break expression", - Parsing::Return => "a return expression", - Parsing::Continue => "a continue expression", - } - .fmt(f) - } - } -} - -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 - } - - /// 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(()) - } - } -} +pub mod parser; diff --git a/cl-parser/src/parser.rs b/cl-parser/src/parser.rs new file mode 100644 index 0000000..6637385 --- /dev/null +++ b/cl-parser/src/parser.rs @@ -0,0 +1,1057 @@ +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(()) + } +}