use std::fmt::{Display, Formatter};
use crate::{
Lex, Offset, Parse, ParseStream, Span, Spanned, TokenGroup, TokenParseError, TokenStream,
TokenTree,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DelimiterKind {
Parenthesis,
Bracket,
Brace,
AngleBar,
}
impl DelimiterKind {
pub const fn expression_name(self) -> &'static str {
match self {
Self::Parenthesis => "parenthesized expression",
Self::Bracket => "array expression",
Self::Brace => "list expression",
Self::AngleBar => "angle-bar list expression",
}
}
}
pub trait DelimiterValue: Spanned + Lex + Sized {
fn from_delimiter(delimiter: Delimiter) -> Option<Self>;
fn delimiter(&self) -> Delimiter;
fn expected() -> &'static str;
fn surround(&self, output: &mut TokenStream, contents: TokenStream) {
output.extend([TokenGroup::new(self.delimiter(), contents)]);
}
}
pub trait DelimiterToken: Parse + DelimiterValue {
const KIND: DelimiterKind;
fn new(spans: DoubleSpan) -> Self;
fn spans(&self) -> DoubleSpan;
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct DoubleSpan(pub Span, pub Span);
impl DoubleSpan {
pub fn new(open: Span, close: Span) -> Self {
Self(open, close)
}
pub fn detached() -> Self {
Self(Span::detached(), Span::detached())
}
pub fn unclosed(open: Span, eof: Offset) -> Self {
Self(open, Span::from_offset(eof))
}
pub fn open(&self) -> Span {
self.0.clone()
}
pub fn close(&self) -> Span {
self.1.clone()
}
pub fn is_closed(&self) -> bool {
self.1.bounds().is_none_or(|(start, end)| start != end)
}
}
impl Spanned for DoubleSpan {
fn span(&self) -> Span {
self.0.join(self.1.clone())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Delimiter {
pub kind: DelimiterKind,
pub spans: DoubleSpan,
}
impl Delimiter {
pub fn new(kind: DelimiterKind, spans: DoubleSpan) -> Self {
Self { kind, spans }
}
pub fn opening_span(&self) -> Span {
self.spans.open()
}
pub fn closing_span(&self) -> Span {
self.spans.close()
}
pub fn is_closed(&self) -> bool {
self.spans.is_closed()
}
}
impl Spanned for Delimiter {
fn span(&self) -> Span {
self.spans.span()
}
}
impl DelimiterValue for Delimiter {
fn from_delimiter(delimiter: Delimiter) -> Option<Self> {
Some(delimiter)
}
fn delimiter(&self) -> Delimiter {
self.clone()
}
fn expected() -> &'static str {
"a delimited group"
}
}
impl Parse for Delimiter {
fn parse(input: &mut ParseStream) -> Result<Self, TokenParseError> {
let group = parse_any_group(input, Self::expected())?;
if !group.stream().is_empty() {
return Err(TokenParseError::unexpected(
"an empty delimited group",
group.delim_kind().opening(),
group.span(),
));
}
Ok(group.delimiter().clone())
}
}
impl Lex for Delimiter {
fn to_tokens(&self, output: &mut TokenStream) {
self.surround(output, TokenStream::new());
}
}
#[doc(hidden)]
pub fn parse_delimiter<D: DelimiterToken>(input: &mut ParseStream) -> Result<D, TokenParseError> {
let kind = D::KIND;
let group = parse_group(input, kind)?;
if !group.stream().is_empty() {
return Err(TokenParseError::unexpected(
kind.opening(),
kind.opening(),
group.span(),
));
}
Ok(D::new(group.delimiter().spans.clone()))
}
pub(crate) fn parse_group(
input: &mut ParseStream,
kind: DelimiterKind,
) -> Result<TokenGroup, TokenParseError> {
let group = parse_any_group(input, kind.opening())?;
if group.delim_kind() != kind {
return Err(TokenParseError::unexpected(
kind.opening(),
group.delim_kind().opening(),
group.span(),
));
}
Ok(group)
}
pub(crate) fn parse_any_group(
input: &mut ParseStream,
expected: &'static str,
) -> Result<TokenGroup, TokenParseError> {
let Some(token) = input.next_token() else {
return Err(TokenParseError::unexpected_end(expected, input.eof_span()));
};
let TokenTree::Group(group) = token else {
return Err(TokenParseError::unexpected_token(expected, &token));
};
Ok(group)
}
impl Display for Delimiter {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
formatter.write_str(self.kind.opening())
}
}
impl Display for DelimiterKind {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
formatter.write_str(self.opening())
}
}
impl DelimiterKind {
pub fn opening(self) -> &'static str {
match self {
Self::Parenthesis => "(",
Self::Bracket => "[",
Self::Brace => "{",
Self::AngleBar => "<|",
}
}
pub fn closing(self) -> &'static str {
match self {
Self::Parenthesis => ")",
Self::Bracket => "]",
Self::Brace => "}",
Self::AngleBar => "|>",
}
}
}