use indexmap::IndexSet;
use rustc_hash::{FxHashMap, FxHashSet};
use std::str::from_utf8;
#[cfg(feature = "logging")]
use log::*;
use crate::ast::AST;
use crate::cst::syntax_stream::SyntaxStream;
use crate::cst::SyntaxKind::*;
use crate::cst::{syntax_stream, CST};
use crate::cst::{CSTStream, Event, SyntaxKind};
use crate::parser::token_stream::TokenStream;
use crate::tokenizer::{Token, TokenId, Tokenizer};
use crate::Span;
mod token_stream;
#[cfg(test)]
mod tests;
pub struct Parser<'src> {
pub(crate) parser: ParserImpl<'src>,
}
impl<'src> Parser<'src> {
pub fn new(source: &'src [u8]) -> Self {
Self { parser: ParserImpl::from(Tokenizer::new(source)) }
}
#[inline]
pub fn source(&self) -> &'src [u8] {
self.parser.tokens.source()
}
#[inline]
pub fn into_ast(self) -> AST<'src> {
AST::from(self)
}
#[inline]
#[doc(hidden)]
pub fn into_cst(self) -> CST {
CST::from(self)
}
#[inline]
pub fn into_cst_stream(self) -> CSTStream<'src> {
CSTStream::from(self)
}
}
enum ParserState {
StartOfInput,
EndOfInput,
OK,
Failure,
}
pub(crate) struct ParserImpl<'src> {
tokens: TokenStream<'src>,
output: SyntaxStream,
state: ParserState,
opt_depth: usize,
not_depth: usize,
#[cfg(feature = "logging")]
depth: usize,
expected_token_errors: FxHashMap<Span, (TokenId, IndexSet<&'static str>)>,
unexpected_token_errors: FxHashSet<Span>,
pending_errors: Vec<(Span, String)>,
cache: FxHashSet<(usize, SyntaxKind)>,
}
impl<'src> From<Tokenizer<'src>> for ParserImpl<'src> {
fn from(tokenizer: Tokenizer<'src>) -> Self {
Self {
tokens: TokenStream::new(tokenizer),
output: SyntaxStream::new(),
pending_errors: Vec::new(),
expected_token_errors: FxHashMap::default(),
unexpected_token_errors: FxHashSet::default(),
cache: FxHashSet::default(),
opt_depth: 0,
not_depth: 0,
#[cfg(feature = "logging")]
depth: 0,
state: ParserState::StartOfInput,
}
}
}
impl Iterator for ParserImpl<'_> {
type Item = Event;
fn next(&mut self) -> Option<Self::Item> {
match self.state {
ParserState::StartOfInput => {
self.state = ParserState::OK;
Some(Event::Begin(SOURCE_FILE))
}
ParserState::EndOfInput => None,
_ => {
if let Some(token) = self.output.pop() {
return Some(token);
}
if self.tokens.has_more() {
let _ = self.trivia();
let _ = self.top_level_item();
self.flush_errors();
self.cache.clear();
self.state = ParserState::OK;
}
if let Some(token) = self.output.pop() {
Some(token)
} else {
self.state = ParserState::EndOfInput;
Some(Event::End(SOURCE_FILE))
}
}
}
}
}
impl<'src> ParserImpl<'src> {
fn peek(&mut self) -> Option<&Token> {
self.tokens.peek_token(0)
}
fn peek_non_trivia(&mut self) -> Option<&Token> {
let mut i = 0;
let token_pos = loop {
match self.tokens.peek_token(i) {
Some(token) => {
if token.is_trivia() {
i += 1;
} else {
break i;
}
}
None => return None,
}
};
self.tokens.peek_token(token_pos)
}
fn bump(&mut self) -> Option<Token> {
let token = self.tokens.next_token();
match &token {
Some(token) => self.output.push_token(token.into(), token.span()),
None => {}
}
token
}
fn bookmark(&mut self) -> Bookmark {
Bookmark {
tokens: self.tokens.bookmark(),
output: self.output.bookmark(),
}
}
fn restore_bookmark(&mut self, bookmark: &Bookmark) {
self.tokens.restore_bookmark(&bookmark.tokens);
self.output.truncate(&bookmark.output);
}
fn remove_bookmark(&mut self, bookmark: Bookmark) {
self.tokens.remove_bookmark(bookmark.tokens);
self.output.remove_bookmark(bookmark.output);
}
fn enter_hex_pattern_mode(&mut self) -> &mut Self {
if matches!(self.state, ParserState::Failure) {
return self;
}
self.tokens.enter_hex_pattern_mode();
self
}
fn enter_hex_jump_mode(&mut self) -> &mut Self {
if matches!(self.state, ParserState::Failure) {
return self;
}
self.tokens.enter_hex_jump_mode();
self
}
fn begin(&mut self, kind: SyntaxKind) -> &mut Self {
self.trivia();
#[cfg(feature = "logging")]
{
debug!(
"{}{:?} -- next token: {}",
" ".repeat(self.depth),
kind,
self.tokens
.peek_token(0)
.map(|t| format!("{:?}", t))
.unwrap_or_default()
);
self.depth += 1;
}
self.output.begin(kind);
self
}
fn end(&mut self) -> &mut Self {
#[cfg(feature = "logging")]
{
self.depth -= 1;
}
if matches!(self.state, ParserState::Failure) {
self.output.end_with_error();
} else {
self.output.end();
}
self
}
fn end_with_recovery(
&mut self,
recovery_set: &'static TokenSet,
) -> &mut Self {
if let Some(token) = self.peek_non_trivia() {
if recovery_set.contains(token).is_some() {
self.end();
self.recover();
return self;
} else {
let token_span = token.span();
let token_id = token.id();
self.trivia();
self.bump();
self.state = ParserState::Failure;
if self.pending_errors.is_empty() {
let (actual_token_id, expected) = self
.expected_token_errors
.entry(token_span)
.or_default();
*actual_token_id = token_id;
expected.extend(
recovery_set
.token_ids()
.map(|token| token.description()),
);
self.handle_errors();
} else {
self.flush_errors();
}
}
}
while let Some(token) = self.peek_non_trivia() {
if recovery_set.contains(token).is_some() {
break;
} else {
self.trivia();
self.bump();
}
}
self.end();
self.recover();
self
}
fn recover(&mut self) -> &mut Self {
self.state = ParserState::OK;
self
}
fn trivia(&mut self) -> &mut Self {
if matches!(self.state, ParserState::Failure) {
return self;
}
while let Some(token) = self.peek() {
if token.is_trivia() {
self.bump();
} else {
break;
}
}
self
}
fn expect(&mut self, expected_tokens: &'static TokenSet) -> &mut Self {
self.expect_d(expected_tokens, None)
}
fn expect_d(
&mut self,
expected_tokens: &'static TokenSet,
description: Option<&'static str>,
) -> &mut Self {
debug_assert!(!expected_tokens.is_empty());
if matches!(self.state, ParserState::Failure) {
return self;
}
let (token_id, token_match, token_span) = match self.peek_non_trivia()
{
None => {
let last = self.tokens.source().len().saturating_sub(1) as u32;
(None, None, Span(last..last))
}
Some(token) => (
Some(token.id()),
expected_tokens.contains(token),
token.span(),
),
};
match (self.not_depth, token_match) {
(not_depth, Some(_)) if not_depth > 0 => {
self.unexpected_token_errors.insert(token_span);
self.handle_errors()
}
(0, None) => {
let (actual_token_id, expected) =
self.expected_token_errors.entry(token_span).or_default();
*actual_token_id = token_id.unwrap_or(TokenId::UNKNOWN);
if let Some(description) = description {
expected.insert(description);
} else {
expected.extend(
expected_tokens
.token_ids()
.map(|token| token.description()),
);
}
self.handle_errors();
}
_ => {}
}
if let Some(t) = token_match {
self.trivia();
let token = self.tokens.next_token().unwrap();
self.output.push_token(*t, token.span());
if self.opt_depth == 0 {
self.flush_errors()
}
} else {
self.state = ParserState::Failure;
}
self
}
fn begin_alt(&mut self) -> Alt<'_, 'src> {
let bookmark = self.bookmark();
Alt { parser: self, matched: false, bookmark }
}
fn opt<P>(&mut self, parser: P) -> &mut Self
where
P: Fn(&mut Self) -> &mut Self,
{
if matches!(self.state, ParserState::Failure) {
return self;
}
let bookmark = self.bookmark();
self.trivia();
self.opt_depth += 1;
parser(self);
self.opt_depth -= 1;
if matches!(self.state, ParserState::Failure) {
self.recover();
self.restore_bookmark(&bookmark);
}
self.remove_bookmark(bookmark);
self
}
fn not<P>(&mut self, parser: P) -> &mut Self
where
P: Fn(&mut Self) -> &mut Self,
{
if matches!(self.state, ParserState::Failure) {
return self;
}
let bookmark = self.bookmark();
self.trivia();
self.not_depth += 1;
parser(self);
self.not_depth -= 1;
self.state = match self.state {
ParserState::OK => ParserState::Failure,
ParserState::Failure => ParserState::OK,
_ => unreachable!(),
};
self.restore_bookmark(&bookmark);
self.remove_bookmark(bookmark);
self
}
fn opt_expect(&mut self, expected_tokens: &'static TokenSet) -> &mut Self {
self.opt(|p| p.expect(expected_tokens))
}
fn if_next<P>(
&mut self,
expected_tokens: &'static TokenSet,
parser: P,
) -> &mut Self
where
P: Fn(&mut Self) -> &mut Self,
{
if matches!(self.state, ParserState::Failure) {
return self;
}
match self.peek_non_trivia() {
None => {}
Some(token) => {
if expected_tokens.contains(token).is_some() {
self.trivia();
parser(self);
} else {
let token_span = token.span();
let token_id = token.id();
let (actual_token, expected) = self
.expected_token_errors
.entry(token_span)
.or_default();
*actual_token = token_id;
expected.extend(
expected_tokens
.token_ids()
.map(|token| token.description()),
);
}
}
}
self
}
fn cond<P>(
&mut self,
expected_tokens: &'static TokenSet,
parser: P,
) -> &mut Self
where
P: Fn(&mut Self) -> &mut Self,
{
self.if_next(expected_tokens, |p| {
p.expect(expected_tokens).then(|p| parser(p))
});
self
}
#[inline]
fn zero_or_more<P>(&mut self, parser: P) -> &mut Self
where
P: Fn(&mut Self) -> &mut Self,
{
self.n_or_more(0, parser)
}
#[inline]
fn one_or_more<P>(&mut self, parser: P) -> &mut Self
where
P: Fn(&mut Self) -> &mut Self,
{
self.n_or_more(1, parser)
}
fn n_or_more<P>(&mut self, n: usize, parser: P) -> &mut Self
where
P: Fn(&mut Self) -> &mut Self,
{
if matches!(self.state, ParserState::Failure) {
return self;
}
for _ in 0..n {
self.trivia();
parser(self);
if matches!(self.state, ParserState::Failure) {
return self;
}
}
loop {
let bookmark = self.bookmark();
self.trivia();
self.opt_depth += 1;
parser(self);
self.opt_depth -= 1;
if matches!(self.state, ParserState::Failure) {
self.recover();
self.restore_bookmark(&bookmark);
self.remove_bookmark(bookmark);
break;
} else {
self.remove_bookmark(bookmark);
}
}
self
}
fn then<P>(&mut self, parser: P) -> &mut Self
where
P: Fn(&mut Self) -> &mut Self,
{
if matches!(self.state, ParserState::Failure) {
return self;
}
self.trivia();
parser(self);
self
}
fn cached<P>(&mut self, kind: SyntaxKind, parser: P) -> &mut Self
where
P: Fn(&mut Self) -> &mut Self,
{
let start_index = self.tokens.current_token_index();
if self.cache.contains(&(start_index, kind)) {
self.state = ParserState::Failure;
return self;
}
parser(self);
if matches!(self.state, ParserState::Failure) {
self.cache.insert((start_index, kind));
}
self
}
fn flush_errors(&mut self) {
self.expected_token_errors.clear();
self.unexpected_token_errors.clear();
for (span, error) in self.pending_errors.drain(0..) {
self.output.push_error(error, span);
}
}
fn handle_errors(&mut self) {
if self.opt_depth > 0 {
return;
}
let expected_token = self
.expected_token_errors
.drain()
.max_by_key(|(span, _)| span.start());
let unexpected_token = self
.unexpected_token_errors
.drain()
.max_by_key(|span| span.start());
let (span, expected) = match (expected_token, unexpected_token) {
(Some((e, _)), Some(u)) if u.start() > e.start() => (u, None),
(None, Some(u)) => (u, None),
(Some((e, expected)), _) => (e, Some(expected)),
(None, None) => return,
};
if self
.pending_errors
.iter()
.any(|(error_span, _)| error_span.eq(&span))
{
return;
}
let error_msg = match from_utf8(&self.tokens.source()[span.range()]) {
Ok(actual_token) => {
if let Some((actual_token_id, expected)) = expected {
if actual_token_id == TokenId::UNKNOWN
&& actual_token.starts_with("/*")
{
"unclosed comment".to_string()
}
else if actual_token_id == TokenId::UNKNOWN
&& actual_token.starts_with('"')
{
"unclosed literal string".to_string()
}
else if actual_token_id == TokenId::UNKNOWN
&& actual_token.starts_with('/')
{
"unclosed regular expression".to_string()
} else {
let (last, all_except_last) =
expected.as_slice().split_last().unwrap();
match (actual_token.len(), all_except_last.len()) {
(0, 0) => {
format!("expecting {last}, found end of file")
}
(l, 0) if l > 15 => format!("expecting {last}"),
(_, 0) => {
format!("expecting {last}, found `{actual_token}`")
}
(0, _) => {
format!(
"expecting {} or {last}, found end of file",
itertools::join(all_except_last.iter(), ", "),
)
}
(l, _) if l > 15 => format!(
"expecting {} or {last}",
itertools::join(all_except_last.iter(), ", ")
),
(_, _) => format!(
"expecting {} or {last}, found `{actual_token}`",
itertools::join(all_except_last.iter(), ", "),
),
}
}
} else if actual_token.is_empty() {
"unexpected end of file".to_string()
} else {
format!("unexpected `{actual_token}`")
}
}
Err(_) => "invalid UTF-8 character".to_string(),
};
self.pending_errors.push((span, error_msg));
}
}
macro_rules! t {
($( $tokens:path )|*) => {
&TokenSet(&[$( $tokens ),*])
};
}
impl<'src> ParserImpl<'src> {
fn top_level_item(&mut self) -> &mut Self {
let token = match self.peek() {
Some(token) => token,
None => {
self.state = ParserState::Failure;
return self;
}
};
match token {
Token::IMPORT_KW(_) => self.import_stmt(),
Token::GLOBAL_KW(_) | Token::PRIVATE_KW(_) | Token::RULE_KW(_) => {
self.rule_decl()
}
token => {
let span = token.span();
self.output.push_error(
"expecting import statement or rule definition",
span,
);
self.output.begin(ERROR);
while let Some(token) = self.peek_non_trivia() {
if matches!(
token,
Token::GLOBAL_KW(_)
| Token::PRIVATE_KW(_)
| Token::RULE_KW(_)
) {
break;
}
self.trivia();
self.bump();
}
self.output.end();
self.state = ParserState::Failure;
self
}
}
}
fn import_stmt(&mut self) -> &mut Self {
self.begin(IMPORT_STMT)
.expect(t!(IMPORT_KW))
.expect(t!(STRING_LIT))
.end()
}
fn rule_decl(&mut self) -> &mut Self {
self.begin(RULE_DECL)
.opt(|p| p.rule_mods())
.expect(t!(RULE_KW))
.expect(t!(IDENT))
.if_next(t!(COLON), |p| p.rule_tags())
.expect(t!(L_BRACE))
.if_next(t!(META_KW), |p| p.meta_blk())
.if_next(t!(STRINGS_KW), |p| p.patterns_blk())
.then(|p| p.condition_blk())
.expect(t!(R_BRACE))
.end_with_recovery(t!(GLOBAL_KW
| PRIVATE_KW
| RULE_KW
| IMPORT_KW))
}
fn rule_mods(&mut self) -> &mut Self {
self.begin(RULE_MODS)
.begin_alt()
.alt(|p| p.expect(t!(PRIVATE_KW)).opt_expect(t!(GLOBAL_KW)))
.alt(|p| p.expect(t!(GLOBAL_KW)).opt_expect(t!(PRIVATE_KW)))
.end_alt()
.end()
}
fn rule_tags(&mut self) -> &mut Self {
self.begin(RULE_TAGS)
.expect(t!(COLON))
.one_or_more(|p| p.expect(t!(IDENT)))
.end_with_recovery(t!(L_BRACE))
}
fn meta_blk(&mut self) -> &mut Self {
self.begin(META_BLK)
.expect(t!(META_KW))
.expect(t!(COLON))
.one_or_more(|p| p.meta_def())
.end_with_recovery(t!(STRINGS_KW | CONDITION_KW))
}
fn meta_def(&mut self) -> &mut Self {
self.begin(META_DEF)
.expect(t!(IDENT))
.expect(t!(EQUAL))
.begin_alt()
.alt(|p| {
p.opt_expect(t!(MINUS)).expect(t!(INTEGER_LIT | FLOAT_LIT))
})
.alt(|p| p.expect(t!(STRING_LIT | TRUE_KW | FALSE_KW)))
.end_alt()
.end()
}
fn patterns_blk(&mut self) -> &mut Self {
self.begin(PATTERNS_BLK)
.expect(t!(STRINGS_KW))
.expect(t!(COLON))
.one_or_more(|p| p.pattern_def())
.end_with_recovery(t!(CONDITION_KW))
}
fn pattern_def(&mut self) -> &mut Self {
self.begin(PATTERN_DEF)
.expect(t!(PATTERN_IDENT))
.expect(t!(EQUAL))
.begin_alt()
.alt(|p| p.expect(t!(STRING_LIT)))
.alt(|p| p.expect(t!(REGEXP)))
.alt(|p| p.hex_pattern())
.end_alt()
.opt(|p| p.pattern_mods())
.end()
}
fn pattern_mods(&mut self) -> &mut Self {
self.begin(PATTERN_MODS).one_or_more(|p| p.pattern_mod()).end()
}
fn pattern_mod(&mut self) -> &mut Self {
const DESC: Option<&'static str> = Some("pattern modifier");
self.begin(PATTERN_MOD)
.begin_alt()
.alt(|p| {
p.expect_d(
t!(ASCII_KW
| WIDE_KW
| NOCASE_KW
| PRIVATE_KW
| FULLWORD_KW),
DESC,
)
})
.alt(|p| {
p.expect_d(t!(BASE64_KW | BASE64WIDE_KW), DESC).opt(|p| {
p.expect(t!(L_PAREN))
.expect(t!(STRING_LIT))
.expect(t!(R_PAREN))
})
})
.alt(|p| {
p.expect_d(t!(XOR_KW), DESC).opt(|p| {
p.expect(t!(L_PAREN))
.expect(t!(INTEGER_LIT))
.opt(|p| p.expect(t!(HYPHEN)).expect(t!(INTEGER_LIT)))
.expect(t!(R_PAREN))
})
})
.end_alt()
.end()
}
fn condition_blk(&mut self) -> &mut Self {
self.begin(CONDITION_BLK)
.expect(t!(CONDITION_KW))
.expect(t!(COLON))
.then(|p| p.boolean_expr())
.end_with_recovery(t!(R_BRACE))
}
fn hex_pattern(&mut self) -> &mut Self {
self.begin(HEX_PATTERN)
.expect(t!(L_BRACE))
.enter_hex_pattern_mode()
.then(|p| p.hex_sub_pattern())
.expect(t!(R_BRACE))
.end()
}
fn hex_sub_pattern(&mut self) -> &mut Self {
self.begin(HEX_SUB_PATTERN)
.begin_alt()
.alt(|p| p.expect(t!(HEX_BYTE)))
.alt(|p| p.hex_alternative())
.end_alt()
.zero_or_more(|p| {
p.zero_or_more(|p| p.hex_jump())
.begin_alt()
.alt(|p| p.expect(t!(HEX_BYTE)))
.alt(|p| p.hex_alternative())
.end_alt()
})
.end()
}
fn hex_alternative(&mut self) -> &mut Self {
self.begin(HEX_ALTERNATIVE)
.expect(t!(L_PAREN))
.then(|p| p.hex_sub_pattern())
.zero_or_more(|p| p.expect(t!(PIPE)).then(|p| p.hex_sub_pattern()))
.expect(t!(R_PAREN))
.end()
}
fn hex_jump(&mut self) -> &mut Self {
self.begin(HEX_JUMP)
.expect(t!(L_BRACKET))
.enter_hex_jump_mode()
.begin_alt()
.alt(|p| {
p.opt_expect(t!(INTEGER_LIT))
.expect(t!(HYPHEN))
.opt_expect(t!(INTEGER_LIT))
})
.alt(|p| p.expect(t!(INTEGER_LIT)))
.end_alt()
.expect(t!(R_BRACKET))
.end()
}
fn boolean_expr(&mut self) -> &mut Self {
self.begin(BOOLEAN_EXPR)
.boolean_term()
.zero_or_more(|p| {
p.expect_d(t!(AND_KW | OR_KW), Some("operator"))
.then(|p| p.boolean_term())
})
.end()
}
fn boolean_term(&mut self) -> &mut Self {
const DESC: Option<&'static str> = Some("expression");
self.begin(BOOLEAN_TERM)
.begin_alt()
.alt(|p| {
p.expect_d(t!(PATTERN_IDENT), DESC)
.cond(t!(AT_KW), |p| p.expr())
.cond(t!(IN_KW), |p| p.range())
})
.alt(|p| p.expect_d(t!(TRUE_KW | FALSE_KW), DESC))
.alt(|p| {
p.expect_d(t!(NOT_KW | DEFINED_KW), DESC)
.then(|p| p.boolean_term())
})
.alt(|p| p.for_expr())
.alt(|p| p.of_expr())
.alt(|p| {
p.expr().zero_or_more(|p| {
p.expect_d(
t!(EQ
| NE
| LE
| LT
| GE
| GT
| CONTAINS_KW
| ICONTAINS_KW
| STARTSWITH_KW
| ISTARTSWITH_KW
| ENDSWITH_KW
| IENDSWITH_KW
| IEQUALS_KW
| MATCHES_KW),
DESC,
)
.then(|p| p.expr())
})
})
.alt(|p| {
p.expect_d(t!(L_PAREN), DESC)
.then(|p| p.boolean_expr())
.expect(t!(R_PAREN))
})
.end_alt()
.end()
}
fn expr(&mut self) -> &mut Self {
self.begin(EXPR)
.term()
.zero_or_more(|p| {
p.expect_d(
t!(ADD
| SUB
| MUL
| DIV
| MOD
| SHL
| SHR
| BITWISE_AND
| BITWISE_OR
| BITWISE_XOR
| DOT),
Some("operator"),
)
.then(|p| p.term())
})
.end()
}
fn term(&mut self) -> &mut Self {
self.begin(TERM)
.then(|p| p.primary_expr())
.cond(t!(L_BRACKET), |p| p.expr().expect(t!(R_BRACKET)))
.cond(t!(L_PAREN), |p| {
p.opt(|p| p.boolean_expr())
.zero_or_more(|p| {
p.expect(t!(COMMA)).then(|p| p.boolean_expr())
})
.expect(t!(R_PAREN))
})
.end()
}
fn range(&mut self) -> &mut Self {
self.begin(RANGE)
.expect(t!(L_PAREN))
.then(|p| p.expr())
.expect(t!(DOT))
.expect(t!(DOT))
.then(|p| p.expr())
.expect(t!(R_PAREN))
.end()
}
fn primary_expr(&mut self) -> &mut Self {
const DESC: Option<&'static str> = Some("expression");
self.cached(PRIMARY_EXPR, |p| {
p.begin(PRIMARY_EXPR)
.begin_alt()
.alt(|p| {
p.expect_d(
t!(FLOAT_LIT
| INTEGER_LIT
| STRING_LIT
| REGEXP
| FILESIZE_KW
| ENTRYPOINT_KW),
DESC,
)
})
.alt(|p| {
p.expect_d(t!(PATTERN_COUNT), DESC)
.opt(|p| p.expect(t!(IN_KW)).then(|p| p.range()))
})
.alt(|p| {
p.expect_d(t!(PATTERN_OFFSET | PATTERN_LENGTH), DESC).opt(
|p| {
p.expect(t!(L_BRACKET))
.then(|p| p.expr())
.expect(t!(R_BRACKET))
},
)
})
.alt(|p| p.expect_d(t!(MINUS), DESC).then(|p| p.term()))
.alt(|p| p.expect_d(t!(BITWISE_NOT), DESC).then(|p| p.term()))
.alt(|p| {
p.expect_d(t!(L_PAREN), DESC)
.then(|p| p.expr())
.expect(t!(R_PAREN))
})
.alt(|p| {
p.expect_d(t!(IDENT), DESC)
.zero_or_more(|p| p.expect(t!(DOT)).expect(t!(IDENT)))
})
.end_alt()
.end()
})
}
fn for_expr(&mut self) -> &mut Self {
self.begin(FOR_EXPR)
.expect(t!(FOR_KW))
.then(|p| p.quantifier())
.begin_alt()
.alt(|p| {
p.expect(t!(OF_KW))
.begin_alt()
.alt(|p| p.expect(t!(THEM_KW)))
.alt(|p| p.pattern_ident_tuple())
.end_alt()
})
.alt(|p| {
p.expect(t!(IDENT))
.zero_or_more(|p| p.expect(t!(COMMA)).expect(t!(IDENT)))
.expect(t!(IN_KW))
.then(|p| p.iterable())
})
.end_alt()
.expect(t!(COLON))
.expect(t!(L_PAREN))
.then(|p| p.boolean_expr())
.expect(t!(R_PAREN))
.end()
}
fn of_expr(&mut self) -> &mut Self {
self.begin(OF_EXPR)
.then(|p| p.quantifier())
.expect(t!(OF_KW))
.begin_alt()
.alt(|p| {
p.begin_alt()
.alt(|p| p.expect(t!(THEM_KW)))
.alt(|p| p.pattern_ident_tuple())
.end_alt()
.cond(t!(AT_KW), |p| p.expr())
.cond(t!(IN_KW), |p| p.range())
})
.alt(|p| {
p.boolean_expr_tuple().not(|p| p.expect(t!(AT_KW | IN_KW)))
})
.end_alt()
.end()
}
fn quantifier(&mut self) -> &mut Self {
self.begin(QUANTIFIER)
.begin_alt()
.alt(|p| p.expect(t!(ALL_KW | NONE_KW | ANY_KW)))
.alt(|p| p.primary_expr().expect(t!(PERCENT)))
.alt(|p| p.expr().not(|p| p.expect(t!(PERCENT))))
.end_alt()
.end()
}
fn iterable(&mut self) -> &mut Self {
self.begin(ITERABLE)
.begin_alt()
.alt(|p| p.range())
.alt(|p| p.expr_tuple())
.alt(|p| p.expr())
.end_alt()
.end()
}
fn boolean_expr_tuple(&mut self) -> &mut Self {
self.begin(BOOLEAN_EXPR_TUPLE)
.expect(t!(L_PAREN))
.then(|p| p.boolean_expr())
.zero_or_more(|p| p.expect(t!(COMMA)).then(|p| p.boolean_expr()))
.expect(t!(R_PAREN))
.end()
}
fn expr_tuple(&mut self) -> &mut Self {
self.begin(EXPR_TUPLE)
.expect(t!(L_PAREN))
.then(|p| p.expr())
.zero_or_more(|p| p.expect(t!(COMMA)).then(|p| p.expr()))
.expect(t!(R_PAREN))
.end()
}
fn pattern_ident_tuple(&mut self) -> &mut Self {
self.begin(PATTERN_IDENT_TUPLE)
.expect(t!(L_PAREN))
.expect(t!(PATTERN_IDENT))
.opt_expect(t!(ASTERISK)) .zero_or_more(|p| {
p.expect(t!(COMMA))
.expect(t!(PATTERN_IDENT))
.opt_expect(t!(ASTERISK))
})
.expect(t!(R_PAREN))
.end()
}
}
struct Bookmark {
tokens: token_stream::Bookmark,
output: syntax_stream::Bookmark,
}
struct TokenSet(&'static [SyntaxKind]);
impl TokenSet {
#[inline]
fn is_empty(&self) -> bool {
self.0.is_empty()
}
fn contains(&self, token: &Token) -> Option<&SyntaxKind> {
self.0.iter().find(|t| t.token_id() == token.id())
}
fn token_ids(&self) -> impl Iterator<Item = TokenId> + 'static {
self.0.iter().map(move |t| t.token_id())
}
}
struct Alt<'a, 'src> {
parser: &'a mut ParserImpl<'src>,
matched: bool,
bookmark: Bookmark,
}
impl<'a, 'src> Alt<'a, 'src> {
fn alt<F>(mut self, f: F) -> Self
where
F: Fn(&'a mut ParserImpl<'src>) -> &'a mut ParserImpl<'src>,
{
if matches!(self.parser.state, ParserState::Failure) {
return self;
}
if !self.matched {
self.parser.trivia();
self.parser.opt_depth += 1;
self.parser = f(self.parser);
self.parser.opt_depth -= 1;
match self.parser.state {
ParserState::OK => {
self.matched = true;
}
ParserState::Failure => {
self.parser.recover();
self.parser.restore_bookmark(&self.bookmark);
}
_ => unreachable!(),
};
}
self
}
fn end_alt(self) -> &'a mut ParserImpl<'src> {
self.parser.remove_bookmark(self.bookmark);
if self.matched {
self.parser.state = ParserState::OK;
} else {
self.parser.state = ParserState::Failure;
self.parser.handle_errors();
};
self.parser
}
}