use std::borrow::Cow;
use crate::{TSXKeyword, TSXToken};
use iterator_endiate::EndiateIteratorExt;
use source_map::Span;
use tokenizer_lib::Token;
use visitable_derive::Visitable;
use crate::{errors::parse_lexing_error, tokens::token_as_identifier, ASTNode, Expression};
#[derive(Debug, Clone, PartialEq, Eq, Visitable)]
#[cfg_attr(feature = "self-rust-tokenize", derive(self_rust_tokenize::SelfRustTokenize))]
pub struct EnumDeclaration {
pub is_constant: bool,
pub name: String,
pub members: Vec<EnumMember>,
pub position: Span,
}
impl ASTNode for EnumDeclaration {
fn get_position(&self) -> Cow<Span> {
Cow::Borrowed(&self.position)
}
fn from_reader(
reader: &mut impl tokenizer_lib::TokenReader<crate::TSXToken, Span>,
state: &mut crate::ParsingState,
settings: &crate::ParseOptions,
) -> Result<Self, crate::ParseError> {
let const_pos = reader
.conditional_next(|tok| matches!(tok, TSXToken::Keyword(TSXKeyword::Const)))
.map(|Token(_, pos)| pos);
let is_constant = const_pos.is_some();
let enum_pos = reader.expect_next(TSXToken::Keyword(TSXKeyword::Enum))?;
let (name, _) =
token_as_identifier(reader.next().ok_or_else(parse_lexing_error)?, "Enum name")?;
reader.expect_next(TSXToken::OpenBrace)?;
let mut members = Vec::new();
loop {
if let Some(Token(TSXToken::CloseBrace, _)) = reader.peek() {
break;
}
members.push(EnumMember::from_reader(reader, state, settings)?);
if let Some(Token(TSXToken::Comma, _)) = reader.peek() {
reader.next();
}
}
let end_pos = reader.expect_next(TSXToken::CloseBrace)?;
Ok(EnumDeclaration {
is_constant,
position: const_pos.unwrap_or(enum_pos).union(&end_pos),
name,
members,
})
}
fn to_string_from_buffer<T: source_map::ToString>(
&self,
buf: &mut T,
settings: &crate::ToStringOptions,
depth: u8,
) {
if self.is_constant {
buf.push_str("const ");
}
buf.push_str("enum ");
buf.push_str(&self.name);
settings.add_gap(buf);
buf.push_str("{");
for (at_end, member) in self.members.iter().endiate() {
if settings.pretty {
buf.push_new_line();
settings.add_indent(depth + 1, buf);
}
member.to_string_from_buffer(buf, settings, depth);
if !settings.pretty && !at_end {
buf.push(',');
}
}
if settings.pretty && !self.members.is_empty() {
buf.push_new_line();
}
buf.push('}');
}
}
#[derive(Debug, Clone, PartialEq, Eq, Visitable)]
#[cfg_attr(feature = "self-rust-tokenize", derive(self_rust_tokenize::SelfRustTokenize))]
pub enum EnumMember {
Variant { name: String, value: Option<Expression>, position: Span },
}
impl ASTNode for EnumMember {
fn get_position(&self) -> Cow<Span> {
match self {
EnumMember::Variant { position, .. } => Cow::Borrowed(position),
}
}
fn from_reader(
reader: &mut impl tokenizer_lib::TokenReader<crate::TSXToken, Span>,
state: &mut crate::ParsingState,
settings: &crate::ParseOptions,
) -> Result<Self, crate::ParseError> {
let (name, start_pos) =
token_as_identifier(reader.next().ok_or_else(parse_lexing_error)?, "Enum variant")?;
match reader.peek() {
Some(Token(TSXToken::Assign, _)) => {
reader.next();
let expression = Expression::from_reader(reader, state, settings)?;
Ok(EnumMember::Variant {
name,
position: start_pos.union(&expression.get_position()),
value: Some(expression),
})
}
_ => Ok(EnumMember::Variant { name, value: None, position: start_pos }),
}
}
fn to_string_from_buffer<T: source_map::ToString>(
&self,
buf: &mut T,
settings: &crate::ToStringOptions,
depth: u8,
) {
match self {
EnumMember::Variant { name, value, .. } => {
buf.push_str(name);
if let Some(value) = value {
buf.push_str(if settings.pretty { " = " } else { "=" });
value.to_string_from_buffer(buf, settings, depth);
}
}
}
}
}