This breaks out the pattern matching/unification algorithm from cl-interpret/interpret.rs to cl-interpret/pattern.rs TODO: pattern destructuring in const, static :^)
1126 lines
34 KiB
Rust
1126 lines
34 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> {
|
|
/// 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(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
|
|
}
|
|
|
|
/// 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 { 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::SelfKw
|
|
| 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 { 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)?,
|
|
extents: 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 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 {
|
|
to: 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)?, kind: ModuleKind::parse(p)? })
|
|
}
|
|
}
|
|
|
|
impl Parse<'_> for ModuleKind {
|
|
/// Parses the item list associated with a [Module], if present
|
|
fn parse(p: &mut Parser) -> PResult<ModuleKind> {
|
|
const P: Parsing = Parsing::ModuleKind;
|
|
let inline = delim(Parse::parse, CURLIES, P);
|
|
|
|
match p.peek_kind(P)? {
|
|
TokenKind::LCurly => Ok(ModuleKind::Inline(inline(p)?)),
|
|
TokenKind::Semi => {
|
|
p.consume_peeked();
|
|
Ok(ModuleKind::Outline)
|
|
}
|
|
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 (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,
|
|
sign,
|
|
bind,
|
|
body: match p.peek_kind(P)? {
|
|
TokenKind::Semi => {
|
|
p.consume_peeked();
|
|
None
|
|
}
|
|
_ => Some(Expr::parse(p)?),
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
type FnSig = (Vec<Param>, 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((params, types))
|
|
}
|
|
}
|
|
|
|
type TypedParam = (Param, TyKind);
|
|
|
|
impl Parse<'_> for TypedParam {
|
|
/// Parses a single function [parameter](Param)
|
|
fn parse(p: &mut Parser) -> PResult<(Param, TyKind)> {
|
|
Ok((
|
|
Param { mutability: Mutability::parse(p)?, bind: Pattern::parse(p)? },
|
|
{
|
|
p.match_type(TokenKind::Colon, Parsing::Param)?;
|
|
TyKind::parse(p)?
|
|
},
|
|
))
|
|
}
|
|
}
|
|
|
|
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)?, 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)? {
|
|
TokenKind::LParen => StructKind::Tuple(delim(
|
|
sep(Ty::parse, TokenKind::Comma, PARENS.1, P),
|
|
PARENS,
|
|
P,
|
|
)(p)?),
|
|
TokenKind::LCurly => StructKind::Struct(delim(
|
|
sep(StructMember::parse, TokenKind::Comma, CURLIES.1, P),
|
|
CURLIES,
|
|
P,
|
|
)(p)?),
|
|
TokenKind::Semi => {
|
|
p.consume_peeked();
|
|
StructKind::Empty
|
|
}
|
|
got => Err(p.error(ExpectedToken { want: TokenKind::Semi, got }, P))?,
|
|
})
|
|
}
|
|
}
|
|
|
|
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)?, kind: EnumKind::parse(p)? })
|
|
}
|
|
}
|
|
|
|
impl Parse<'_> for EnumKind {
|
|
/// Parses the various [kinds of Enum](EnumKind)
|
|
fn parse(p: &mut Parser<'_>) -> PResult<EnumKind> {
|
|
const P: Parsing = Parsing::EnumKind;
|
|
Ok(match p.peek_kind(P)? {
|
|
TokenKind::LCurly => EnumKind::Variants(delim(
|
|
sep(Variant::parse, TokenKind::Comma, TokenKind::RCurly, P),
|
|
CURLIES,
|
|
P,
|
|
)(p)?),
|
|
TokenKind::Semi => {
|
|
p.consume_peeked();
|
|
EnumKind::NoVariants
|
|
}
|
|
t => Err(p.error(Unexpected(t), P))?,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl Parse<'_> for Variant {
|
|
/// Parses an [`enum`](Enum) [Variant]
|
|
fn parse(p: &mut Parser) -> PResult<Variant> {
|
|
Ok(Variant { name: Sym::parse(p)?, kind: VariantKind::parse(p)? })
|
|
}
|
|
}
|
|
|
|
impl Parse<'_> for VariantKind {
|
|
/// Parses the various [kinds of Enum Variant](VariantKind)
|
|
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
|
const P: Parsing = Parsing::VariantKind;
|
|
Ok(match p.peek_kind(P)? {
|
|
TokenKind::Eq => {
|
|
p.match_type(TokenKind::Eq, P)?;
|
|
let tok = p.match_type(TokenKind::Literal, P)?;
|
|
|
|
VariantKind::CLike(match tok.data() {
|
|
TokenData::Integer(i) => *i,
|
|
_ => panic!("Expected token data for {tok:?} while parsing {P}"),
|
|
})
|
|
}
|
|
TokenKind::LCurly => VariantKind::Struct(delim(
|
|
sep(StructMember::parse, TokenKind::Comma, TokenKind::RCurly, P),
|
|
CURLIES,
|
|
P,
|
|
)(p)?),
|
|
TokenKind::LParen => {
|
|
let tup = Ty::parse(p)?;
|
|
if !matches!(tup.kind, TyKind::Tuple(_) | TyKind::Empty) {
|
|
Err(p.error(ErrorKind::ExpectedParsing { want: Parsing::TyTuple }, P))?
|
|
}
|
|
|
|
VariantKind::Tuple(tup)
|
|
}
|
|
_ => VariantKind::Plain,
|
|
})
|
|
}
|
|
}
|
|
|
|
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 {
|
|
reason: ExpectedParsing { want: Parsing::Path },
|
|
while_parsing: P,
|
|
loc: target.extents.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::SelfKw | 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)?, extents: 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!() => Path::parse(p)?.into(),
|
|
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: Path::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::SelfKw => PathPart::SelfKw,
|
|
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,
|
|
},
|
|
extents: 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]
|
|
///
|
|
/// See also: [ExprKind::parse]
|
|
fn parse(p: &mut Parser) -> PResult<Expr> {
|
|
let start = p.loc();
|
|
Ok(Expr { kind: ExprKind::parse(p)?, extents: Span(start, p.loc()) })
|
|
}
|
|
}
|
|
|
|
impl Parse<'_> for ExprKind {
|
|
/// Parses an [ExprKind] at the lowest precedence level
|
|
// Implementer's note: Do not call this from within [prec::exprkind]
|
|
fn parse(p: &mut Parser<'_>) -> PResult<ExprKind> {
|
|
prec::exprkind(p, 0)
|
|
}
|
|
}
|
|
|
|
impl Parse<'_> for Quote {
|
|
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
|
let quote = delim(
|
|
ExprKind::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: ExprKind::parse(p)?.into() })
|
|
}
|
|
TokenKind::AmpAmp => {
|
|
p.consume_peeked();
|
|
Ok(AddrOf {
|
|
mutable: Mutability::Not,
|
|
expr: ExprKind::AddrOf(AddrOf {
|
|
mutable: Mutability::parse(p)?,
|
|
expr: ExprKind::parse(p)?.into(),
|
|
})
|
|
.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> {
|
|
let start = p.loc();
|
|
let kind = prec::exprkind(p, prec::Precedence::Condition.level())?;
|
|
Ok(Expr { kind, extents: Span(start, p.loc()) })
|
|
}
|
|
|
|
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)? })
|
|
}
|
|
}
|
|
|
|
impl Parse<'_> for Pattern {
|
|
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
|
let value = prec::exprkind(p, prec::Precedence::Pattern.level())?;
|
|
Pattern::try_from(value).map_err(|e| p.error(InvalidPattern(e.into()), Parsing::Pattern))
|
|
}
|
|
}
|
|
|
|
impl Parse<'_> for Match {
|
|
/// [Match] = `match` [Expr] `{` [MatchArm],* `}`
|
|
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
|
p.match_type(TokenKind::Match, Parsing::Match)?;
|
|
let scrutinee = Expr::parse(p)?.into();
|
|
let arms = delim(
|
|
sep(MatchArm::parse, TokenKind::Comma, CURLIES.1, Parsing::Match),
|
|
CURLIES,
|
|
Parsing::Match,
|
|
)(p)?;
|
|
Ok(Match { scrutinee, arms })
|
|
}
|
|
}
|
|
|
|
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(Expr::parse(p)?.into()),
|
|
})
|
|
}
|