use super::*;
use crate::error::{
Error,
ErrorKind::{self, *},
PResult, Parsing,
};
use cl_ast::*;
use cl_lexer::Lexer;
#[derive(Debug)]
pub struct Parser<'t> {
lexer: Lexer<'t>,
next: Option<Token>,
loc: Loc,
}
impl<'t> Parser<'t> {
pub fn new(lexer: Lexer<'t>) -> Self {
Self { loc: Loc::from(&lexer), lexer, next: None }
}
pub fn loc(&self) -> Loc {
self.loc
}
fn error(&self, reason: ErrorKind, while_parsing: Parsing) -> Error {
Error { reason, while_parsing, loc: self.loc }
}
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),
}
}
}
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!())
}
pub fn peek_kind(&mut self, while_parsing: Parsing) -> PResult<TokenKind> {
self.peek(while_parsing).map(|t| t.ty)
}
pub fn consume_peeked(&mut self) -> Option<Token> {
self.loc = Loc::from(&self.lexer);
self.next.take()
}
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),
}
}
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))
}
}
#[inline]
pub fn match_op(&mut self, want: Punct, while_parsing: Parsing) -> PResult<Token> {
self.match_type(TokenKind::Punct(want), while_parsing)
}
}
const BRACKETS: (Punct, Punct) = (Punct::LBrack, Punct::RBrack);
const CURLIES: (Punct, Punct) = (Punct::LCurly, Punct::RCurly);
const PARENS: (Punct, Punct) = (Punct::LParen, Punct::RParen);
const fn delim<'t, T>(
f: impl Fn(&mut Parser<'t>) -> PResult<T>,
delim: (Punct, Punct),
while_parsing: Parsing,
) -> impl Fn(&mut Parser<'t>) -> PResult<T> {
move |parser| {
parser.match_op(delim.0, while_parsing)?;
let out = f(parser)?;
parser.match_op(delim.1, while_parsing)?;
Ok(out)
}
}
const fn sep<'t, T>(
f: impl Fn(&mut Parser<'t>) -> PResult<T>,
sep: Punct,
until: Punct,
while_parsing: Parsing,
) -> impl Fn(&mut Parser<'t>) -> PResult<Vec<T>> {
move |parser| {
let mut args = vec![];
while TokenKind::Punct(until) != parser.peek_kind(while_parsing)? {
args.push(f(parser)?);
if TokenKind::Punct(sep) != parser.peek_kind(while_parsing)? {
break;
}
parser.consume_peeked();
}
Ok(args)
}
}
const fn rep<'t, T>(
f: impl Fn(&mut Parser<'t>) -> PResult<T>,
until: Punct,
while_parsing: Parsing,
) -> impl Fn(&mut Parser<'t>) -> PResult<Vec<T>> {
move |parser| {
let mut out = vec![];
while TokenKind::Punct(until) != parser.peek_kind(while_parsing)? {
out.push(f(parser)?)
}
Ok(out)
}
}
macro item_like() {
TokenKind::Punct(Punct::Hash)
| TokenKind::Pub
| TokenKind::Type
| TokenKind::Const
| TokenKind::Static
| TokenKind::Mod
| TokenKind::Fn
| TokenKind::Struct
| TokenKind::Enum
| TokenKind::Impl
| TokenKind::Use
}
impl<'t> Parser<'t> {
pub fn file(&mut self) -> PResult<File> {
let mut items = vec![];
while match self.peek_kind(Parsing::File) {
Ok(TokenKind::Punct(Punct::RCurly)) | Err(Error { reason: EndOfInput, .. }) => false,
Ok(_) => true,
Err(e) => Err(e)?,
} {
items.push(self.item()?)
}
Ok(File { items })
}
pub fn item(&mut self) -> PResult<Item> {
let start = self.loc();
Ok(Item {
attrs: self.attributes()?,
vis: self.visibility(),
kind: self.itemkind()?,
extents: Span(start, self.loc()),
})
}
pub fn ty(&mut self) -> PResult<Ty> {
let start = self.loc();
Ok(Ty { kind: self.tykind()?, extents: Span(start, self.loc()) })
}
pub fn path(&mut self) -> PResult<Path> {
const PARSING: Parsing = Parsing::Path;
let absolute = self.match_op(Punct::ColonColon, PARSING).is_ok();
let mut parts = vec![];
if absolute {
match self.path_part() {
Ok(part) => parts.push(part),
Err(_) => return Ok(Path { absolute, parts }),
}
} else {
parts.push(self.path_part()?)
};
while self.match_op(Punct::ColonColon, Parsing::Path).is_ok() {
parts.push(self.path_part()?)
}
Ok(Path { absolute, parts })
}
pub fn stmt(&mut self) -> PResult<Stmt> {
let start = self.loc();
Ok(Stmt {
kind: self.stmtkind()?,
semi: match self.match_op(Punct::Semi, Parsing::Stmt) {
Ok(_) => Semi::Terminated,
_ => Semi::Unterminated,
},
extents: Span(start, self.loc()),
})
}
pub fn expr(&mut self) -> PResult<Expr> {
self.expr_from(|this| this.exprkind(0))
}
}
impl<'t> Parser<'t> {
pub fn attributes(&mut self) -> PResult<Attrs> {
if self.match_op(Punct::Hash, Parsing::Attrs).is_err() {
return Ok(Attrs { meta: vec![] });
}
let meta = delim(
sep(Self::meta, Punct::Comma, BRACKETS.1, Parsing::Attrs),
BRACKETS,
Parsing::Attrs,
)(self)?;
Ok(Attrs { meta })
}
pub fn meta(&mut self) -> PResult<Meta> {
Ok(Meta { name: self.identifier()?, kind: self.meta_kind()? })
}
pub fn meta_kind(&mut self) -> PResult<MetaKind> {
const PARSING: Parsing = Parsing::Meta;
let lit_tuple = delim(
sep(Self::literal, Punct::Comma, PARENS.1, PARSING),
PARENS,
PARSING,
);
Ok(match self.peek_kind(PARSING) {
Ok(TokenKind::Punct(Punct::Eq)) => {
self.consume_peeked();
MetaKind::Equals(self.literal()?)
}
Ok(TokenKind::Punct(Punct::LParen)) => MetaKind::Func(lit_tuple(self)?),
_ => MetaKind::Plain,
})
}
}
impl<'t> Parser<'t> {
pub fn itemkind(&mut self) -> PResult<ItemKind> {
Ok(match self.peek_kind(Parsing::Item)? {
TokenKind::Type => self.parse_alias()?.into(),
TokenKind::Const => self.parse_const()?.into(),
TokenKind::Static => self.parse_static()?.into(),
TokenKind::Mod => self.parse_module()?.into(),
TokenKind::Fn => self.parse_function()?.into(),
TokenKind::Struct => self.parse_struct()?.into(),
TokenKind::Enum => self.parse_enum()?.into(),
TokenKind::Impl => self.parse_impl()?.into(),
TokenKind::Use => self.parse_use()?.into(),
t => Err(self.error(Unexpected(t), Parsing::Item))?,
})
}
pub fn parse_alias(&mut self) -> PResult<Alias> {
const PARSING: Parsing = Parsing::Alias;
self.consume_peeked();
let out = Ok(Alias {
to: self.identifier()?,
from: if self.match_op(Punct::Eq, PARSING).is_ok() {
Some(self.ty()?.into())
} else {
None
},
});
self.match_op(Punct::Semi, PARSING)?;
out
}
pub fn parse_const(&mut self) -> PResult<Const> {
const PARSING: Parsing = Parsing::Const;
self.consume_peeked();
let out = Ok(Const {
name: self.identifier()?,
ty: {
self.match_op(Punct::Colon, PARSING)?;
self.ty()?.into()
},
init: {
self.match_op(Punct::Eq, PARSING)?;
self.expr()?.into()
},
});
self.match_op(Punct::Semi, PARSING)?;
out
}
pub fn parse_static(&mut self) -> PResult<Static> {
const PARSING: Parsing = Parsing::Static;
self.consume_peeked();
let out = Ok(Static {
mutable: self.mutability(),
name: self.identifier()?,
ty: {
self.match_op(Punct::Colon, PARSING)?;
self.ty()?.into()
},
init: {
self.match_op(Punct::Eq, PARSING)?;
self.expr()?.into()
},
});
self.match_op(Punct::Semi, PARSING)?;
out
}
pub fn parse_module(&mut self) -> PResult<Module> {
self.consume_peeked();
Ok(Module { name: self.identifier()?, kind: self.modulekind()? })
}
pub fn modulekind(&mut self) -> PResult<ModuleKind> {
const PARSING: Parsing = Parsing::ModuleKind;
let inline = delim(Self::file, CURLIES, PARSING);
match self.peek_kind(PARSING)? {
TokenKind::Punct(Punct::LCurly) => Ok(ModuleKind::Inline(inline(self)?)),
TokenKind::Punct(Punct::Semi) => {
self.consume_peeked();
Ok(ModuleKind::Outline)
}
got => Err(self.error(
ExpectedToken { want: TokenKind::Punct(Punct::Semi), got },
PARSING,
)),
}
}
pub fn parse_function(&mut self) -> PResult<Function> {
const PARSING: Parsing = Parsing::Function;
self.consume_peeked();
let name = self.identifier()?;
let (bind, types) = delim(Self::parse_params, PARENS, PARSING)(self)?;
let sign = TyFn {
args: Box::new(match types.len() {
0 => TyKind::Empty,
_ => TyKind::Tuple(TyTuple { types }),
}),
rety: self.parse_rety()?.map(Box::new),
};
Ok(Function {
name,
sign,
bind,
body: match self.peek_kind(PARSING)? {
TokenKind::Punct(Punct::LCurly) => Some(self.block()?),
TokenKind::Punct(Punct::Semi) => {
self.consume_peeked();
None
}
t => Err(self.error(Unexpected(t), PARSING))?,
},
})
}
pub fn parse_params(&mut self) -> PResult<(Vec<Param>, Vec<TyKind>)> {
const PARSING: Parsing = Parsing::Function;
let (mut params, mut types) = (vec![], vec![]);
while Ok(TokenKind::Punct(Punct::RParen)) != self.peek_kind(PARSING) {
let (param, ty) = self.parse_param()?;
params.push(param);
types.push(ty);
if self.match_op(Punct::Comma, PARSING).is_err() {
break;
}
}
Ok((params, types))
}
pub fn parse_param(&mut self) -> PResult<(Param, TyKind)> {
Ok((
Param { mutability: self.mutability(), name: self.identifier()? },
{
self.match_op(Punct::Colon, Parsing::Param)?;
self.tykind()?
},
))
}
pub fn parse_struct(&mut self) -> PResult<Struct> {
const PARSING: Parsing = Parsing::Struct;
self.consume_peeked();
Ok(Struct {
name: self.identifier()?,
kind: match self.peek_kind(PARSING)? {
TokenKind::Punct(Punct::LParen) => self.structkind_tuple()?,
TokenKind::Punct(Punct::LCurly) => self.structkind_struct()?,
TokenKind::Punct(Punct::Semi) => {
self.consume_peeked();
StructKind::Empty
}
got => Err(self.error(
ExpectedToken { want: TokenKind::Punct(Punct::Semi), got },
PARSING,
))?,
},
})
}
pub fn structkind_tuple(&mut self) -> PResult<StructKind> {
const PARSING: Parsing = Parsing::StructKind;
Ok(StructKind::Tuple(delim(
sep(Self::ty, Punct::Comma, PARENS.1, PARSING),
PARENS,
PARSING,
)(self)?))
}
pub fn structkind_struct(&mut self) -> PResult<StructKind> {
const PARSING: Parsing = Parsing::StructKind;
Ok(StructKind::Struct(delim(
sep(Self::struct_member, Punct::Comma, CURLIES.1, PARSING),
CURLIES,
PARSING,
)(self)?))
}
pub fn struct_member(&mut self) -> PResult<StructMember> {
const PARSING: Parsing = Parsing::StructMember;
Ok(StructMember {
vis: self.visibility(),
name: self.identifier()?,
ty: {
self.match_op(Punct::Colon, PARSING)?;
self.ty()?
},
})
}
pub fn parse_enum(&mut self) -> PResult<Enum> {
const PARSING: Parsing = Parsing::Enum;
self.consume_peeked();
Ok(Enum {
name: self.identifier()?,
kind: match self.peek_kind(PARSING)? {
TokenKind::Punct(Punct::LCurly) => EnumKind::Variants(delim(
sep(Self::enum_variant, Punct::Comma, Punct::RCurly, PARSING),
CURLIES,
PARSING,
)(self)?),
TokenKind::Punct(Punct::Semi) => {
self.consume_peeked();
EnumKind::NoVariants
}
t => Err(self.error(Unexpected(t), PARSING))?,
},
})
}
pub fn enum_variant(&mut self) -> PResult<Variant> {
const PARSING: Parsing = Parsing::Variant;
Ok(Variant {
name: self.identifier()?,
kind: match self.peek_kind(PARSING)? {
TokenKind::Punct(Punct::Eq) => self.variantkind_clike()?,
TokenKind::Punct(Punct::LCurly) => self.variantkind_struct()?,
TokenKind::Punct(Punct::LParen) => self.variantkind_tuple()?,
_ => VariantKind::Plain,
},
})
}
pub fn variantkind_clike(&mut self) -> PResult<VariantKind> {
const PARSING: Parsing = Parsing::VariantKind;
self.match_op(Punct::Eq, PARSING)?;
let tok = self.match_type(TokenKind::Literal, PARSING)?;
Ok(VariantKind::CLike(match tok.data() {
TokenData::Integer(i) => *i,
_ => panic!("Expected token data for {tok:?} while parsing {PARSING}"),
}))
}
pub fn variantkind_struct(&mut self) -> PResult<VariantKind> {
const PARSING: Parsing = Parsing::VariantKind;
Ok(VariantKind::Struct(delim(
sep(Self::struct_member, Punct::Comma, Punct::RCurly, PARSING),
CURLIES,
PARSING,
)(self)?))
}
pub fn variantkind_tuple(&mut self) -> PResult<VariantKind> {
const PARSING: Parsing = Parsing::VariantKind;
let tup = self.ty()?;
if !matches!(tup.kind, TyKind::Tuple(_) | TyKind::Empty) {
Err(self.error(
ErrorKind::ExpectedParsing { want: Parsing::TyTuple },
PARSING,
))?
}
Ok(VariantKind::Tuple(tup))
}
pub fn parse_impl(&mut self) -> PResult<Impl> {
const PARSING: Parsing = Parsing::Impl;
self.consume_peeked();
Ok(Impl {
target: self.parse_impl_kind()?,
body: delim(Self::file, CURLIES, PARSING)(self)?,
})
}
pub fn parse_impl_kind(&mut self) -> PResult<ImplKind> {
const PARSING: Parsing = Parsing::ImplKind;
let target = self.ty()?;
if self.match_type(TokenKind::For, PARSING).is_err() {
Ok(ImplKind::Type(target))
} else if let TyKind::Path(impl_trait) = target.kind {
Ok(ImplKind::Trait { impl_trait, for_type: self.ty()?.into() })
} else {
Err(Error {
reason: ExpectedParsing { want: Parsing::Path },
while_parsing: PARSING,
loc: target.extents.head,
})?
}
}
pub fn parse_use(&mut self) -> PResult<Use> {
self.consume_peeked();
let absolute = self.match_op(Punct::ColonColon, Parsing::Use).is_ok();
let tree = self.parse_use_tree()?;
self.match_op(Punct::Semi, Parsing::Use)?;
Ok(Use { tree, absolute })
}
pub fn parse_use_tree(&mut self) -> PResult<UseTree> {
const PARSING: Parsing = Parsing::UseTree;
Ok(match self.peek_kind(PARSING)? {
TokenKind::Punct(Punct::Star) => {
self.consume_peeked();
UseTree::Glob
}
TokenKind::Punct(Punct::LCurly) => UseTree::Tree(delim(
sep(Self::parse_use_tree, Punct::Comma, CURLIES.1, PARSING),
CURLIES,
PARSING,
)(self)?),
TokenKind::SelfKw | TokenKind::Super | TokenKind::Identifier => {
let name = self.path_part()?;
if self.match_op(Punct::ColonColon, PARSING).is_ok() {
UseTree::Path(name, Box::new(self.parse_use_tree()?))
} else {
let PathPart::Ident(name) = name else {
Err(self.error(
ErrorKind::ExpectedParsing { want: Parsing::Identifier },
PARSING,
))?
};
UseTree::Name(name)
}
}
t => Err(self.error(Unexpected(t), Parsing::UseTree))?,
})
}
pub fn visibility(&mut self) -> Visibility {
match self.match_type(TokenKind::Pub, Parsing::Visibility) {
Ok(_) => Visibility::Public,
Err(_) => Visibility::Private,
}
}
pub fn mutability(&mut self) -> Mutability {
match self.match_type(TokenKind::Mut, Parsing::Mutability) {
Ok(_) => Mutability::Mut,
Err(_) => Mutability::Not,
}
}
}
impl<'t> Parser<'t> {
pub fn tykind(&mut self) -> PResult<TyKind> {
const PARSING: Parsing = Parsing::TyKind;
let out = match self.peek_kind(PARSING)? {
TokenKind::Punct(Punct::Bang) => {
self.consume_peeked();
TyKind::Never
}
TokenKind::SelfTy => {
self.consume_peeked();
TyKind::SelfTy
}
TokenKind::Punct(Punct::Amp) | TokenKind::Punct(Punct::AmpAmp) => self.tyref()?.into(),
TokenKind::Punct(Punct::LParen) => {
let out = self.tytuple()?;
match out.types.is_empty() {
true => TyKind::Empty,
false => TyKind::Tuple(out),
}
}
TokenKind::Fn => self.tyfn()?.into(),
path_like!() => self.path()?.into(),
t => Err(self.error(Unexpected(t), PARSING))?,
};
Ok(out)
}
pub fn tytuple(&mut self) -> PResult<TyTuple> {
const PARSING: Parsing = Parsing::TyTuple;
Ok(TyTuple {
types: delim(
sep(Self::tykind, Punct::Comma, PARENS.1, PARSING),
PARENS,
PARSING,
)(self)?,
})
}
pub fn tyref(&mut self) -> PResult<TyRef> {
const PARSING: Parsing = Parsing::TyRef;
let mut count = 0;
loop {
match self.peek_kind(PARSING)? {
TokenKind::Punct(Punct::Amp) => count += 1,
TokenKind::Punct(Punct::AmpAmp) => count += 2,
_ => break,
}
self.consume_peeked();
}
Ok(TyRef { count, mutable: self.mutability(), to: self.path()? })
}
pub fn tyfn(&mut self) -> PResult<TyFn> {
const PARSING: Parsing = Parsing::TyFn;
self.match_type(TokenKind::Fn, PARSING)?;
Ok(TyFn {
args: Box::new(match self.tyfn_args()? {
t if t.is_empty() => TyKind::Empty,
types => TyKind::Tuple(TyTuple { types }),
}),
rety: self.parse_rety()?.map(Into::into),
})
}
pub fn parse_rety(&mut self) -> PResult<Option<Ty>> {
Ok(match self.match_op(Punct::Arrow, Parsing::TyFn) {
Ok(_) => Some(self.ty()?),
Err(_) => None,
})
}
pub fn tyfn_args(&mut self) -> PResult<Vec<TyKind>> {
const P: Parsing = Parsing::TyFn;
delim(sep(Self::tykind, Punct::Comma, PARENS.1, P), PARENS, P)(self)
}
}
macro literal_like() {
TokenKind::True | TokenKind::False | TokenKind::Literal
}
macro path_like() {
TokenKind::Super
| TokenKind::SelfKw
| TokenKind::Identifier
| TokenKind::Punct(Punct::ColonColon)
}
impl<'t> Parser<'t> {
pub fn path_part(&mut self) -> PResult<PathPart> {
const PARSING: Parsing = Parsing::PathPart;
let out = match self.peek_kind(PARSING)? {
TokenKind::Super => PathPart::SuperKw,
TokenKind::SelfKw => PathPart::SelfKw,
TokenKind::Identifier => PathPart::Ident(self.identifier()?),
t => return Err(self.error(Unexpected(t), PARSING)),
};
self.consume_peeked();
Ok(out)
}
pub fn identifier(&mut self) -> PResult<Sym> {
let tok = self.match_type(TokenKind::Identifier, Parsing::Identifier)?;
match tok.data() {
TokenData::String(ident) => Ok(ident.into()),
_ => panic!("Expected token data for {tok:?}"),
}
}
}
impl<'t> Parser<'t> {
pub fn stmtkind(&mut self) -> PResult<StmtKind> {
Ok(match self.peek_kind(Parsing::StmtKind)? {
TokenKind::Punct(Punct::Semi) => StmtKind::Empty,
TokenKind::Let => self.parse_let()?.into(),
item_like!() => self.item()?.into(),
_ => self.expr()?.into(),
})
}
pub fn parse_let(&mut self) -> PResult<Let> {
self.consume_peeked();
Ok(Let {
mutable: self.mutability(),
name: self.identifier()?,
ty: if Ok(TokenKind::Punct(Punct::Colon)) == self.peek_kind(Parsing::Let) {
self.consume_peeked();
Some(self.ty()?.into())
} else {
None
},
init: if Ok(TokenKind::Punct(Punct::Eq)) == self.peek_kind(Parsing::Let) {
self.consume_peeked();
Some(self.expr()?.into())
} else {
None
},
})
}
}
impl<'t> Parser<'t> {
pub fn expr_from(&mut self, f: impl Fn(&mut Self) -> PResult<ExprKind>) -> PResult<Expr> {
let start = self.loc();
Ok(Expr { kind: f(self)?, extents: Span(start, self.loc()) })
}
pub fn exprkind(&mut self, power: u8) -> PResult<ExprKind> {
let parsing = Parsing::ExprKind;
let mut head = match self.peek_kind(Parsing::Unary)? {
literal_like!() => self.literal()?.into(),
path_like!() => self.exprkind_pathlike()?,
TokenKind::Punct(Punct::Amp | Punct::AmpAmp) => self.addrof()?.into(),
TokenKind::Punct(Punct::LCurly) => self.block()?.into(),
TokenKind::Punct(Punct::LBrack) => self.exprkind_arraylike()?,
TokenKind::Punct(Punct::LParen) => self.exprkind_tuplelike()?,
TokenKind::Punct(op) => {
let (kind, prec) = from_prefix(op)
.ok_or_else(|| self.error(Unexpected(TokenKind::Punct(op)), parsing))?;
let ((), after) = prec.prefix().expect("should have a precedence");
self.consume_peeked();
Unary { kind, tail: self.exprkind(after)?.into() }.into()
}
TokenKind::Loop => {
self.consume_peeked();
Loop { body: self.expr()?.into() }.into()
}
TokenKind::While => ExprKind::While(self.parse_while()?),
TokenKind::If => ExprKind::If(self.parse_if()?),
TokenKind::For => ExprKind::For(self.parse_for()?),
TokenKind::Break => ExprKind::Break(self.parse_break()?),
TokenKind::Return => ExprKind::Return(self.parse_return()?),
TokenKind::Continue => {
self.consume_peeked();
Continue.into()
}
t => Err(self.error(Unexpected(t), Parsing::Unary))?,
};
fn from_postfix(op: Punct) -> Option<Precedence> {
Some(match op {
Punct::LBrack => Precedence::Index,
Punct::LParen => Precedence::Call,
Punct::Dot => Precedence::Member,
_ => None?,
})
}
while let Ok(TokenKind::Punct(op)) = self.peek_kind(parsing) {
if let Some((before, ())) = from_postfix(op).and_then(Precedence::postfix) {
if before < power {
break;
}
self.consume_peeked();
head = match op {
Punct::LBrack => {
let indices = sep(Self::expr, Punct::Comma, Punct::RBrack, parsing)(self)?;
self.match_op(Punct::RBrack, parsing)?;
ExprKind::Index(Index { head: head.into(), indices })
}
Punct::LParen => {
let exprs = sep(Self::expr, Punct::Comma, Punct::RParen, parsing)(self)?;
self.match_op(Punct::RParen, parsing)?;
Binary {
kind: BinaryKind::Call,
parts: (head, Tuple { exprs }.into()).into(),
}
.into()
}
Punct::Dot => {
let kind = self.access()?;
Member { head: Box::new(head), kind }.into()
}
_ => Err(self.error(Unexpected(TokenKind::Punct(op)), parsing))?,
};
continue;
}
if let Some((kind, prec)) = from_infix(op) {
let (before, after) = prec.infix().expect("should have a precedence");
if before < power {
break;
}
self.consume_peeked();
let tail = self.exprkind(after)?;
head = Binary { kind, parts: (head, tail).into() }.into();
continue;
}
if let Some((kind, prec)) = from_modify(op) {
let (before, after) = prec.infix().expect("should have a precedence");
if before < power {
break;
}
self.consume_peeked();
let tail = self.exprkind(after)?;
head = Modify { kind, parts: (head, tail).into() }.into();
continue;
}
if let Punct::Eq = op {
let (before, after) = Precedence::Assign
.infix()
.expect("should have a precedence");
if before < power {
break;
}
self.consume_peeked();
let tail = self.exprkind(after)?;
head = Assign { parts: (head, tail).into() }.into();
}
break;
}
Ok(head)
}
pub fn access(&mut self) -> PResult<MemberKind> {
const PARSING: Parsing = Parsing::Member;
const DEL: (Punct, Punct) = PARENS; match self.peek_kind(PARSING)? {
TokenKind::Identifier => {
let name = self.identifier()?;
if self.match_op(DEL.0, PARSING).is_err() {
Ok(MemberKind::Struct(name))
} else {
let exprs = sep(Self::expr, Punct::Comma, DEL.1, PARSING)(self)?;
self.match_op(DEL.1, PARSING)?; Ok(MemberKind::Call(name, Tuple { exprs }))
}
}
TokenKind::Literal => {
let name = self.literal()?; Ok(MemberKind::Tuple(name))
}
t => Err(self.error(Unexpected(t), PARSING)),
}
}
pub fn exprkind_pathlike(&mut self) -> PResult<ExprKind> {
let head = self.path()?;
Ok(match self.match_op(Punct::Colon, Parsing::Path) {
Ok(_) => ExprKind::Structor(self.structor_body(head)?),
Err(_) => ExprKind::Path(head),
})
}
pub fn structor_body(&mut self, to: Path) -> PResult<Structor> {
let init = delim(
sep(Self::fielder, Punct::Comma, CURLIES.1, Parsing::Structor),
CURLIES,
Parsing::Structor,
)(self)?;
Ok(Structor { to, init })
}
pub fn fielder(&mut self) -> PResult<Fielder> {
const PARSING: Parsing = Parsing::Fielder;
Ok(Fielder {
name: self.identifier()?,
init: match self.match_op(Punct::Colon, PARSING) {
Ok(_) => Some(Box::new(self.expr()?)),
Err(_) => None,
},
})
}
pub fn exprkind_arraylike(&mut self) -> PResult<ExprKind> {
const PARSING: Parsing = Parsing::Array;
const START: Punct = Punct::LBrack;
const END: Punct = Punct::RBrack;
self.match_op(START, PARSING)?;
let out = match self.peek_kind(PARSING)? {
TokenKind::Punct(END) => Array { values: vec![] }.into(),
_ => self.exprkind_array_rep()?,
};
self.match_op(END, PARSING)?;
Ok(out)
}
pub fn exprkind_array_rep(&mut self) -> PResult<ExprKind> {
const PARSING: Parsing = Parsing::Array;
const END: Punct = Punct::RBrack;
let first = self.expr()?;
Ok(match self.peek_kind(PARSING)? {
TokenKind::Punct(Punct::Semi) => ArrayRep {
value: first.kind.into(),
repeat: {
self.consume_peeked();
Box::new(self.exprkind(0)?)
},
}
.into(),
TokenKind::Punct(Punct::RBrack) => Array { values: vec![first] }.into(),
TokenKind::Punct(Punct::Comma) => Array {
values: {
self.consume_peeked();
let mut out = vec![first];
out.extend(sep(Self::expr, Punct::Comma, END, PARSING)(self)?);
out
},
}
.into(),
ty => Err(self.error(Unexpected(ty), PARSING))?,
})
}
pub fn exprkind_tuplelike(&mut self) -> PResult<ExprKind> {
self.match_op(Punct::LParen, Parsing::Group)?;
let out = match self.peek_kind(Parsing::Group)? {
TokenKind::Punct(Punct::RParen) => Ok(ExprKind::Empty),
_ => self.exprkind_group(),
};
self.match_op(Punct::RParen, Parsing::Group)?;
out
}
pub fn exprkind_group(&mut self) -> PResult<ExprKind> {
let first = self.expr()?;
match self.peek_kind(Parsing::Group)? {
TokenKind::Punct(Punct::Comma) => {
let mut exprs = vec![first];
self.consume_peeked();
while TokenKind::Punct(Punct::RParen) != self.peek_kind(Parsing::Tuple)? {
exprs.push(self.expr()?);
match self.peek_kind(Parsing::Tuple)? {
TokenKind::Punct(Punct::Comma) => self.consume_peeked(),
_ => break,
};
}
Ok(Tuple { exprs }.into())
}
_ => Ok(Group { expr: first.kind.into() }.into()),
}
}
}
impl<'t> Parser<'t> {
pub fn addrof(&mut self) -> PResult<AddrOf> {
const PARSING: Parsing = Parsing::AddrOf;
let mut count = 0;
loop {
count += match self.peek_kind(PARSING)? {
TokenKind::Punct(Punct::Amp) => 1,
TokenKind::Punct(Punct::AmpAmp) => 2,
_ => break,
};
self.consume_peeked();
}
Ok(AddrOf { count, mutable: self.mutability(), expr: self.exprkind(0)?.into() })
}
pub fn literal(&mut self) -> PResult<Literal> {
let Token { ty, data, .. } = self.consume(Parsing::Literal)?;
match ty {
TokenKind::True => return Ok(Literal::Bool(true)),
TokenKind::False => return Ok(Literal::Bool(false)),
TokenKind::Literal => (),
t => return Err(self.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) => todo!("Literal::Float({v})"),
_ => panic!("Expected token data for {ty:?}"),
})
}
pub fn block(&mut self) -> PResult<Block> {
const A_BLOCK: Parsing = Parsing::Block;
Ok(Block { stmts: delim(rep(Self::stmt, CURLIES.1, A_BLOCK), CURLIES, A_BLOCK)(self)? })
}
}
impl<'t> Parser<'t> {
pub fn parse_break(&mut self) -> PResult<Break> {
self.consume_peeked();
Ok(Break { body: self.ret_body(Parsing::Break)? })
}
pub fn parse_return(&mut self) -> PResult<Return> {
self.consume_peeked();
Ok(Return { body: self.ret_body(Parsing::Return)? })
}
fn ret_body(&mut self, while_parsing: Parsing) -> PResult<Option<Box<Expr>>> {
Ok(match self.peek_kind(while_parsing)? {
TokenKind::Punct(Punct::Semi) => None,
_ => Some(self.expr()?.into()),
})
}
pub fn parse_while(&mut self) -> PResult<While> {
self.consume_peeked();
Ok(While {
cond: self.expr()?.into(),
pass: self.block()?.into(),
fail: self.parse_else()?,
})
}
#[rustfmt::skip] pub fn parse_if(&mut self) -> PResult<If> {
self.consume_peeked();
Ok(If {
cond: self.expr()?.into(),
pass: self.block()?.into(),
fail: self.parse_else()?,
})
}
pub fn parse_for(&mut self) -> PResult<For> {
self.consume_peeked();
let bind = self.identifier()?;
self.match_type(TokenKind::In, Parsing::For)?;
Ok(For {
bind,
cond: self.expr()?.into(),
pass: self.block()?.into(),
fail: self.parse_else()?,
})
}
pub fn parse_else(&mut self) -> PResult<Else> {
match self.peek_kind(Parsing::Else) {
Ok(TokenKind::Else) => {
self.consume_peeked();
Ok(self.expr()?.into())
}
Ok(_) | Err(Error { reason: EndOfInput, .. }) => Ok(None.into()),
Err(e) => Err(e),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Precedence {
Assign,
Compare,
Range,
Index,
Logic,
Bitwise,
Shift,
Factor,
Term,
Unary,
Member, Call,
}
impl Precedence {
#[inline]
pub fn level(self) -> u8 {
(self as u8) << 1
}
pub fn prefix(self) -> Option<((), u8)> {
match self {
Self::Unary => Some(((), self.level())),
_ => None,
}
}
pub fn infix(self) -> Option<(u8, u8)> {
let level = self.level();
match self {
Self::Unary => None,
Self::Assign => Some((level + 1, level)),
_ => Some((level, level + 1)),
}
}
pub fn postfix(self) -> Option<(u8, ())> {
match self {
Self::Index | Self::Call | Self::Member => Some((self.level(), ())),
_ => None,
}
}
}
impl From<ModifyKind> for Precedence {
fn from(_value: ModifyKind) -> Self {
Precedence::Assign
}
}
impl From<BinaryKind> for Precedence {
fn from(value: BinaryKind) -> Self {
use BinaryKind as Op;
match value {
Op::Call => Precedence::Call,
Op::Mul | Op::Div | Op::Rem => Precedence::Term,
Op::Add | Op::Sub => Precedence::Factor,
Op::Shl | Op::Shr => Precedence::Shift,
Op::BitAnd | Op::BitOr | Op::BitXor => Precedence::Bitwise,
Op::LogAnd | Op::LogOr | Op::LogXor => Precedence::Logic,
Op::RangeExc | Op::RangeInc => Precedence::Range,
Op::Lt | Op::LtEq | Op::Equal | Op::NotEq | Op::GtEq | Op::Gt => Precedence::Compare,
}
}
}
impl From<UnaryKind> for Precedence {
fn from(value: UnaryKind) -> Self {
use UnaryKind as Op;
match value {
Op::Deref | Op::Neg | Op::Not | Op::At | Op::Tilde => Precedence::Unary,
}
}
}
macro operator($($name:ident ($takes:ident => $returns:ident) {$($t:ident => $p:ident),*$(,)?};)*) {$(
pub fn $name (value: $takes) -> Option<($returns, Precedence)> {
match value {
$($takes::$t => Some(($returns::$p, Precedence::from($returns::$p))),)*
_ => None?,
}
})*
}
operator! {
from_prefix (Punct => UnaryKind) {
Star => Deref,
Minus => Neg,
Bang => Not,
At => At,
Tilde => Tilde,
};
from_modify(Punct => ModifyKind) {
AmpEq => And,
BarEq => Or,
XorEq => Xor,
LtLtEq => Shl,
GtGtEq => Shr,
PlusEq => Add,
MinusEq => Sub,
StarEq => Mul,
SlashEq => Div,
RemEq => Rem,
};
from_infix (Punct => BinaryKind) {
Lt => Lt,
LtEq => LtEq,
EqEq => Equal,
BangEq => NotEq,
GtEq => GtEq,
Gt => Gt,
DotDot => RangeExc,
DotDotEq => RangeInc,
AmpAmp => LogAnd,
BarBar => LogOr,
XorXor => LogXor,
Amp => BitAnd,
Bar => BitOr,
Xor => BitXor,
LtLt => Shl,
GtGt => Shr,
Plus => Add,
Minus => Sub,
Star => Mul,
Slash => Div,
Rem => Rem,
};
}