doughlang: Preserve errors through entire pipeline
lexer: - Un-stringify errors - Reserve more words - Doc the comments parser: - MASSIVE changes to peek, peek_if, next_if, consume_if=>expect. - Keep track of when EOF is allowable - TKind is stupidly cheap with >100 niches, so we can fit like 4 of them in a single ParseError lmao - TODO: make sure EOF/UnexpectedEOF propagation is correct. It seems... Kinda Not correct. - Add meta-expressions
This commit is contained in:
574
src/parser.rs
574
src/parser.rs
@@ -1,7 +1,7 @@
|
||||
//! The parser takes a stream of [Token]s from the [Lexer], and turns them into [crate::ast] nodes.
|
||||
use crate::{
|
||||
ast::*,
|
||||
lexer::{LexError, Lexer},
|
||||
lexer::{LexError, LexFailure, Lexer},
|
||||
span::Span,
|
||||
token::{Lexeme, TKind, Token},
|
||||
};
|
||||
@@ -9,8 +9,12 @@ use std::{error::Error, fmt::Display, vec};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum ParseError {
|
||||
/// Reached the expected end of input.
|
||||
EOF(Span),
|
||||
/// Unexpectedly reached end of input.
|
||||
UnexpectedEOF(Span),
|
||||
FromLexer(LexError),
|
||||
Expected(TKind, Span),
|
||||
Expected(TKind, TKind, Span),
|
||||
NotLiteral(TKind, Span),
|
||||
NotPattern(TKind, Span),
|
||||
NotType(TKind, Span),
|
||||
@@ -19,12 +23,16 @@ pub enum ParseError {
|
||||
NotPostfix(TKind, Span),
|
||||
}
|
||||
|
||||
pub use ParseError::EOF;
|
||||
|
||||
impl Error for ParseError {}
|
||||
impl Display for ParseError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::EOF(loc) => write!(f, "{loc}: Reached end of input."),
|
||||
Self::UnexpectedEOF(loc) => write!(f, "{loc}: Unexpected end of input."),
|
||||
Self::FromLexer(e) => e.fmt(f),
|
||||
Self::Expected(tk, loc) => write!(f, "{loc}: Expected {tk:?}."),
|
||||
Self::Expected(e, tk, loc) => write!(f, "{loc}: Expected {e:?}, got {tk:?}."),
|
||||
Self::NotLiteral(tk, loc) => write!(f, "{loc}: {tk:?} is not valid in a literal."),
|
||||
Self::NotPattern(tk, loc) => write!(f, "{loc}: {tk:?} is not valid in a pattern."),
|
||||
Self::NotType(tk, loc) => write!(f, "{loc}: {tk:?} is not valid in a type."),
|
||||
@@ -37,10 +45,36 @@ impl Display for ParseError {
|
||||
|
||||
pub type PResult<T> = Result<T, ParseError>;
|
||||
|
||||
trait PResultExt<T> {
|
||||
fn no_eof(self) -> PResult<T>;
|
||||
fn allow_eof(self) -> PResult<Option<T>>;
|
||||
}
|
||||
|
||||
impl<T> PResultExt<T> for PResult<T> {
|
||||
fn no_eof(self) -> Self {
|
||||
match self {
|
||||
Err(ParseError::EOF(span)) => Err(ParseError::UnexpectedEOF(span)),
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
fn allow_eof(self) -> PResult<Option<T>> {
|
||||
match self {
|
||||
Ok(t) => Ok(Some(t)),
|
||||
Err(ParseError::EOF(_)) => Ok(None),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Opens a scope where [ParseError::EOF] is unexpected (See [PResultExt::no_eof])
|
||||
fn no_eof<T>(f: impl FnOnce() -> PResult<T>) -> PResult<T> {
|
||||
f().no_eof()
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Parser<'t> {
|
||||
pub lexer: Lexer<'t>,
|
||||
pub next_tok: Option<Token>,
|
||||
pub next_tok: Option<PResult<Token>>,
|
||||
pub last_loc: Span,
|
||||
pub elide_do: bool,
|
||||
}
|
||||
@@ -72,46 +106,59 @@ impl<'t> Parser<'t> {
|
||||
None => loop {
|
||||
match self.lexer.scan() {
|
||||
Ok(Token { kind: TKind::Comment, .. }) => {}
|
||||
Ok(tok) => break tok,
|
||||
Err(e) => Err(ParseError::FromLexer(e))?,
|
||||
Ok(tok) => break Ok(tok),
|
||||
Err(LexError { pos, res: LexFailure::EOF }) => Err(ParseError::EOF(pos))?,
|
||||
Err(e) => break Err(ParseError::FromLexer(e)),
|
||||
}
|
||||
},
|
||||
};
|
||||
self.last_loc = next_tok.span;
|
||||
self.next_tok = Some(next_tok);
|
||||
Ok(self.next_tok.as_ref().expect("should have token"))
|
||||
|
||||
let next_tok = self.next_tok.as_ref().expect("should have Some lex result");
|
||||
|
||||
if let Ok(tok) = next_tok {
|
||||
self.last_loc = tok.span;
|
||||
}
|
||||
|
||||
next_tok.as_ref().map_err(|e| *e)
|
||||
}
|
||||
|
||||
/// Peeks the next token if it matches the `expected` [TKind]
|
||||
pub fn peek_if(&mut self, expected: TKind) -> Option<&Token> {
|
||||
self.peek().into_iter().find(|tok| tok.kind == expected)
|
||||
pub fn peek_if(&mut self, expected: TKind) -> PResult<Option<&Token>> {
|
||||
match self.peek() {
|
||||
Ok(tok) if tok.kind == expected => Ok(Some(tok)),
|
||||
Ok(_) => Ok(None),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes and returns the currently-peeked [Token].
|
||||
pub fn take(&mut self) -> Option<Token> {
|
||||
let tok = self.next_tok.take();
|
||||
self.elide_do = matches!(tok, Some(Token { kind: TKind::RCurly, .. }));
|
||||
pub fn take(&mut self) -> PResult<Token> {
|
||||
let tok = self
|
||||
.next_tok
|
||||
.take()
|
||||
.unwrap_or(Err(ParseError::UnexpectedEOF(self.last_loc)));
|
||||
self.elide_do = matches!(tok, Ok(Token { kind: TKind::RCurly | TKind::Semi, .. }));
|
||||
tok
|
||||
}
|
||||
|
||||
/// Consumes the currently-peeked [Token], returning its lexeme without cloning.
|
||||
pub fn take_lexeme(&mut self) -> Option<Lexeme> {
|
||||
pub fn take_lexeme(&mut self) -> PResult<Lexeme> {
|
||||
self.take().map(|tok| tok.lexeme)
|
||||
}
|
||||
|
||||
#[allow(clippy::should_implement_trait)]
|
||||
pub fn next(&mut self) -> PResult<Token> {
|
||||
self.peek()?;
|
||||
self.peek().no_eof()?;
|
||||
Ok(self.take().expect("should have token here"))
|
||||
}
|
||||
|
||||
/// Consumes and returns the next [Token] if it matches the `expected` [TKind]
|
||||
pub fn next_if(&mut self, expected: TKind) -> PResult<Token> {
|
||||
let token = self.peek()?;
|
||||
if token.kind == expected {
|
||||
Ok(self.take().expect("should have token here"))
|
||||
} else {
|
||||
Err(ParseError::Expected(expected, token.span))
|
||||
pub fn next_if(&mut self, expected: TKind) -> PResult<Result<Token, TKind>> {
|
||||
match self.peek() {
|
||||
Ok(t) if t.kind == expected => self.take().map(Ok),
|
||||
Ok(t) => Ok(Err(t.kind)),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,13 +174,15 @@ impl<'t> Parser<'t> {
|
||||
end: TKind,
|
||||
) -> PResult<Vec<P>> {
|
||||
// TODO: This loses lexer errors
|
||||
while self.peek_if(end).is_none() {
|
||||
elems.push(self.parse(level.clone())?);
|
||||
if self.next_if(sep).is_err() {
|
||||
break;
|
||||
}
|
||||
while self.peek_if(end).no_eof()?.is_none() {
|
||||
elems.push(self.parse(level.clone()).no_eof()?);
|
||||
match self.peek_if(sep)? {
|
||||
Some(_) => self.consume(),
|
||||
None => break,
|
||||
};
|
||||
}
|
||||
self.next_if(end)?;
|
||||
self.next_if(end)?
|
||||
.map_err(|tk| ParseError::Expected(end, tk, self.span()))?;
|
||||
Ok(elems)
|
||||
}
|
||||
|
||||
@@ -148,33 +197,37 @@ impl<'t> Parser<'t> {
|
||||
sep: TKind,
|
||||
) -> PResult<Vec<P>> {
|
||||
loop {
|
||||
elems.push(self.parse(level.clone())?);
|
||||
if self.next_if(sep).is_err() {
|
||||
break Ok(elems);
|
||||
}
|
||||
let elem = self.parse(level.clone()).no_eof()?;
|
||||
elems.push(elem);
|
||||
match self.peek_if(sep) {
|
||||
Ok(Some(_)) => self.consume(),
|
||||
Ok(None) | Err(ParseError::EOF(_)) => break Ok(elems),
|
||||
Err(e) => Err(e)?,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses into an [`Option<P>`] if the next token is `next`
|
||||
pub fn opt_if<P: Parse<'t>>(&mut self, level: P::Prec, next: TKind) -> PResult<Option<P>> {
|
||||
Ok(match self.next_if(next) {
|
||||
Ok(_) => Some(self.parse(level)?),
|
||||
Ok(match self.next_if(next)? {
|
||||
Ok(_) => Some(self.parse(level).no_eof()?),
|
||||
Err(_) => None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Parses a P unless the next token is `end`
|
||||
pub fn opt<P: Parse<'t>>(&mut self, level: P::Prec, end: TKind) -> PResult<Option<P>> {
|
||||
let out = match self.peek_if(end) {
|
||||
None => Some(self.parse(level)?),
|
||||
let out = match self.peek_if(end)? {
|
||||
None => Some(self.parse(level).no_eof()?),
|
||||
Some(_) => None,
|
||||
};
|
||||
self.next_if(end)?;
|
||||
self.expect(end)?;
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
pub fn consume_if(&mut self, next: TKind) -> PResult<&mut Self> {
|
||||
self.next_if(next)?;
|
||||
pub fn expect(&mut self, next: TKind) -> PResult<&mut Self> {
|
||||
self.next_if(next)?
|
||||
.map_err(|tk| ParseError::Expected(next, tk, self.span()))?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
@@ -197,17 +250,12 @@ impl<'t> Parse<'t> for FqPath {
|
||||
|
||||
fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult<Self> {
|
||||
let mut parts = vec![];
|
||||
if p.next_if(TKind::ColonColon).is_ok() {
|
||||
if p.next_if(TKind::ColonColon)?.is_ok() {
|
||||
parts.push("".into()); // the "root"
|
||||
}
|
||||
loop {
|
||||
parts.push(
|
||||
p.next_if(TKind::Identifier)?
|
||||
.lexeme
|
||||
.string()
|
||||
.expect("Identifier should have String"),
|
||||
);
|
||||
if p.next_if(TKind::ColonColon).is_err() {
|
||||
while let Ok(id) = p.next_if(TKind::Identifier)? {
|
||||
parts.push(id.lexeme.string().expect("Identifier should have String"));
|
||||
if let None | Some(Err(_)) = p.next_if(TKind::ColonColon).allow_eof()? {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -223,26 +271,19 @@ impl<'t> Parse<'t> for Literal {
|
||||
Ok(match tok.kind {
|
||||
TKind::True => p.consume().then(Literal::Bool(true)),
|
||||
TKind::False => p.consume().then(Literal::Bool(false)),
|
||||
TKind::Character => Literal::Char(
|
||||
p.take_lexeme()
|
||||
.expect("should have Token")
|
||||
.char()
|
||||
.expect("should have one char in char literal"),
|
||||
),
|
||||
TKind::Integer => {
|
||||
let Token { lexeme, span, .. } = p.take().expect("should have Token");
|
||||
let Lexeme::Integer(int, _) = lexeme else {
|
||||
Err(ParseError::Expected(TKind::Integer, span))?
|
||||
};
|
||||
Literal::Int(int)
|
||||
}
|
||||
TKind::String => Literal::Str({
|
||||
let Token { lexeme, span, .. } = p.take().expect("should have Token");
|
||||
lexeme
|
||||
.string()
|
||||
.ok_or(ParseError::Expected(TKind::String, span))?
|
||||
TKind::Character => Literal::Char({
|
||||
let Token { lexeme, .. } = p.take().expect("should have Token");
|
||||
lexeme.char().expect("char token should have char")
|
||||
}),
|
||||
_ => Err(ParseError::Expected(TKind::Integer, tok.span))?,
|
||||
TKind::Integer => Literal::Int({
|
||||
let Token { lexeme, .. } = p.take().expect("should have Token");
|
||||
lexeme.int().expect("integer token should have int")
|
||||
}),
|
||||
TKind::String => Literal::Str({
|
||||
let Token { lexeme, .. } = p.take().expect("should have Token");
|
||||
lexeme.string().expect("string token should have string")
|
||||
}),
|
||||
other => Err(ParseError::NotLiteral(other, tok.span))?,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -288,6 +329,7 @@ fn pat_from_infix(token: &Token) -> Option<(PatPs, PPrec)> {
|
||||
|
||||
impl<'t> Parse<'t> for Pat {
|
||||
type Prec = PPrec;
|
||||
|
||||
fn parse(p: &mut Parser<'t>, level: PPrec) -> PResult<Self> {
|
||||
let tok = p.peek()?;
|
||||
|
||||
@@ -315,12 +357,10 @@ impl<'t> Parse<'t> for Pat {
|
||||
.opt(PPrec::Alt, TKind::RCurly)?
|
||||
.unwrap_or_else(|| Box::new(Pat::Op(PatOp::Tuple, vec![]))),
|
||||
),
|
||||
Ok(_) | Err(ParseError::FromLexer(LexError { pos: _, res: "EOF" })) => {
|
||||
match path.parts.len() {
|
||||
1 => Self::Name(path.parts.pop().expect("name has 1 part")),
|
||||
_ => Self::Path(path),
|
||||
}
|
||||
}
|
||||
Ok(_) | Err(ParseError::EOF(_)) => match path.parts.len() {
|
||||
1 => Self::Name(path.parts.pop().expect("name has 1 part")),
|
||||
_ => Self::Path(path),
|
||||
},
|
||||
Err(e) => Err(e)?,
|
||||
}
|
||||
}
|
||||
@@ -329,21 +369,21 @@ impl<'t> Parse<'t> for Pat {
|
||||
TKind::DotDot => Pat::Op(
|
||||
PatOp::Rest,
|
||||
// Identifier in Rest position always becomes binder
|
||||
match p.consume().peek()?.kind {
|
||||
TKind::Identifier => vec![Pat::Name(
|
||||
match p.consume().peek().allow_eof()?.map(Token::kind) {
|
||||
Some(TKind::Identifier) => vec![Pat::Name(
|
||||
p.take_lexeme()
|
||||
.expect("should have lexeme")
|
||||
.string()
|
||||
.expect("should be string"),
|
||||
)],
|
||||
TKind::Grave | TKind::Integer | TKind::Character => vec![p.parse(level)?],
|
||||
Some(TKind::Grave | TKind::Integer | TKind::Character) => vec![p.parse(level)?],
|
||||
_ => vec![],
|
||||
},
|
||||
),
|
||||
TKind::DotDotEq => Pat::Op(
|
||||
PatOp::RangeIn,
|
||||
match p.consume().peek()?.kind {
|
||||
TKind::Grave | TKind::Integer | TKind::Character => vec![p.parse(level)?],
|
||||
match p.consume().peek().allow_eof()?.map(Token::kind) {
|
||||
Some(TKind::Grave | TKind::Integer | TKind::Character) => vec![p.parse(level)?],
|
||||
_ => vec![],
|
||||
},
|
||||
),
|
||||
@@ -360,14 +400,14 @@ impl<'t> Parse<'t> for Pat {
|
||||
_ => Err(ParseError::NotPattern(tok.kind, tok.span))?,
|
||||
};
|
||||
|
||||
while let Ok(tok) = p.peek()
|
||||
while let Ok(Some(tok)) = p.peek().allow_eof()
|
||||
&& let Some((op, prec)) = pat_from_infix(tok)
|
||||
&& level <= prec
|
||||
{
|
||||
let kind = tok.kind;
|
||||
head = match op {
|
||||
PatPs::Typed => Pat::Typed(head.into(), p.consume().parse(())?),
|
||||
PatPs::Op(op @ PatOp::RangeEx) => Pat::Op(
|
||||
PatPs::Op(op @ (PatOp::RangeEx | PatOp::RangeIn)) => Pat::Op(
|
||||
op,
|
||||
match p.consume().peek().map(|t| t.kind) {
|
||||
Ok(TKind::Integer | TKind::Character | TKind::Identifier) => {
|
||||
@@ -379,7 +419,6 @@ impl<'t> Parse<'t> for Pat {
|
||||
PatPs::Op(op) => Pat::Op(op, p.consume().list_bare(vec![head], prec.next(), kind)?),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(head)
|
||||
}
|
||||
}
|
||||
@@ -389,10 +428,11 @@ impl<'t> Parse<'t> for Ty {
|
||||
|
||||
fn parse(p: &mut Parser<'t>, level: Self::Prec) -> PResult<Self>
|
||||
where Self: Sized {
|
||||
let tok = p.peek()?;
|
||||
let &Token { kind, span, .. } = p.peek()?;
|
||||
|
||||
let head = match tok.kind {
|
||||
TKind::Identifier => match tok.lexeme.str() {
|
||||
// TODO: this is a kinda jank way of error reporting
|
||||
let head = match kind {
|
||||
TKind::Identifier => match p.peek()?.lexeme.str() {
|
||||
Some("_") => p.consume().then(Ty::Infer),
|
||||
_ => Ty::Named(p.parse(())?),
|
||||
},
|
||||
@@ -403,7 +443,7 @@ impl<'t> Parse<'t> for Ty {
|
||||
match p.next()? {
|
||||
Token { kind: TKind::Semi, .. } => {
|
||||
let ty = Ty::Array(ty, p.parse(Prec::Binary.next())?);
|
||||
p.next_if(TKind::RBrack)?;
|
||||
p.expect(TKind::RBrack)?;
|
||||
ty
|
||||
}
|
||||
Token { kind: TKind::RBrack, .. } => Ty::Slice(ty),
|
||||
@@ -411,30 +451,27 @@ impl<'t> Parse<'t> for Ty {
|
||||
}
|
||||
}
|
||||
TKind::Fn => {
|
||||
p.consume().consume_if(TKind::LParen)?;
|
||||
|
||||
let mut tys = p.list(vec![], (), TKind::Comma, TKind::RParen)?;
|
||||
tys.push(match p.next_if(TKind::Arrow) {
|
||||
Ok(_) => p.parse(())?,
|
||||
_ => Ty::Tuple(vec![]),
|
||||
});
|
||||
Ty::Fn(tys)
|
||||
}
|
||||
TKind::LParen => {
|
||||
let mut tys = p.consume().list(vec![], (), TKind::Comma, TKind::RParen)?;
|
||||
match p.next_if(TKind::Arrow) {
|
||||
Ok(_) => {
|
||||
tys.push(p.parse(())?);
|
||||
Ty::Fn(tys)
|
||||
}
|
||||
_ => Ty::Tuple(tys),
|
||||
p.consume();
|
||||
match p.parse(())? {
|
||||
Ty::Fn(args) => Ty::Fn(args),
|
||||
other @ Ty::Tuple(_) => Ty::Fn(vec![other, Ty::Tuple(vec![])]),
|
||||
other => Ty::Fn(vec![other, Ty::Tuple(vec![])]),
|
||||
}
|
||||
}
|
||||
_ => Err(ParseError::NotType(tok.kind, tok.span))?,
|
||||
TKind::LParen => {
|
||||
Ty::Tuple(p.consume().list(vec![], (), TKind::Comma, TKind::RParen)?)
|
||||
}
|
||||
_ => Err(ParseError::NotType(kind, span))?,
|
||||
};
|
||||
|
||||
Ok(match p.next_if(TKind::Arrow) {
|
||||
Ok(_) => Ty::Fn(vec![head, p.parse(())?]),
|
||||
Ok(match p.next_if(TKind::Arrow).allow_eof()? {
|
||||
Some(Ok(_)) => Ty::Fn(vec![
|
||||
match head {
|
||||
args @ Ty::Tuple(_) => args,
|
||||
arg => Ty::Tuple(vec![arg]),
|
||||
},
|
||||
p.parse(())?,
|
||||
]),
|
||||
_ => head,
|
||||
})
|
||||
}
|
||||
@@ -483,15 +520,18 @@ pub enum Prec {
|
||||
|
||||
impl Prec {
|
||||
pub const MIN: usize = Prec::Min.value();
|
||||
|
||||
pub const fn value(self) -> usize {
|
||||
self as usize * 2
|
||||
}
|
||||
|
||||
pub const fn prev(self) -> usize {
|
||||
match self {
|
||||
Self::Assign => self.value() + 1,
|
||||
_ => self.value(),
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn next(self) -> usize {
|
||||
match self {
|
||||
Self::Assign => self.value(),
|
||||
@@ -526,7 +566,7 @@ pub enum Ps {
|
||||
fn from_prefix(token: &Token) -> PResult<(Ps, Prec)> {
|
||||
Ok(match token.kind {
|
||||
TKind::Do => (Ps::Op(Op::Do), Prec::Do),
|
||||
TKind::Semi => (Ps::ExplicitDo, Prec::Do),
|
||||
TKind::Semi => (Ps::End, Prec::Body),
|
||||
|
||||
TKind::Identifier | TKind::ColonColon => (Ps::Id, Prec::Max),
|
||||
TKind::Grave => (Ps::Mid, Prec::Max),
|
||||
@@ -566,6 +606,7 @@ fn from_prefix(token: &Token) -> PResult<(Ps, Prec)> {
|
||||
TKind::Minus => (Ps::Op(Op::Neg), Prec::Unary),
|
||||
TKind::Plus => (Ps::Op(Op::Identity), Prec::Unary),
|
||||
TKind::Star => (Ps::Op(Op::Deref), Prec::Unary),
|
||||
TKind::Hash => (Ps::Op(Op::Meta), Prec::Unary),
|
||||
|
||||
kind => Err(ParseError::NotPrefix(kind, token.span))?,
|
||||
})
|
||||
@@ -574,18 +615,24 @@ fn from_prefix(token: &Token) -> PResult<(Ps, Prec)> {
|
||||
fn from_infix(token: &Token) -> PResult<(Ps, Prec)> {
|
||||
Ok(match token.kind {
|
||||
TKind::Semi => (Ps::Op(Op::Do), Prec::Do), // the inspiration
|
||||
TKind::As => (Ps::Op(Op::As), Prec::Max),
|
||||
TKind::Comma => (Ps::Op(Op::Tuple), Prec::Tuple),
|
||||
TKind::Dot => (Ps::Op(Op::Dot), Prec::Project),
|
||||
TKind::AmpAmp => (Ps::Op(Op::LogAnd), Prec::LogAnd),
|
||||
TKind::BarBar => (Ps::Op(Op::LogOr), Prec::LogOr),
|
||||
TKind::Question => (Ps::Op(Op::Try), Prec::Unary),
|
||||
TKind::LParen => (Ps::Op(Op::Call), Prec::Extend),
|
||||
TKind::LBrack => (Ps::Op(Op::Index), Prec::Extend),
|
||||
TKind::LCurly => (Ps::Make, Prec::Make),
|
||||
TKind::RParen | TKind::RBrack | TKind::RCurly => (Ps::End, Prec::Max),
|
||||
TKind::In => (Ps::Op(Op::Do), Prec::Do),
|
||||
|
||||
TKind::Eq => (Ps::Op(Op::Set), Prec::Assign),
|
||||
TKind::StarEq => (Ps::Op(Op::MulSet), Prec::Assign),
|
||||
TKind::SlashEq => (Ps::Op(Op::DivSet), Prec::Assign),
|
||||
TKind::RemEq => (Ps::Op(Op::RemSet), Prec::Assign),
|
||||
TKind::PlusEq => (Ps::Op(Op::AddSet), Prec::Assign),
|
||||
TKind::MinusEq => (Ps::Op(Op::SubSet), Prec::Assign),
|
||||
TKind::LtLtEq => (Ps::Op(Op::ShlSet), Prec::Assign),
|
||||
TKind::GtGtEq => (Ps::Op(Op::ShrSet), Prec::Assign),
|
||||
TKind::AmpEq => (Ps::Op(Op::AndSet), Prec::Assign),
|
||||
TKind::XorEq => (Ps::Op(Op::XorSet), Prec::Assign),
|
||||
TKind::BarEq => (Ps::Op(Op::OrSet), Prec::Assign),
|
||||
TKind::Comma => (Ps::Op(Op::Tuple), Prec::Tuple),
|
||||
TKind::LCurly => (Ps::Make, Prec::Make),
|
||||
TKind::XorXor => (Ps::Op(Op::LogXor), Prec::Logical),
|
||||
TKind::BarBar => (Ps::Op(Op::LogOr), Prec::LogOr),
|
||||
TKind::AmpAmp => (Ps::Op(Op::LogAnd), Prec::LogAnd),
|
||||
TKind::Lt => (Ps::Op(Op::Lt), Prec::Compare),
|
||||
TKind::LtEq => (Ps::Op(Op::Leq), Prec::Compare),
|
||||
TKind::EqEq => (Ps::Op(Op::Eq), Prec::Compare),
|
||||
@@ -605,6 +652,13 @@ fn from_infix(token: &Token) -> PResult<(Ps, Prec)> {
|
||||
TKind::Slash => (Ps::Op(Op::Div), Prec::Term),
|
||||
TKind::Rem => (Ps::Op(Op::Rem), Prec::Term),
|
||||
|
||||
TKind::Question => (Ps::Op(Op::Try), Prec::Unary),
|
||||
TKind::Dot => (Ps::Op(Op::Dot), Prec::Project),
|
||||
TKind::LParen => (Ps::Op(Op::Call), Prec::Extend),
|
||||
TKind::LBrack => (Ps::Op(Op::Index), Prec::Extend),
|
||||
|
||||
TKind::RParen | TKind::RBrack | TKind::RCurly => (Ps::End, Prec::Max),
|
||||
TKind::As => (Ps::Op(Op::As), Prec::Max),
|
||||
_ => (Ps::ImplicitDo, Prec::Do),
|
||||
})
|
||||
}
|
||||
@@ -615,7 +669,7 @@ impl<'t> Parse<'t> for Const {
|
||||
fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult<Self> {
|
||||
Ok(Self(
|
||||
p.consume().parse(PPrec::Tuple)?,
|
||||
p.consume_if(TKind::Eq)?.parse(Prec::Tuple.value())?,
|
||||
p.expect(TKind::Eq)?.parse(Prec::Tuple.value())?,
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -637,7 +691,7 @@ impl<'t> Parse<'t> for Fn {
|
||||
type Prec = ();
|
||||
|
||||
fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult<Self> {
|
||||
match p.consume().next_if(TKind::Identifier) {
|
||||
match p.consume().next_if(TKind::Identifier)? {
|
||||
Ok(Token { lexeme, .. }) => Ok(Self(
|
||||
lexeme.string(),
|
||||
p.parse(PPrec::Tuple)?,
|
||||
@@ -648,7 +702,7 @@ impl<'t> Parse<'t> for Fn {
|
||||
None,
|
||||
Pat::Op(
|
||||
PatOp::Tuple,
|
||||
p.consume_if(TKind::LParen)?.list(
|
||||
p.expect(TKind::LParen)?.list(
|
||||
vec![],
|
||||
PPrec::Tuple,
|
||||
TKind::Comma,
|
||||
@@ -667,12 +721,15 @@ impl<'t> Parse<'t> for Let {
|
||||
|
||||
fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult<Self> {
|
||||
let pat = p.consume().parse(PPrec::Tuple)?;
|
||||
if p.next_if(TKind::Eq).is_err() {
|
||||
if p.next_if(TKind::Eq).allow_eof()?.is_none_or(|v| v.is_err()) {
|
||||
return Ok(Self(pat, vec![]));
|
||||
}
|
||||
|
||||
let body = p.parse(Prec::Tuple.value())?;
|
||||
if p.next_if(TKind::Else).is_err() {
|
||||
if p.next_if(TKind::Else)
|
||||
.allow_eof()?
|
||||
.is_none_or(|v| v.is_err())
|
||||
{
|
||||
return Ok(Self(pat, vec![body]));
|
||||
}
|
||||
|
||||
@@ -685,42 +742,41 @@ impl<'t> Parse<'t> for Match {
|
||||
|
||||
fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult<Self> {
|
||||
Ok(Self(p.consume().parse(Prec::Logical.value())?, {
|
||||
p.next_if(TKind::LCurly)?;
|
||||
p.expect(TKind::LCurly)?;
|
||||
p.list(vec![], Prec::Body.next(), TKind::Comma, TKind::RCurly)?
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'t> Parse<'t> for MatchArm {
|
||||
type Prec = usize;
|
||||
|
||||
fn parse(p: &mut Parser<'t>, level: usize) -> PResult<Self> {
|
||||
p.next_if(TKind::Bar).ok();
|
||||
p.next_if(TKind::Bar)?.ok(); // and discard
|
||||
Ok(MatchArm(
|
||||
p.parse(PPrec::Min)?,
|
||||
p.consume_if(TKind::FatArrow)?.parse(level)?,
|
||||
p.expect(TKind::FatArrow)?.parse(level)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'t> Parse<'t> for MakeArm {
|
||||
type Prec = ();
|
||||
|
||||
fn parse(p: &mut Parser<'t>, _level: ()) -> PResult<Self> {
|
||||
let name = p
|
||||
.next_if(TKind::Identifier)?
|
||||
.map_err(|tk| ParseError::Expected(TKind::Identifier, tk, p.span()))?;
|
||||
Ok(MakeArm(
|
||||
p.next_if(TKind::Identifier)?
|
||||
.lexeme
|
||||
.string()
|
||||
.expect("Identifier should have String"),
|
||||
{
|
||||
p.next_if(TKind::Colon)
|
||||
.ok()
|
||||
.map(|_| p.parse(Prec::Body.value()))
|
||||
.transpose()?
|
||||
},
|
||||
name.lexeme.string().expect("Identifier should have String"),
|
||||
p.opt_if(Prec::Body.value(), TKind::Colon)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'t> Parse<'t> for Mod {
|
||||
type Prec = ();
|
||||
|
||||
fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult<Self> {
|
||||
let ty = p.consume().parse(())?;
|
||||
let body = p.parse(Prec::Body.value())?;
|
||||
@@ -732,14 +788,14 @@ fn parse_for<'t>(p: &mut Parser<'t>, _level: ()) -> PResult<Expr> {
|
||||
// for Pat
|
||||
let pat = p.consume().parse(PPrec::Tuple)?;
|
||||
// in Expr
|
||||
let iter: Anno<Expr> = p.consume_if(TKind::In)?.parse(Prec::Logical.next())?;
|
||||
let iter: Anno<Expr> = p.expect(TKind::In)?.parse(Prec::Logical.next())?;
|
||||
let cspan = iter.1;
|
||||
// Expr
|
||||
let pass: Anno<Expr> = p.parse(Prec::Body.next())?;
|
||||
let pspan = pass.1;
|
||||
// else Expr?
|
||||
let fail = match p.next_if(TKind::Else) {
|
||||
Ok(_) => p.parse(Prec::Body.next())?,
|
||||
let fail = match p.next_if(TKind::Else).allow_eof()? {
|
||||
Some(Ok(_)) => p.parse(Prec::Body.next())?,
|
||||
_ => Expr::Op(Op::Tuple, vec![]).anno(pspan),
|
||||
};
|
||||
let fspan = fail.1;
|
||||
@@ -834,125 +890,143 @@ impl<'t> Parse<'t> for Expr {
|
||||
fn parse(p: &mut Parser<'t>, level: usize) -> PResult<Self> {
|
||||
const MIN: usize = Prec::MIN;
|
||||
|
||||
// TODO: in-tree doc comments
|
||||
while p.next_if(TKind::Doc)?.is_ok() {}
|
||||
|
||||
// Prefix
|
||||
let tok = p.peek()?;
|
||||
let ((op, prec), span) = (from_prefix(tok)?, tok.span);
|
||||
let tok @ &Token { kind, span, .. } = p.peek()?;
|
||||
let ((op, prec), span) = (from_prefix(tok)?, span);
|
||||
no_eof(move || {
|
||||
let mut head = match op {
|
||||
// "End" is produced when an "empty" expression is syntactically required.
|
||||
// This happens when a semi or closing delimiter begins an expression.
|
||||
// The token which emitted "End" cannot be consumed, as it is expected elsewhere.
|
||||
Ps::End if level <= prec.next() => Expr::Op(Op::Tuple, vec![]),
|
||||
Ps::End => Err(ParseError::NotPrefix(kind, span))?,
|
||||
|
||||
let mut head = match op {
|
||||
// Empty is returned when a block finisher is an expr prefix.
|
||||
// It's the only expr that doesn't consume.
|
||||
Ps::End if level == prec.next() => Expr::Op(Op::Tuple, vec![]),
|
||||
Ps::End => Err(ParseError::NotPrefix(tok.kind, span))?,
|
||||
|
||||
Ps::ExplicitDo => {
|
||||
p.consume();
|
||||
Expr::Op(Op::Tuple, vec![])
|
||||
}
|
||||
|
||||
Ps::Id => Expr::Id(p.parse(())?),
|
||||
Ps::Mid => Expr::MetId(p.consume().next()?.lexeme.to_string()),
|
||||
Ps::Lit => Expr::Lit(p.parse(())?),
|
||||
Ps::Let => Expr::Let(p.parse(())?),
|
||||
Ps::For => parse_for(p, ())?,
|
||||
Ps::Const => Expr::Const(p.parse(())?),
|
||||
Ps::Typedef => Expr::Struct(p.parse(())?),
|
||||
Ps::Match => Expr::Match(p.parse(())?),
|
||||
Ps::Mod => Expr::Mod(p.parse(())?),
|
||||
Ps::Op(Op::Block) => Expr::Op(
|
||||
Op::Block,
|
||||
p.consume().opt(MIN, TKind::RCurly)?.into_iter().collect(),
|
||||
),
|
||||
Ps::Op(Op::Array) => parse_array(p)?,
|
||||
Ps::Op(Op::Group) => match p.consume().opt(MIN, TKind::RParen)? {
|
||||
Some(value) => Expr::Op(Op::Group, vec![value]),
|
||||
None => Expr::Op(Op::Tuple, vec![]),
|
||||
},
|
||||
Ps::Op(op @ (Op::If | Op::While)) => {
|
||||
p.consume();
|
||||
let exprs = vec![
|
||||
// conditional restricted to Logical operators or above
|
||||
p.parse(Prec::Logical.value())?,
|
||||
p.parse(prec.next())?,
|
||||
match p.peek() {
|
||||
Ok(Token { kind: TKind::Else, .. }) => p.consume().parse(prec.next())?,
|
||||
_ => Expr::Op(Op::Tuple, vec![]).anno(span.merge(p.span())),
|
||||
},
|
||||
];
|
||||
Expr::Op(op, exprs)
|
||||
}
|
||||
Ps::Fn => Expr::Fn(p.parse(())?),
|
||||
Ps::Lambda => Expr::Fn(Box::new(Fn(
|
||||
None,
|
||||
p.consume()
|
||||
.opt(PPrec::Tuple, TKind::Bar)?
|
||||
.unwrap_or(Pat::Op(PatOp::Tuple, vec![])),
|
||||
p.opt_if((), TKind::Arrow)?.unwrap_or(Ty::Infer),
|
||||
p.parse(Prec::Body.next())?,
|
||||
))),
|
||||
Ps::Lambda0 => Expr::Fn(Box::new(Fn(
|
||||
None,
|
||||
Pat::Op(PatOp::Tuple, vec![]),
|
||||
p.consume().opt_if((), TKind::Arrow)?.unwrap_or(Ty::Infer),
|
||||
p.parse(Prec::Body.next())?,
|
||||
))),
|
||||
Ps::DoubleRef => p.consume().parse(prec.next()).map(|Anno(expr, span)| {
|
||||
Expr::Op(
|
||||
Op::Refer,
|
||||
vec![Anno(Expr::Op(Op::Refer, vec![Anno(expr, span)]), span)],
|
||||
)
|
||||
})?,
|
||||
|
||||
Ps::Op(op) => Expr::Op(op, vec![p.consume().parse(prec.next())?]),
|
||||
_ => unimplemented!("prefix {op:?}"),
|
||||
};
|
||||
|
||||
// Infix and Postfix
|
||||
while let Ok(tok) = p.peek()
|
||||
&& let Ok((op, prec)) = from_infix(tok)
|
||||
&& level <= prec.prev()
|
||||
&& op != Ps::End
|
||||
{
|
||||
let kind = tok.kind;
|
||||
let span = span.merge(p.span());
|
||||
|
||||
head = match op {
|
||||
// Make (structor expressions) are context-sensitive
|
||||
Ps::Make => match &head {
|
||||
Expr::Id(_) | Expr::MetId(_) => Expr::Make(Box::new(Make(
|
||||
head.anno(span),
|
||||
p.consume().list(vec![], (), TKind::Comma, TKind::RCurly)?,
|
||||
))),
|
||||
_ => break,
|
||||
Ps::Id => Expr::Id(p.parse(())?),
|
||||
Ps::Mid => Expr::MetId(p.consume().next()?.lexeme.to_string()),
|
||||
Ps::Lit => Expr::Lit(p.parse(())?),
|
||||
Ps::Let => Expr::Let(p.parse(())?),
|
||||
Ps::For => parse_for(p, ())?,
|
||||
Ps::Const => Expr::Const(p.parse(())?),
|
||||
Ps::Typedef => Expr::Struct(p.parse(())?),
|
||||
Ps::Match => Expr::Match(p.parse(())?),
|
||||
Ps::Mod => Expr::Mod(p.parse(())?),
|
||||
Ps::Op(Op::Meta) => Expr::Op(
|
||||
Op::Meta,
|
||||
vec![
|
||||
p.consume()
|
||||
.expect(TKind::LBrack)?
|
||||
.opt(MIN, TKind::RBrack)?
|
||||
.unwrap_or(Expr::Op(Op::Tuple, vec![]).anno(span)),
|
||||
p.parse(level)?,
|
||||
],
|
||||
),
|
||||
Ps::Op(Op::Block) => Expr::Op(
|
||||
Op::Block,
|
||||
p.consume().opt(MIN, TKind::RCurly)?.into_iter().collect(),
|
||||
),
|
||||
Ps::Op(Op::Array) => parse_array(p)?,
|
||||
Ps::Op(Op::Group) => match p.consume().opt(MIN, TKind::RParen)? {
|
||||
Some(value) => Expr::Op(Op::Group, vec![value]),
|
||||
None => Expr::Op(Op::Tuple, vec![]),
|
||||
},
|
||||
// As is ImplicitDo (semicolon elision)
|
||||
Ps::ImplicitDo if p.elide_do => head.and_do(span, p.parse(prec.next())?),
|
||||
Ps::ImplicitDo => break,
|
||||
Ps::Op(Op::Do) => head.and_do(span, p.consume().parse(prec.next())?),
|
||||
Ps::Op(Op::Index) => Expr::Op(
|
||||
Op::Index,
|
||||
p.consume()
|
||||
.list(vec![head.anno(span)], 0, TKind::Comma, TKind::RBrack)?,
|
||||
),
|
||||
Ps::Op(Op::Call) => Expr::Op(
|
||||
Op::Call,
|
||||
p.consume()
|
||||
.list(vec![head.anno(span)], 0, TKind::Comma, TKind::RParen)?,
|
||||
),
|
||||
Ps::Op(op @ (Op::Tuple | Op::Dot | Op::LogAnd | Op::LogOr)) => Expr::Op(
|
||||
op,
|
||||
p.consume()
|
||||
.list_bare(vec![head.anno(span)], prec.next(), kind)?,
|
||||
),
|
||||
Ps::Op(op @ Op::Try) => {
|
||||
Ps::Op(op @ (Op::If | Op::While)) => {
|
||||
p.consume();
|
||||
Expr::Op(op, vec![head.anno(span)])
|
||||
let exprs = vec![
|
||||
// conditional restricted to Logical operators or above
|
||||
p.parse(Prec::Logical.value())?,
|
||||
p.parse(prec.next())?,
|
||||
match p.peek() {
|
||||
Ok(Token { kind: TKind::Else, .. }) => {
|
||||
p.consume().parse(prec.next())?
|
||||
}
|
||||
_ => Expr::Op(Op::Tuple, vec![]).anno(span.merge(p.span())),
|
||||
},
|
||||
];
|
||||
Expr::Op(op, exprs)
|
||||
}
|
||||
Ps::Op(op) => Expr::Op(op, vec![head.anno(span), p.consume().parse(prec.next())?]),
|
||||
_ => Err(ParseError::NotInfix(kind, span))?,
|
||||
}
|
||||
}
|
||||
Ps::Fn => Expr::Fn(p.parse(())?),
|
||||
Ps::Lambda => Expr::Fn(Box::new(Fn(
|
||||
None,
|
||||
p.consume()
|
||||
.opt(PPrec::Tuple, TKind::Bar)?
|
||||
.unwrap_or(Pat::Op(PatOp::Tuple, vec![])),
|
||||
p.opt_if((), TKind::Arrow)?.unwrap_or(Ty::Infer),
|
||||
p.parse(Prec::Body.next())?,
|
||||
))),
|
||||
Ps::Lambda0 => Expr::Fn(Box::new(Fn(
|
||||
None,
|
||||
Pat::Op(PatOp::Tuple, vec![]),
|
||||
p.consume().opt_if((), TKind::Arrow)?.unwrap_or(Ty::Infer),
|
||||
p.parse(Prec::Body.next())?,
|
||||
))),
|
||||
Ps::DoubleRef => p.consume().parse(prec.next()).map(|Anno(expr, span)| {
|
||||
Expr::Op(
|
||||
Op::Refer,
|
||||
vec![Anno(Expr::Op(Op::Refer, vec![Anno(expr, span)]), span)],
|
||||
)
|
||||
})?,
|
||||
|
||||
Ok(head)
|
||||
Ps::Op(op) => Expr::Op(op, vec![p.consume().parse(prec.next())?]),
|
||||
_ => unimplemented!("prefix {op:?}"),
|
||||
};
|
||||
|
||||
// Infix and Postfix
|
||||
while let Ok(Some(tok)) = p.peek().allow_eof()
|
||||
&& let Ok((op, prec)) = from_infix(tok)
|
||||
&& level <= prec.prev()
|
||||
&& op != Ps::End
|
||||
{
|
||||
let kind = tok.kind;
|
||||
let span = span.merge(p.span());
|
||||
|
||||
head = match op {
|
||||
// Make (structor expressions) are context-sensitive
|
||||
Ps::Make => match &head {
|
||||
Expr::Id(_) | Expr::MetId(_) => Expr::Make(Box::new(Make(
|
||||
head.anno(span),
|
||||
p.consume().list(vec![], (), TKind::Comma, TKind::RCurly)?,
|
||||
))),
|
||||
_ => break,
|
||||
},
|
||||
// As is ImplicitDo (semicolon elision)
|
||||
Ps::ImplicitDo if p.elide_do => head.and_do(span, p.parse(prec.next())?),
|
||||
Ps::ImplicitDo => break,
|
||||
Ps::Op(Op::Do) => head.and_do(span, p.consume().parse(prec.next())?),
|
||||
Ps::Op(Op::Index) => Expr::Op(
|
||||
Op::Index,
|
||||
p.consume()
|
||||
.list(vec![head.anno(span)], 0, TKind::Comma, TKind::RBrack)?,
|
||||
),
|
||||
Ps::Op(Op::Call) => Expr::Op(
|
||||
Op::Call,
|
||||
vec![
|
||||
head.anno(span),
|
||||
p.consume()
|
||||
.opt(0, TKind::RParen)?
|
||||
.unwrap_or(Expr::Op(Op::Tuple, vec![]).anno(span)),
|
||||
],
|
||||
),
|
||||
Ps::Op(op @ (Op::Tuple | Op::Dot | Op::LogAnd | Op::LogOr)) => Expr::Op(
|
||||
op,
|
||||
p.consume()
|
||||
.list_bare(vec![head.anno(span)], prec.next(), kind)?,
|
||||
),
|
||||
Ps::Op(op @ Op::Try) => {
|
||||
p.consume();
|
||||
Expr::Op(op, vec![head.anno(span)])
|
||||
}
|
||||
Ps::Op(op) => {
|
||||
Expr::Op(op, vec![head.anno(span), p.consume().parse(prec.next())?])
|
||||
}
|
||||
_ => Err(ParseError::NotInfix(kind, span))?,
|
||||
}
|
||||
}
|
||||
|
||||
Ok(head)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -966,7 +1040,7 @@ fn parse_array<'t>(p: &mut Parser<'t>) -> PResult<Expr> {
|
||||
let prec = Prec::Tuple;
|
||||
let item = p.parse(prec.value())?;
|
||||
let repeat = p.opt_if(prec.next(), TKind::Semi)?;
|
||||
p.next_if(TKind::RBrack)?;
|
||||
p.expect(TKind::RBrack)?;
|
||||
|
||||
Ok(match (repeat, item) {
|
||||
(Some(repeat), item) => Expr::Op(Op::ArRep, vec![item, repeat]),
|
||||
|
||||
Reference in New Issue
Block a user