1225 lines
37 KiB
Rust

use super::*;
use crate::error::{
Error,
ErrorKind::{self, *},
PResult, Parsing,
};
use cl_ast::*;
use cl_lexer::Lexer;
// Precedence climbing expression parser
mod prec;
/// Parses a sequence of [Tokens](Token) into an [AST](cl_ast)
#[derive(Debug)]
pub struct Parser<'t> {
/// Name of the file being parsed
file: Sym,
/// Lazy tokenizer
lexer: Lexer<'t>,
/// Look-ahead buffer
next: Option<Token>,
/// The location of the current token
loc: Loc,
}
/// Basic parser functionality
impl<'t> Parser<'t> {
pub fn new(filename: impl AsRef<str>, lexer: Lexer<'t>) -> Self {
Self { file: filename.as_ref().into(), loc: Loc::from(&lexer), lexer, next: None }
}
/// Gets the location of the last consumed [Token]
pub fn loc(&self) -> Loc {
self.loc
}
/// Attempts to parse anything that implements the [Parse] trait
#[inline]
pub fn parse<P: Parse<'t>>(&mut self) -> PResult<P> {
P::parse(self)
}
/// Constructs an [Error]
pub fn error(&self, reason: ErrorKind, while_parsing: Parsing) -> Error {
Error { in_file: self.file, reason, while_parsing, loc: self.loc }
}
/// Internal impl of peek and consume
fn consume_from_lexer(&mut self, while_parsing: Parsing) -> PResult<Token> {
loop {
let tok = self
.lexer
.scan()
.map_err(|e| self.error(e.into(), while_parsing))?;
match tok.ty {
TokenKind::Comment | TokenKind::Invalid => continue,
_ => break Ok(tok),
}
}
}
/// 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!())
}
/// Looks ahead at the next [Token]'s [TokenKind]
pub fn peek_kind(&mut self, while_parsing: Parsing) -> PResult<TokenKind> {
self.peek(while_parsing).map(|t| t.ty)
}
/// 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<Token> {
// location must be updated whenever a token is pulled from the lexer
self.loc = Loc::from(&self.lexer);
self.next.take()
}
/// Consumes one [Token]
pub fn consume(&mut self, while_parsing: Parsing) -> PResult<Token> {
match self.consume_peeked() {
Some(token) => Ok(token),
None => self.consume_from_lexer(while_parsing),
}
}
/// Consumes the next [Token] if it matches the pattern [TokenKind]
pub fn match_type(&mut self, want: TokenKind, while_parsing: Parsing) -> PResult<Token> {
let got = self.peek_kind(while_parsing)?;
if got == want {
Ok(self.consume_peeked().expect("should not fail after peek"))
} else {
Err(self.error(ExpectedToken { want, got }, while_parsing))
}
}
}
// the three matched delimiter pairs
/// Square brackets: `[` `]`
const BRACKETS: (TokenKind, TokenKind) = (TokenKind::LBrack, TokenKind::RBrack);
/// Curly braces: `{` `}`
const CURLIES: (TokenKind, TokenKind) = (TokenKind::LCurly, TokenKind::RCurly);
/// Parentheses: `(` `)`
const PARENS: (TokenKind, TokenKind) = (TokenKind::LParen, TokenKind::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<T>,
delim: (TokenKind, TokenKind),
while_parsing: Parsing,
) -> impl Fn(&mut Parser<'t>) -> PResult<T> {
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<T>,
sep: TokenKind,
until: TokenKind,
while_parsing: Parsing,
) -> impl Fn(&mut Parser<'t>) -> PResult<Vec<T>> {
move |parser| {
let mut args = vec![];
while until != parser.peek_kind(while_parsing)? {
args.push(f(parser)?);
if sep != parser.peek_kind(while_parsing)? {
break;
}
parser.consume_peeked();
}
Ok(args)
}
}
/// Parses constructions of the form `(f ~until)*`
///
/// where `~until` is a negative lookahead assertion
const fn rep<'t, T>(
f: impl Fn(&mut Parser<'t>) -> PResult<T>,
until: TokenKind,
while_parsing: Parsing,
) -> impl Fn(&mut Parser<'t>) -> PResult<Vec<T>> {
move |parser| {
let mut out = vec![];
while until != parser.peek_kind(while_parsing)? {
out.push(f(parser)?)
}
Ok(out)
}
}
/// Expands to a pattern which matches item-like [TokenKind]s
macro item_like() {
TokenKind::Hash
| TokenKind::Pub
| TokenKind::Type
| TokenKind::Const
| TokenKind::Static
| TokenKind::Mod
| TokenKind::Fn
| TokenKind::Struct
| TokenKind::Enum
| TokenKind::Impl
| TokenKind::Use
}
/// Expands to a pattern which matches literal-like [TokenKind]s
macro literal_like() {
TokenKind::True | TokenKind::False | TokenKind::Literal
}
/// Expands to a pattern which matches path-like [TokenKinds](TokenKind)
macro path_like() {
TokenKind::Super | TokenKind::SelfTy | TokenKind::Identifier | TokenKind::ColonColon
}
pub trait Parse<'t>: Sized {
/// Parses a Self from the provided [Parser]
fn parse(p: &mut Parser<'t>) -> PResult<Self>;
}
impl Parse<'_> for Sym {
/// [Sym] = [`Identifier`](TokenKind::Identifier)
fn parse(p: &mut Parser) -> PResult<Sym> {
let tok = p.match_type(TokenKind::Identifier, Parsing::Identifier)?;
match tok.data() {
TokenData::String(ident) => Ok(ident.into()),
_ => panic!("Expected token data for {tok:?}"),
}
}
}
impl Parse<'_> for Mutability {
/// [Mutability] = `mut`?
#[inline]
fn parse(p: &mut Parser) -> PResult<Mutability> {
Ok(match p.match_type(TokenKind::Mut, Parsing::Mutability) {
Ok(_) => Mutability::Mut,
Err(_) => Mutability::Not,
})
}
}
impl Parse<'_> for Visibility {
/// [Visibility] = `pub`?
#[inline]
fn parse(p: &mut Parser) -> PResult<Self> {
Ok(match p.match_type(TokenKind::Pub, Parsing::Visibility) {
Ok(_) => Visibility::Public,
Err(_) => Visibility::Private,
})
}
}
impl Parse<'_> for Literal {
/// [Literal] = [LITERAL](TokenKind::Literal) | `true` | `false`
fn parse(p: &mut Parser) -> PResult<Literal> {
let Token { ty, data, .. } = p.consume(Parsing::Literal)?;
match ty {
TokenKind::True => return Ok(Literal::Bool(true)),
TokenKind::False => return Ok(Literal::Bool(false)),
TokenKind::Literal => (),
t => return Err(p.error(Unexpected(t), Parsing::Literal)),
}
Ok(match data {
TokenData::String(v) => Literal::String(v),
TokenData::Character(v) => Literal::Char(v),
TokenData::Integer(v) => Literal::Int(v),
TokenData::Float(v) => Literal::Float(v.to_bits()),
_ => panic!("Expected token data for {ty:?}"),
})
}
}
impl Parse<'_> for File {
/// Parses a [File]
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
let mut items = vec![];
while match p.peek_kind(Parsing::File) {
Ok(TokenKind::RCurly) | Err(Error { reason: EndOfInput, .. }) => false,
Ok(_) => true,
Err(e) => Err(e)?,
} {
items.push(Item::parse(p)?)
}
Ok(File { name: p.file.to_ref(), items })
}
}
impl Parse<'_> for Attrs {
/// Parses an [attribute set](Attrs)
fn parse(p: &mut Parser) -> PResult<Attrs> {
if p.match_type(TokenKind::Hash, Parsing::Attrs).is_err() {
return Ok(Attrs { meta: vec![] });
}
let meta = delim(
sep(Meta::parse, TokenKind::Comma, BRACKETS.1, Parsing::Attrs),
BRACKETS,
Parsing::Attrs,
)(p)?;
Ok(Attrs { meta })
}
}
impl Parse<'_> for Meta {
/// Parses a single [attribute](Meta)
fn parse(p: &mut Parser) -> PResult<Meta> {
Ok(Meta { name: Sym::parse(p)?, kind: MetaKind::parse(p)? })
}
}
impl Parse<'_> for MetaKind {
/// Parses data associated with a [Meta] attribute
fn parse(p: &mut Parser) -> PResult<MetaKind> {
const P: Parsing = Parsing::Meta;
let lit_tuple = delim(
sep(Literal::parse, TokenKind::Comma, PARENS.1, P),
PARENS,
P,
);
Ok(match p.peek_kind(P) {
Ok(TokenKind::Eq) => {
p.consume_peeked();
MetaKind::Equals(Literal::parse(p)?)
}
Ok(TokenKind::LParen) => MetaKind::Func(lit_tuple(p)?),
_ => MetaKind::Plain,
})
}
}
// --- Items ---
impl Parse<'_> for Item {
/// Parses an [Item]
///
/// See also: [ItemKind::parse]
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
let start = p.loc();
Ok(Item {
attrs: Attrs::parse(p)?,
vis: Visibility::parse(p)?,
kind: ItemKind::parse(p)?,
span: Span(start, p.loc()),
})
}
}
impl Parse<'_> for ItemKind {
/// Parses an [ItemKind]
///
/// See also: [Item::parse]
fn parse(p: &mut Parser) -> PResult<Self> {
Ok(match p.peek_kind(Parsing::Item)? {
TokenKind::Type => Alias::parse(p)?.into(),
TokenKind::Const => Const::parse(p)?.into(),
TokenKind::Static => Static::parse(p)?.into(),
TokenKind::Mod => Module::parse(p)?.into(),
TokenKind::Fn => Function::parse(p)?.into(),
TokenKind::Struct => Struct::parse(p)?.into(),
TokenKind::Enum => Enum::parse(p)?.into(),
TokenKind::Impl => Impl::parse(p)?.into(),
TokenKind::Use => Use::parse(p)?.into(),
t => Err(p.error(Unexpected(t), Parsing::Item))?,
})
}
}
impl Parse<'_> for Generics {
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
const P: Parsing = Parsing::Generics;
let vars = match p.peek_kind(P)? {
TokenKind::Lt => delim(
sep(Sym::parse, TokenKind::Comma, TokenKind::Gt, P),
(TokenKind::Lt, TokenKind::Gt),
P,
)(p)?,
_ => Vec::new(),
};
Ok(Generics { vars })
}
}
impl Parse<'_> for Alias {
/// Parses a [`type` alias](Alias)
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
const P: Parsing = Parsing::Alias;
p.consume_peeked();
let out = Ok(Alias {
name: Sym::parse(p)?,
from: if p.match_type(TokenKind::Eq, P).is_ok() {
Some(Ty::parse(p)?.into())
} else {
None
},
});
p.match_type(TokenKind::Semi, P)?;
out
}
}
impl Parse<'_> for Const {
/// Parses a [compile-time constant](Const)
fn parse(p: &mut Parser) -> PResult<Const> {
const P: Parsing = Parsing::Const;
p.consume_peeked();
let out = Ok(Const {
name: Sym::parse(p)?,
ty: {
p.match_type(TokenKind::Colon, P)?;
Ty::parse(p)?.into()
},
init: {
p.match_type(TokenKind::Eq, P)?;
Expr::parse(p)?.into()
},
});
p.match_type(TokenKind::Semi, P)?;
out
}
}
impl Parse<'_> for Static {
/// Parses a [`static` item](Static)
fn parse(p: &mut Parser) -> PResult<Static> {
const P: Parsing = Parsing::Static;
p.consume_peeked();
let out = Ok(Static {
mutable: Mutability::parse(p)?,
name: Sym::parse(p)?,
ty: {
p.match_type(TokenKind::Colon, P)?;
Ty::parse(p)?.into()
},
init: {
p.match_type(TokenKind::Eq, P)?;
Expr::parse(p)?.into()
},
});
p.match_type(TokenKind::Semi, P)?;
out
}
}
impl Parse<'_> for Module {
/// Parses a [Module]
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
p.consume_peeked();
Ok(Module {
name: Sym::parse(p)?,
file: {
const P: Parsing = Parsing::ModuleKind;
let inline = delim(Parse::parse, CURLIES, P);
match p.peek_kind(P)? {
TokenKind::LCurly => Some(inline(p)?),
TokenKind::Semi => {
p.consume_peeked();
None
}
got => Err(p.error(ExpectedToken { want: TokenKind::Semi, got }, P))?,
}
},
})
}
}
impl Parse<'_> for Function {
/// Parses a [Function] definition
fn parse(p: &mut Parser) -> PResult<Function> {
const P: Parsing = Parsing::Function;
p.consume_peeked();
let name = Sym::parse(p)?;
let gens = Generics::parse(p)?;
let (bind, types) = delim(FnSig::parse, PARENS, P)(p)?;
let sign = TyFn {
args: Box::new(match types.len() {
0 => TyKind::Empty,
_ => TyKind::Tuple(TyTuple { types }),
}),
rety: Ok(match p.match_type(TokenKind::Arrow, Parsing::TyFn) {
Ok(_) => Some(Ty::parse(p)?),
Err(_) => None,
})?
.map(Box::new),
};
Ok(Function {
name,
gens,
sign,
bind,
body: match p.peek_kind(P)? {
TokenKind::Semi => {
p.consume_peeked();
None
}
_ => Some(Expr::parse(p)?),
},
})
}
}
type FnSig = (Pattern, Vec<TyKind>);
impl Parse<'_> for FnSig {
/// Parses the [parameters](Param) associated with a Function
fn parse(p: &mut Parser) -> PResult<FnSig> {
const P: Parsing = Parsing::Function;
let (mut params, mut types) = (vec![], vec![]);
while Ok(TokenKind::RParen) != p.peek_kind(P) {
let (param, ty) = TypedParam::parse(p)?;
params.push(param);
types.push(ty);
if p.match_type(TokenKind::Comma, P).is_err() {
break;
}
}
Ok((Pattern::Tuple(params), types))
}
}
type TypedParam = (Pattern, TyKind);
impl Parse<'_> for TypedParam {
/// Parses a single function [parameter](Param)
fn parse(p: &mut Parser) -> PResult<(Pattern, TyKind)> {
Ok((
Pattern::parse(p)?,
if p.match_type(TokenKind::Colon, Parsing::Param).is_ok() {
TyKind::parse(p)?
} else {
TyKind::Infer
},
))
}
}
impl Parse<'_> for Struct {
/// Parses a [`struct` definition](Struct)
fn parse(p: &mut Parser) -> PResult<Struct> {
p.match_type(TokenKind::Struct, Parsing::Struct)?;
Ok(Struct { name: Sym::parse(p)?, gens: Generics::parse(p)?, kind: StructKind::parse(p)? })
}
}
impl Parse<'_> for StructKind {
/// Parses the various [kinds of Struct](StructKind)
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
const P: Parsing = Parsing::StructKind;
Ok(match p.peek_kind(P) {
Ok(TokenKind::LParen) => StructKind::Tuple(delim(
sep(Ty::parse, TokenKind::Comma, PARENS.1, P),
PARENS,
P,
)(p)?),
Ok(TokenKind::LCurly) => StructKind::Struct(delim(
sep(StructMember::parse, TokenKind::Comma, CURLIES.1, P),
CURLIES,
P,
)(p)?),
Ok(_) | Err(Error { reason: ErrorKind::EndOfInput, .. }) => StructKind::Empty,
Err(e) => Err(e)?,
})
}
}
impl Parse<'_> for StructMember {
/// Parses a single [StructMember]
fn parse(p: &mut Parser) -> PResult<StructMember> {
const P: Parsing = Parsing::StructMember;
Ok(StructMember {
vis: Visibility::parse(p)?,
name: Sym::parse(p)?,
ty: {
p.match_type(TokenKind::Colon, P)?;
Ty::parse(p)?
},
})
}
}
impl Parse<'_> for Enum {
/// Parses an [`enum`](Enum) definition
fn parse(p: &mut Parser) -> PResult<Enum> {
p.match_type(TokenKind::Enum, Parsing::Enum)?;
Ok(Enum {
name: Sym::parse(p)?,
gens: Generics::parse(p)?,
variants: {
const P: Parsing = Parsing::EnumKind;
match p.peek_kind(P)? {
TokenKind::LCurly => delim(
sep(Variant::parse, TokenKind::Comma, TokenKind::RCurly, P),
CURLIES,
P,
)(p)?,
t => Err(p.error(Unexpected(t), P))?,
}
},
})
}
}
impl Parse<'_> for Variant {
/// Parses an [`enum`](Enum) [Variant]
fn parse(p: &mut Parser) -> PResult<Variant> {
let name = Sym::parse(p)?;
let kind;
let body;
if p.match_type(TokenKind::Eq, Parsing::Variant).is_ok() {
kind = StructKind::Empty;
body = Some(Box::new(Expr::parse(p)?));
} else {
kind = StructKind::parse(p)?;
body = None;
}
Ok(Variant { name, kind, body })
}
}
impl Parse<'_> for Impl {
fn parse(p: &mut Parser) -> PResult<Impl> {
const P: Parsing = Parsing::Impl;
p.match_type(TokenKind::Impl, P)?;
Ok(Impl { target: ImplKind::parse(p)?, body: delim(File::parse, CURLIES, P)(p)? })
}
}
impl Parse<'_> for ImplKind {
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
const P: Parsing = Parsing::ImplKind;
let target = Ty::parse(p)?;
if p.match_type(TokenKind::For, P).is_err() {
Ok(ImplKind::Type(target))
} else if let TyKind::Path(impl_trait) = target.kind {
Ok(ImplKind::Trait { impl_trait, for_type: Ty::parse(p)?.into() })
} else {
Err(Error {
in_file: p.file,
reason: ExpectedParsing { want: Parsing::Path },
while_parsing: P,
loc: target.span.head,
})?
}
}
}
impl Parse<'_> for Use {
fn parse(p: &mut Parser) -> PResult<Use> {
const P: Parsing = Parsing::Use;
p.match_type(TokenKind::Use, P)?;
let absolute = p.match_type(TokenKind::ColonColon, P).is_ok();
let tree = UseTree::parse(p)?;
p.match_type(TokenKind::Semi, P)?;
Ok(Use { tree, absolute })
}
}
impl Parse<'_> for UseTree {
fn parse(p: &mut Parser) -> PResult<Self> {
const P: Parsing = Parsing::UseTree;
// glob import
Ok(match p.peek_kind(P)? {
TokenKind::Star => {
p.consume_peeked();
UseTree::Glob
}
TokenKind::LCurly => UseTree::Tree(delim(
sep(Parse::parse, TokenKind::Comma, CURLIES.1, P),
CURLIES,
P,
)(p)?),
TokenKind::Super | TokenKind::Identifier => {
let name = PathPart::parse(p)?;
if p.match_type(TokenKind::ColonColon, P).is_ok() {
UseTree::Path(name, Box::new(UseTree::parse(p)?))
} else {
let PathPart::Ident(name) = name else {
Err(p.error(ErrorKind::ExpectedParsing { want: Parsing::Identifier }, P))?
};
if p.match_type(TokenKind::As, P).is_ok() {
UseTree::Alias(name, p.parse()?)
} else {
UseTree::Name(name)
}
}
}
t => Err(p.error(Unexpected(t), Parsing::UseTree))?,
})
}
}
// --- Types ---
impl Parse<'_> for Ty {
/// Parses a [Ty]
///
/// See also: [TyKind::parse]
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
let start = p.loc();
Ok(Ty { kind: TyKind::parse(p)?, span: Span(start, p.loc()) })
}
}
impl Parse<'_> for TyKind {
/// Parses a [TyKind]
///
/// See also: [Ty::parse]
fn parse(p: &mut Parser) -> PResult<TyKind> {
const P: Parsing = Parsing::TyKind;
let out = match p.peek_kind(P)? {
TokenKind::Bang => {
p.consume_peeked();
TyKind::Never
}
TokenKind::Amp | TokenKind::AmpAmp => TyRef::parse(p)?.into(),
TokenKind::LBrack => {
p.match_type(BRACKETS.0, Parsing::TySlice)?;
let ty = TyKind::parse(p)?;
let (out, kind) = match p.match_type(TokenKind::Semi, Parsing::TyArray).is_ok() {
true => {
let literal = p.match_type(TokenKind::Literal, Parsing::TyArray)?;
let &TokenData::Integer(count) = literal.data() else {
Err(p.error(Unexpected(TokenKind::Literal), Parsing::TyArray))?
};
(
TyKind::Array(TyArray { ty: Box::new(ty), count: count as _ }),
Parsing::TyArray,
)
}
false => (
TyKind::Slice(TySlice { ty: Box::new(ty) }),
Parsing::TySlice,
),
};
p.match_type(BRACKETS.1, kind)?;
out
}
TokenKind::LParen => {
let out = TyTuple::parse(p)?;
match out.types.is_empty() {
true => TyKind::Empty,
false => TyKind::Tuple(out),
}
}
TokenKind::Fn => TyFn::parse(p)?.into(),
path_like!() => {
let path = Path::parse(p)?;
if path.is_sinkhole() {
TyKind::Infer
} else {
TyKind::Path(path)
}
}
t => Err(p.error(Unexpected(t), P))?,
};
Ok(out)
}
}
impl Parse<'_> for TyTuple {
/// [TyTuple] = `(` ([Ty] `,`)* [Ty]? `)`
fn parse(p: &mut Parser) -> PResult<TyTuple> {
const P: Parsing = Parsing::TyTuple;
Ok(TyTuple {
types: delim(sep(TyKind::parse, TokenKind::Comma, PARENS.1, P), PARENS, P)(p)?,
})
}
}
impl Parse<'_> for TyRef {
/// [TyRef] = (`&`|`&&`)* [Path]
fn parse(p: &mut Parser) -> PResult<TyRef> {
const P: Parsing = Parsing::TyRef;
let mut count = 0;
loop {
match p.peek_kind(P)? {
TokenKind::Amp => count += 1,
TokenKind::AmpAmp => count += 2,
_ => break,
}
p.consume_peeked();
}
Ok(TyRef { count, mutable: Mutability::parse(p)?, to: Box::new(Ty::parse(p)?) })
}
}
impl Parse<'_> for TyFn {
/// [TyFn] = `fn` [TyTuple] (-> [Ty])?
fn parse(p: &mut Parser) -> PResult<TyFn> {
const P: Parsing = Parsing::TyFn;
p.match_type(TokenKind::Fn, P)?;
let args = delim(sep(TyKind::parse, TokenKind::Comma, PARENS.1, P), PARENS, P)(p)?;
Ok(TyFn {
args: Box::new(match args {
t if t.is_empty() => TyKind::Empty,
types => TyKind::Tuple(TyTuple { types }),
}),
rety: match p.match_type(TokenKind::Arrow, Parsing::TyFn) {
Ok(_) => Some(Ty::parse(p)?),
Err(_) => None,
}
.map(Into::into),
})
}
}
// --- Paths ---
impl Parse<'_> for Path {
/// Parses a [Path]
///
/// See also: [PathPart::parse], [Sym::parse]
///
/// [Path] = `::` *RelativePath*? | *RelativePath* \
/// *RelativePath* = [PathPart] (`::` [PathPart])*
fn parse(p: &mut Parser) -> PResult<Path> {
const P: Parsing = Parsing::Path;
let absolute = p.match_type(TokenKind::ColonColon, P).is_ok();
let mut parts = vec![];
if absolute {
match PathPart::parse(p) {
Ok(part) => parts.push(part),
Err(_) => return Ok(Path { absolute, parts }),
}
} else {
parts.push(PathPart::parse(p)?)
};
while p.match_type(TokenKind::ColonColon, Parsing::Path).is_ok() {
parts.push(PathPart::parse(p)?)
}
Ok(Path { absolute, parts })
}
}
impl Parse<'_> for PathPart {
/// [PathPart] = `super` | `self` | [`Identifier`](TokenKind::Identifier)
fn parse(p: &mut Parser) -> PResult<PathPart> {
const P: Parsing = Parsing::PathPart;
let out = match p.peek_kind(P)? {
TokenKind::Super => PathPart::SuperKw,
TokenKind::SelfTy => PathPart::SelfTy,
TokenKind::Identifier => PathPart::Ident(Sym::parse(p)?),
t => return Err(p.error(Unexpected(t), P)),
};
// Note: this relies on identifier not peeking
p.consume_peeked();
Ok(out)
}
}
// --- Statements ---
impl Parse<'_> for Stmt {
/// Parses a [Stmt]
///
/// See also: [StmtKind::parse]
fn parse(p: &mut Parser) -> PResult<Stmt> {
let start = p.loc();
Ok(Stmt {
kind: StmtKind::parse(p)?,
semi: match p.match_type(TokenKind::Semi, Parsing::Stmt) {
Ok(_) => Semi::Terminated,
_ => Semi::Unterminated,
},
span: Span(start, p.loc()),
})
}
}
impl Parse<'_> for StmtKind {
/// Parses a [StmtKind]
///
/// See also: [Stmt::parse]
fn parse(p: &mut Parser) -> PResult<StmtKind> {
Ok(match p.peek_kind(Parsing::StmtKind)? {
TokenKind::Semi => StmtKind::Empty,
item_like!() => Item::parse(p)?.into(),
_ => Expr::parse(p)?.into(),
})
}
}
// --- Expressions ---
impl Parse<'_> for Expr {
/// Parses an [Expr]
fn parse(p: &mut Parser) -> PResult<Expr> {
prec::expr(p, 0)
}
}
impl Parse<'_> for Closure {
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
let args = sep(
Pattern::parse,
TokenKind::Comma,
TokenKind::Bar,
Parsing::Closure,
);
let arg = match p.peek_kind(Parsing::Closure)? {
TokenKind::BarBar => {
p.consume_peeked();
Box::new(Pattern::Tuple(vec![]))
}
_ => Box::new(delim(
|p| args(p).map(Pattern::Tuple),
(TokenKind::Bar, TokenKind::Bar),
Parsing::Closure,
)(p)?),
};
let body = p.parse()?;
Ok(Closure { arg, body })
}
}
impl Parse<'_> for Quote {
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
let quote = delim(
Expr::parse,
(TokenKind::Grave, TokenKind::Grave),
Parsing::ExprKind,
)(p)?
.into();
Ok(Quote { quote })
}
}
impl Parse<'_> for Let {
fn parse(p: &mut Parser) -> PResult<Let> {
p.consume_peeked();
Ok(Let {
mutable: Mutability::parse(p)?,
name: Pattern::parse(p)?,
ty: if p.match_type(TokenKind::Colon, Parsing::Let).is_ok() {
Some(Ty::parse(p)?.into())
} else {
None
},
init: if p.match_type(TokenKind::Eq, Parsing::Let).is_ok() {
Some(Expr::parse(p)?.into())
} else {
None
},
})
}
}
impl Parse<'_> for MemberKind {
fn parse(p: &mut Parser) -> PResult<MemberKind> {
const P: Parsing = Parsing::Member;
const DEL: (TokenKind, TokenKind) = PARENS; // delimiter
match p.peek_kind(P)? {
TokenKind::Identifier => {
let name = Sym::parse(p)?;
if p.match_type(DEL.0, P).is_err() {
Ok(MemberKind::Struct(name))
} else {
let exprs = sep(Expr::parse, TokenKind::Comma, DEL.1, P)(p)?;
p.match_type(DEL.1, P)?; // should succeed
Ok(MemberKind::Call(name, Tuple { exprs }))
}
}
TokenKind::Literal => {
let name = Literal::parse(p)?; // TODO: Maybe restrict this to just
Ok(MemberKind::Tuple(name))
}
t => Err(p.error(Unexpected(t), P)),
}
}
}
impl Parse<'_> for Fielder {
/// [Fielder] = [`Identifier`](TokenKind::Identifier) (`:` [Expr])?
fn parse(p: &mut Parser) -> PResult<Fielder> {
const P: Parsing = Parsing::Fielder;
Ok(Fielder {
name: Sym::parse(p)?,
init: match p.match_type(TokenKind::Colon, P) {
Ok(_) => Some(Box::new(Expr::parse(p)?)),
Err(_) => None,
},
})
}
}
impl Parse<'_> for AddrOf {
/// [AddrOf] = (`&`|`&&`)* [Expr]
fn parse(p: &mut Parser) -> PResult<AddrOf> {
const P: Parsing = Parsing::AddrOf;
match p.peek_kind(P)? {
TokenKind::Amp => {
p.consume_peeked();
Ok(AddrOf { mutable: Mutability::parse(p)?, expr: Expr::parse(p)?.into() })
}
TokenKind::AmpAmp => {
let start = p.loc();
p.consume_peeked();
Ok(AddrOf {
mutable: Mutability::Not,
expr: Expr {
kind: ExprKind::AddrOf(AddrOf {
mutable: Mutability::parse(p)?,
expr: Expr::parse(p)?.into(),
}),
span: Span(start, p.loc()),
}
.into(),
})
}
got => Err(p.error(ExpectedToken { want: TokenKind::Amp, got }, P)),
}
}
}
impl Parse<'_> for Block {
/// [Block] = `{` [Stmt]* `}`
fn parse(p: &mut Parser) -> PResult<Block> {
const A_BLOCK: Parsing = Parsing::Block;
Ok(Block { stmts: delim(rep(Parse::parse, CURLIES.1, A_BLOCK), CURLIES, A_BLOCK)(p)? })
}
}
/// Conditions (which precede curly-braced blocks) get special treatment
fn condition(p: &mut Parser) -> PResult<Expr> {
prec::expr(p, prec::Precedence::Condition.level())
}
impl Parse<'_> for While {
/// [While] = `while` [Expr] [Block] [Else]?
#[rustfmt::skip]
fn parse(p: &mut Parser) -> PResult<While> {
p.match_type(TokenKind::While, Parsing::While)?;
Ok(While {
cond: condition(p)?.into(),
pass: Block::parse(p)?.into(),
fail: Else::parse(p)?
})
}
}
impl Parse<'_> for If {
/// [If] = <code>`if` [Expr] [Block] [Else]?</code>
#[rustfmt::skip] // second line is barely not long enough
fn parse(p: &mut Parser) -> PResult<If> {
p.match_type(TokenKind::If, Parsing::If)?;
Ok(If {
cond: condition(p)?.into(),
pass: Block::parse(p)?.into(),
fail: Else::parse(p)?,
})
}
}
impl Parse<'_> for For {
/// [For]: `for` [Pattern] `in` [Expr] [Block] [Else]?
#[rustfmt::skip]
fn parse(p: &mut Parser) -> PResult<For> {
p.match_type(TokenKind::For, Parsing::For)?;
let bind = Pattern::parse(p)?;
p.match_type(TokenKind::In, Parsing::For)?;
Ok(For {
bind,
cond: condition(p)?.into(),
pass: Block::parse(p)?.into(),
fail: Else::parse(p)?,
})
}
}
impl Parse<'_> for Else {
/// [Else]: (`else` [Block])?
fn parse(p: &mut Parser) -> PResult<Else> {
match p.peek_kind(Parsing::Else) {
Ok(TokenKind::Else) => {
p.consume_peeked();
Ok(Expr::parse(p)?.into())
}
Ok(_) | Err(Error { reason: EndOfInput, .. }) => Ok(None.into()),
Err(e) => Err(e),
}
}
}
impl Parse<'_> for Break {
/// [Break] = `break` (*unconsumed* `;` | [Expr])
fn parse(p: &mut Parser) -> PResult<Break> {
p.match_type(TokenKind::Break, Parsing::Break)?;
Ok(Break { body: ret_body(p, Parsing::Break)? })
}
}
impl Parse<'_> for Return {
/// [Return] = `return` (*unconsumed* `;` | [Expr])
fn parse(p: &mut Parser) -> PResult<Return> {
p.match_type(TokenKind::Return, Parsing::Return)?;
Ok(Return { body: ret_body(p, Parsing::Return)? })
}
}
fn pathpattern(p: &mut Parser<'_>) -> PResult<Pattern> {
const P: Parsing = Parsing::Pattern;
let name = Path::parse(p)?;
let struct_members = |p: &mut Parser| {
let name = p.parse()?;
let pat = if p.match_type(TokenKind::Colon, P).is_ok() {
Some(p.parse()?)
} else {
None
};
Ok((name, pat))
};
Ok(match p.peek_kind(Parsing::Pattern)? {
TokenKind::LCurly => Pattern::Struct(
name,
delim(
sep(struct_members, TokenKind::Comma, TokenKind::RCurly, P),
CURLIES,
P,
)(p)?,
),
TokenKind::LParen => Pattern::TupleStruct(
name,
delim(
sep(Parse::parse, TokenKind::Comma, TokenKind::RParen, P),
PARENS,
P,
)(p)?,
),
_ => name
.as_sym()
.map(Pattern::Name)
.unwrap_or(Pattern::Path(name)),
})
}
impl Parse<'_> for Pattern {
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
const P: Parsing = Parsing::Pattern;
Ok(match p.peek_kind(P)? {
// Name, Path, Struct, TupleStruct
TokenKind::Identifier => pathpattern(p)?,
// Literal
TokenKind::Literal => Pattern::Literal(p.parse()?),
// Rest
TokenKind::DotDot => {
p.consume_peeked();
if matches!(
p.peek_kind(P),
Ok(TokenKind::Identifier | TokenKind::Literal)
) {
Pattern::Rest(Some(p.parse()?))
} else {
Pattern::Rest(None)
}
}
// Ref
TokenKind::Amp => {
p.consume_peeked();
Pattern::Ref(p.parse()?, p.parse()?)
}
// Ref(Ref)
TokenKind::AmpAmp => {
p.consume_peeked();
Pattern::Ref(
Mutability::Not,
Box::new(Pattern::Ref(p.parse()?, p.parse()?)),
)
}
// Tuple
TokenKind::LParen => Pattern::Tuple(delim(
sep(Parse::parse, TokenKind::Comma, TokenKind::RParen, P),
PARENS,
P,
)(p)?),
// Array
TokenKind::LBrack => Pattern::Array(delim(
sep(Parse::parse, TokenKind::Comma, TokenKind::RBrack, P),
BRACKETS,
P,
)(p)?),
_ => {
let bad_expr = p.parse()?;
Err(p.error(ErrorKind::InvalidPattern(bad_expr), P))?
}
})
}
}
impl Parse<'_> for Match {
/// [Match] = `match` [Expr] `{` [MatchArm],* `}`
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
p.match_type(TokenKind::Match, Parsing::Match)?;
Ok(Match {
scrutinee: condition(p)?.into(),
arms: delim(
sep(MatchArm::parse, TokenKind::Comma, CURLIES.1, Parsing::Match),
CURLIES,
Parsing::Match,
)(p)?,
})
}
}
impl Parse<'_> for MatchArm {
/// [MatchArm] = [Pattern] `=>` [Expr]
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
let pat = Pattern::parse(p)?;
p.match_type(TokenKind::FatArrow, Parsing::MatchArm)?;
let expr = Expr::parse(p)?;
Ok(MatchArm(pat, expr))
}
}
/// ret_body = (*unconsumed* `;` | [Expr])
fn ret_body(p: &mut Parser, while_parsing: Parsing) -> PResult<Option<Box<Expr>>> {
Ok(match p.peek_kind(while_parsing)? {
TokenKind::Semi => None,
_ => Some(p.parse()?),
})
}
impl<'t, P: Parse<'t>> Parse<'t> for Box<P> {
fn parse(p: &mut Parser<'t>) -> PResult<Self> {
p.parse().map(Box::new)
}
}