use crate::ast::dialect::FeatureSet;
use crate::ast::{Meta, NodeId, Span, Symbol};
use crate::error::{ErrorSink, Expected, FailFastSink, Found, ParseError, ParseResult};
use crate::interner::Interner;
use crate::tokenizer::{BufferedTokenCursor, LexError, Token, TriviaIndex};
use super::Dialect;
use super::clause_marks::{ClauseKw, ClauseMark, ClauseMarkIndex};
pub const DEFAULT_RECURSION_LIMIT: usize = 128;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Checkpoint {
pos: usize,
}
pub struct Parser<'a, D: Dialect> {
cursor: BufferedTokenCursor<'a>,
source: &'a str,
interner: Interner,
errors: FailFastSink,
dialect: D,
next_node_id: u32,
peeked: Option<(usize, Result<Option<Token>, LexError>)>,
recursion_depth: usize,
pub(super) angle_gt_pending: u32,
recursion_limit: usize,
parse_float_as_decimal: bool,
paren_query_grouping: bool,
grouped_query_complete: bool,
pub(in crate::parser) restrict_b_expr: bool,
pub(in crate::parser) suppress_value_star: bool,
pub(in crate::parser) in_connect_by: bool,
capture_clause_marks: bool,
clause_marks: Vec<ClauseMark>,
pub(in crate::parser) body_return_allowed: bool,
}
impl<'a, D: Dialect> Parser<'a, D> {
pub fn new(source: &'a str, tokens: &'a [Token], dialect: D) -> Self {
debug_assert!(
u32::try_from(source.len()).is_ok(),
"Parser source length must fit in u32; tokenize() guards this",
);
Self::from_cursor(source, dialect, BufferedTokenCursor::from_tokens(tokens))
}
pub(crate) fn streaming(
source: &'a str,
dialect: D,
) -> Result<Self, crate::tokenizer::LexError> {
let cursor = BufferedTokenCursor::streaming(source, dialect.features())?;
Ok(Self::from_cursor(source, dialect, cursor))
}
pub(crate) fn streaming_with_trivia(
source: &'a str,
dialect: D,
) -> Result<Self, crate::tokenizer::LexError> {
let cursor = BufferedTokenCursor::streaming_with_trivia(source, dialect.features())?;
Ok(Self::from_cursor(source, dialect, cursor))
}
fn from_cursor(source: &'a str, dialect: D, cursor: BufferedTokenCursor<'a>) -> Self {
debug_assert!(
dialect.features().is_lexically_consistent(),
"dialect feature set is lexically inconsistent: {:?} — two features claim one \
tokenizer trigger, so a fixed lex precedence silently shadows one reading (see \
the FeatureSet::lexical_conflict registry); enable only one claimant of the trigger.",
dialect.features().lexical_conflict(),
);
debug_assert!(
dialect.features().has_satisfied_feature_dependencies(),
"dialect feature set has an unsatisfied grammar-flag dependency: {:?} — a refinement \
flag is enabled without the base flag it rides on, leaving it inert (see the \
FeatureSet::feature_dependencies registry); enable the named base flag or drop the \
dependent one.",
dialect.features().feature_dependencies(),
);
debug_assert!(
dialect.features().has_no_grammar_conflict(),
"dialect feature set has a grammar-position conflict: {:?} — two features read the \
same parser-position head with no lookahead to tell them apart, so a fixed branch \
order silently shadows one reading (see the FeatureSet::grammar_conflict registry); \
enable only one of the contending features.",
dialect.features().grammar_conflict(),
);
Self {
cursor,
source,
interner: Interner::new(),
errors: FailFastSink::new(),
dialect,
next_node_id: 1,
peeked: None,
recursion_depth: 0,
angle_gt_pending: 0,
recursion_limit: DEFAULT_RECURSION_LIMIT,
parse_float_as_decimal: false,
paren_query_grouping: false,
grouped_query_complete: false,
restrict_b_expr: false,
suppress_value_star: false,
in_connect_by: false,
capture_clause_marks: false,
clause_marks: Vec::new(),
body_return_allowed: true,
}
}
#[must_use]
pub fn with_recursion_limit(mut self, limit: usize) -> Self {
self.recursion_limit = limit;
self
}
#[must_use]
pub fn with_parse_float_as_decimal(mut self, enabled: bool) -> Self {
self.parse_float_as_decimal = enabled;
self
}
pub(in crate::parser) fn parse_float_as_decimal(&self) -> bool {
self.parse_float_as_decimal
}
pub(crate) fn with_clause_mark_capture(mut self, enabled: bool) -> Self {
self.capture_clause_marks = enabled;
self
}
#[inline(always)]
pub(in crate::parser) fn capturing_clause_marks(&self) -> bool {
self.capture_clause_marks
}
#[inline(always)]
pub(in crate::parser) fn clause_marks_checkpoint(&self) -> usize {
self.clause_marks.len()
}
#[inline(always)]
pub(in crate::parser) fn truncate_clause_marks(&mut self, checkpoint: usize) {
self.clause_marks.truncate(checkpoint);
}
#[inline(never)]
pub(in crate::parser) fn record_clause_mark(&mut self, kind: ClauseKw, offset: u32) {
self.clause_marks.push(ClauseMark::pending(kind, offset));
}
#[inline(never)]
pub(in crate::parser) fn patch_clause_marks(&mut self, checkpoint: usize, owner: NodeId) {
for mark in &mut self.clause_marks[checkpoint..] {
if mark.owner_is_pending() {
mark.set_owner(owner);
}
}
}
pub(crate) fn take_clause_marks(&mut self) -> ClauseMarkIndex {
ClauseMarkIndex::new(std::mem::take(&mut self.clause_marks))
}
pub fn peek(&mut self) -> Result<Option<Token>, LexError> {
let pos = self.cursor.pos();
if let Some((cached_pos, cached)) = self.peeked {
if cached_pos == pos {
return cached;
}
}
let result = self.cursor.peek();
self.peeked = Some((pos, result));
result
}
pub fn peek_nth(&mut self, n: usize) -> Result<Option<Token>, LexError> {
if n == 0 {
return self.peek();
}
self.cursor.peek_nth(n)
}
pub fn advance(&mut self) -> Result<Option<Token>, LexError> {
self.cursor.advance()
}
pub fn is_eof(&mut self) -> Result<bool, LexError> {
self.cursor.is_eof()
}
pub fn current_span(&mut self) -> crate::error::ParseResult<Span> {
Ok(match self.peek()? {
Some(token) => token.span,
None => self.eof_span(),
})
}
pub fn preceding_span(&self) -> Span {
self.cursor
.preceding()
.map_or_else(|| Span::new(0, 0), |token| token.span)
}
pub fn eof_span(&self) -> Span {
let end = self.source.len() as u32;
Span::new(end, end)
}
pub fn span_text(&self, span: Span) -> &'a str {
let source: &'a str = self.source;
&source[span.start() as usize..span.end() as usize]
}
pub fn intern_identifier(&mut self, token: Token) -> Symbol {
use crate::tokenizer::TokenKind;
let text = self.span_text(token.span);
match token.kind {
TokenKind::Word => self.interner.intern_nonkeyword(text),
TokenKind::Keyword(kw) => self.interner.intern_keyword_ident(kw, text),
_ => self.interner.intern(text),
}
}
pub fn intern_text(&mut self, text: &str) -> Symbol {
self.interner.intern(text)
}
pub fn next_node_id(&mut self) -> NodeId {
let id = NodeId::new(self.next_node_id)
.expect("node-id counter starts at 1 and never reaches 0");
self.next_node_id += 1;
id
}
pub fn make_meta(&mut self, span: Span) -> Meta {
Meta::new(span, self.next_node_id())
}
pub fn report(&mut self, error: ParseError) {
self.errors.report(error);
}
pub fn error_at(
&mut self,
span: Span,
expected: impl Into<Expected>,
found: impl Into<Found>,
) -> ParseError {
let error = ParseError::new(span, expected, found);
self.report(error.clone());
error
}
pub fn unexpected(&mut self, expected: impl Into<Expected>) -> ParseError {
let expected = expected.into();
match self.peek() {
Ok(Some(token)) => {
let found = self.span_text(token.span).to_owned();
self.error_at(token.span, expected, found)
}
Ok(None) => {
let span = self.eof_span();
self.error_at(span, expected, Found::EndOfInput)
}
Err(error) => {
let error = ParseError::from(error);
self.report(error.clone());
error
}
}
}
pub(super) fn enter_recursion(&mut self, span: Span) -> ParseResult<RecursionGuard<'_, 'a, D>> {
if self.recursion_depth >= self.recursion_limit {
return Err(self.recursion_limit_exceeded(span));
}
self.recursion_depth += 1;
Ok(RecursionGuard { parser: self })
}
fn recursion_limit_exceeded(&mut self, span: Span) -> ParseError {
let error = ParseError::recursion_limit_exceeded(span);
self.report(error.clone());
error
}
pub fn checkpoint(&self) -> Checkpoint {
Checkpoint {
pos: self.cursor.pos(),
}
}
pub fn rewind(&mut self, checkpoint: Checkpoint) {
self.cursor.seek(checkpoint.pos);
}
pub(super) fn discard_consumed_tokens(&mut self) {
self.cursor.discard_consumed();
}
pub(crate) fn recover_to_statement_boundary(&mut self) -> ParseResult<bool> {
use crate::tokenizer::{Punctuation, TokenKind};
while let Some(token) = self.advance()? {
if matches!(token.kind, TokenKind::Punctuation(Punctuation::Semicolon)) {
return Ok(true);
}
}
Ok(false)
}
pub fn features(&self) -> &FeatureSet {
self.dialect.features()
}
pub(super) fn take_paren_query_grouping(&mut self) -> bool {
std::mem::take(&mut self.paren_query_grouping)
}
pub(super) fn set_paren_query_grouping(&mut self, grouping: bool) {
self.paren_query_grouping = grouping;
}
pub(super) fn mark_grouped_query_complete(&mut self) {
self.grouped_query_complete = true;
}
pub(super) fn grouped_query_complete(&self) -> bool {
self.grouped_query_complete
}
pub(super) fn take_grouped_query_complete(&mut self) -> bool {
std::mem::take(&mut self.grouped_query_complete)
}
pub(crate) fn live_resolver(&self) -> &Interner {
&self.interner
}
pub(crate) fn take_trivia(&mut self) -> TriviaIndex {
self.cursor.take_trivia()
}
pub(crate) fn finish(self) -> crate::interner::FrozenResolver {
self.interner.freeze()
}
}
pub(super) struct RecursionGuard<'p, 'a, D: Dialect> {
parser: &'p mut Parser<'a, D>,
}
impl<'a, D: Dialect> RecursionGuard<'_, 'a, D> {
pub(super) fn parser(&mut self) -> &mut Parser<'a, D> {
self.parser
}
}
impl<D: Dialect> Drop for RecursionGuard<'_, '_, D> {
fn drop(&mut self) {
self.parser.recursion_depth -= 1;
}
}