use crate::parse_recovery::{ParseRecovery, ParseRecoveryTokenSet, RecoveryResult};
use crate::parsed_syntax::ParsedSyntax::{Absent, Present};
use crate::prelude::*;
use biome_rowan::TextRange;
#[derive(Debug, PartialEq, Eq)]
#[must_use = "this `ParsedSyntax` may be an `Absent` variant, which should be handled"]
pub enum ParsedSyntax {
Absent,
Present(CompletedMarker),
}
impl ParsedSyntax {
#[inline]
pub fn ok(self) -> Option<CompletedMarker> {
match self {
Absent => None,
Present(marker) => Some(marker),
}
}
#[inline]
pub fn and_then<F>(self, op: F) -> ParsedSyntax
where
F: FnOnce(CompletedMarker) -> ParsedSyntax,
{
match self {
Absent => Absent,
Present(marker) => op(marker),
}
}
#[inline]
pub fn or_else<F>(self, op: F) -> ParsedSyntax
where
F: FnOnce() -> ParsedSyntax,
{
match self {
Absent => op(),
t => t,
}
}
#[inline]
#[must_use]
pub fn is_present(&self) -> bool {
matches!(self, Present(_))
}
#[inline]
#[must_use]
pub fn is_absent(&self) -> bool {
matches!(self, Absent)
}
#[inline]
#[track_caller]
pub fn unwrap(self) -> CompletedMarker {
match self {
Absent => {
panic!("Called `unwrap` on an `Absent` syntax");
}
Present(marker) => marker,
}
}
#[allow(unused)]
#[inline]
pub fn unwrap_or(self, default: CompletedMarker) -> CompletedMarker {
match self {
Absent => default,
Present(marker) => marker,
}
}
#[inline]
#[allow(unused)]
pub fn unwrap_or_else<F>(self, default: F) -> CompletedMarker
where
F: FnOnce() -> CompletedMarker,
{
match self {
Absent => default(),
Present(marker) => marker,
}
}
#[inline]
#[track_caller]
pub fn expect(self, msg: &str) -> CompletedMarker {
match self {
Present(marker) => marker,
Absent => panic!("{}", msg),
}
}
pub fn map<F>(self, mapper: F) -> ParsedSyntax
where
F: FnOnce(CompletedMarker) -> CompletedMarker,
{
match self {
Absent => Absent,
Present(element) => Present(mapper(element)),
}
}
#[inline]
pub fn kind<P>(&self, p: &P) -> Option<P::Kind>
where
P: Parser,
{
match self {
Absent => None,
Present(marker) => Some(marker.kind(p)),
}
}
#[inline]
pub fn add_diagnostic_if_present<P, E, D>(
self,
p: &mut P,
error_builder: E,
) -> Option<CompletedMarker>
where
P: Parser,
E: FnOnce(&P, TextRange) -> D,
D: ToDiagnostic<P>,
{
match self {
Present(syntax) => {
let range = syntax.range(p);
let range = TextRange::new(range.start(), range.end());
let diagnostic = error_builder(p, range);
p.error(diagnostic);
Some(syntax)
}
Absent => None,
}
}
#[inline]
pub fn or_add_diagnostic<P, E, D>(self, p: &mut P, error_builder: E) -> Option<CompletedMarker>
where
P: Parser,
E: FnOnce(&P, TextRange) -> D,
D: ToDiagnostic<P>,
{
match self {
Present(syntax) => Some(syntax),
Absent => {
let diagnostic = error_builder(p, p.cur_range());
p.error(diagnostic);
None
}
}
}
#[inline]
pub fn precede_or_add_diagnostic<P, E, D>(self, p: &mut P, error_builder: E) -> Marker
where
P: Parser,
E: FnOnce(&P, TextRange) -> D,
D: ToDiagnostic<P>,
{
match self {
Present(completed) => completed.precede(p),
Absent => {
let diagnostic = error_builder(p, p.cur_range());
p.error(diagnostic);
p.start()
}
}
}
#[inline]
pub fn precede<P>(self, p: &mut P) -> Marker
where
P: Parser,
{
match self {
Present(marker) => marker.precede(p),
Absent => p.start(),
}
}
pub fn or_recover_with_token_set<P, E>(
self,
p: &mut P,
recovery: &ParseRecoveryTokenSet<P::Kind>,
error_builder: E,
) -> RecoveryResult
where
P: Parser,
E: FnOnce(&P, TextRange) -> ParseDiagnostic,
{
match self {
Present(syntax) => Ok(syntax),
Absent => match recovery.recover(p) {
Ok(recovered) => {
let diagnostic = error_builder(p, recovered.range(p));
p.error(diagnostic);
Ok(recovered)
}
Err(recovery_error) => {
let diagnostic = error_builder(p, p.cur_range());
p.error(diagnostic);
Err(recovery_error)
}
},
}
}
pub fn or_recover<'source, P, E, R>(
self,
p: &mut P,
recovery: &R,
error_builder: E,
) -> RecoveryResult
where
P: Parser,
R: ParseRecovery<Parser<'source> = P>,
E: FnOnce(&P, TextRange) -> ParseDiagnostic,
{
match self {
Present(syntax) => Ok(syntax),
Absent => match recovery.recover(p) {
Ok(recovered) => {
let diagnostic = error_builder(p, recovered.range(p));
p.error(diagnostic);
Ok(recovered)
}
Err(recovery_error) => {
let diagnostic = error_builder(p, p.cur_range());
p.error(diagnostic);
Err(recovery_error)
}
},
}
}
}
impl From<CompletedMarker> for ParsedSyntax {
fn from(marker: CompletedMarker) -> Self {
Present(marker)
}
}
impl From<Option<CompletedMarker>> for ParsedSyntax {
fn from(option: Option<CompletedMarker>) -> Self {
match option {
Some(completed) => Present(completed),
None => Absent,
}
}
}