use super::{punctuated::Punctuated, span::ContainedSpan, *};
use crate::{
util::display_option,
visitors::{Visit, VisitMut},
ShortString,
};
use derive_more::Display;
#[derive(Clone, Debug, Display, PartialEq, Node)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[non_exhaustive]
pub enum TypeInfo {
#[display(
"{}{}{}{}",
braces.tokens().0,
display_option(access),
type_info,
braces.tokens().1
)]
Array {
braces: ContainedSpan,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
access: Option<TokenReference>,
type_info: Box<TypeInfo>,
},
#[display("{_0}")]
Basic(TokenReference),
#[display("{_0}")]
String(TokenReference),
#[display("{_0}")]
Boolean(TokenReference),
#[display(
"{}{}{arguments}{}{arrow}{return_type}",
display_option(generics),
parentheses.tokens().0,
parentheses.tokens().1
)]
Callback {
generics: Option<GenericDeclaration>,
parentheses: ContainedSpan,
arguments: Punctuated<TypeArgument>,
arrow: TokenReference,
return_type: Box<TypeInfo>,
},
#[display(
"{}{}{}{}",
base,
arrows.tokens().0,
generics,
arrows.tokens().1
)]
Generic {
base: TokenReference,
arrows: ContainedSpan,
generics: Punctuated<TypeInfo>,
},
#[display("{name}{ellipsis}")]
GenericPack {
name: TokenReference,
ellipsis: TokenReference,
},
#[display("{_0}")]
Intersection(TypeIntersection),
#[display("{module}{punctuation}{type_info}")]
Module {
module: TokenReference,
punctuation: TokenReference,
type_info: Box<IndexedTypeInfo>,
},
#[display("{base}{question_mark}")]
Optional {
base: Box<TypeInfo>,
question_mark: TokenReference,
},
#[display("{}{}{}", braces.tokens().0, fields, braces.tokens().1)]
Table {
braces: ContainedSpan,
fields: Punctuated<TypeField>,
},
#[display(
"{}{}{}{}",
typeof_token,
parentheses.tokens().0,
inner,
parentheses.tokens().1
)]
Typeof {
typeof_token: TokenReference,
parentheses: ContainedSpan,
inner: Box<Expression>,
},
#[display(
"{}{}{}",
parentheses.tokens().0,
types,
parentheses.tokens().1
)]
Tuple {
parentheses: ContainedSpan,
types: Punctuated<TypeInfo>,
},
#[display("{_0}")]
Union(TypeUnion),
#[display("{ellipsis}{type_info}")]
Variadic {
ellipsis: TokenReference,
type_info: Box<TypeInfo>,
},
#[display("{ellipsis}{name}")]
VariadicPack {
ellipsis: TokenReference,
name: TokenReference,
},
}
#[derive(Clone, Debug, Display, PartialEq, Node)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display("{}{types}", display_option(leading))]
pub struct TypeUnion {
pub(crate) leading: Option<TokenReference>,
pub(crate) types: Punctuated<TypeInfo>,
}
impl TypeUnion {
pub fn new(leading: Option<TokenReference>, types: Punctuated<TypeInfo>) -> Self {
Self { leading, types }
}
pub fn with_types(self, types: Punctuated<TypeInfo>) -> Self {
Self { types, ..self }
}
pub fn with_leading(self, leading: Option<TokenReference>) -> Self {
Self { leading, ..self }
}
pub fn leading(&self) -> Option<&TokenReference> {
self.leading.as_ref()
}
pub fn types(&self) -> &Punctuated<TypeInfo> {
&self.types
}
}
#[derive(Clone, Debug, Display, PartialEq, Node)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display("{}{types}", display_option(leading))]
pub struct TypeIntersection {
pub(crate) leading: Option<TokenReference>,
pub(crate) types: Punctuated<TypeInfo>,
}
impl TypeIntersection {
pub fn new(leading: Option<TokenReference>, types: Punctuated<TypeInfo>) -> Self {
Self { leading, types }
}
pub fn with_types(self, types: Punctuated<TypeInfo>) -> Self {
Self { types, ..self }
}
pub fn with_leading(self, leading: Option<TokenReference>) -> Self {
Self { leading, ..self }
}
pub fn leading(&self) -> Option<&TokenReference> {
self.leading.as_ref()
}
pub fn types(&self) -> &Punctuated<TypeInfo> {
&self.types
}
}
#[derive(Clone, Debug, Display, PartialEq, Node)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[non_exhaustive]
pub enum IndexedTypeInfo {
#[display("{_0}")]
Basic(TokenReference),
#[display("{base}{}{generics}{}", arrows.tokens().0, arrows.tokens().1)]
Generic {
base: TokenReference,
arrows: ContainedSpan,
generics: Punctuated<TypeInfo>,
},
}
#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display("{}{key}{colon}{value}", display_option(access))]
pub struct TypeField {
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub(crate) access: Option<TokenReference>,
pub(crate) key: TypeFieldKey,
pub(crate) colon: TokenReference,
pub(crate) value: TypeInfo,
}
impl TypeField {
pub fn new(key: TypeFieldKey, value: TypeInfo) -> Self {
Self {
access: None,
key,
colon: TokenReference::symbol(": ").unwrap(),
value,
}
}
pub fn access(&self) -> Option<&TokenReference> {
self.access.as_ref()
}
pub fn key(&self) -> &TypeFieldKey {
&self.key
}
pub fn colon_token(&self) -> &TokenReference {
&self.colon
}
pub fn value(&self) -> &TypeInfo {
&self.value
}
pub fn with_key(self, key: TypeFieldKey) -> Self {
Self { key, ..self }
}
pub fn with_colon_token(self, colon_token: TokenReference) -> Self {
Self {
colon: colon_token,
..self
}
}
pub fn with_access(self, access: Option<TokenReference>) -> Self {
Self { access, ..self }
}
pub fn with_value(self, value: TypeInfo) -> Self {
Self { value, ..self }
}
}
#[derive(Clone, Debug, Display, PartialEq, Node)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[non_exhaustive]
pub enum TypeFieldKey {
#[display("{_0}")]
Name(TokenReference),
#[display("{}{}{}", brackets.tokens().0, inner, brackets.tokens().1)]
IndexSignature {
brackets: ContainedSpan,
inner: TypeInfo,
},
}
#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display("{assertion_op}{cast_to}")]
pub struct TypeAssertion {
pub(crate) assertion_op: TokenReference,
pub(crate) cast_to: TypeInfo,
}
impl TypeAssertion {
pub fn new(cast_to: TypeInfo) -> Self {
Self {
assertion_op: TokenReference::symbol("::").unwrap(),
cast_to,
}
}
pub fn assertion_op(&self) -> &TokenReference {
&self.assertion_op
}
pub fn cast_to(&self) -> &TypeInfo {
&self.cast_to
}
pub fn with_assertion_op(self, assertion_op: TokenReference) -> Self {
Self {
assertion_op,
..self
}
}
pub fn with_cast_to(self, cast_to: TypeInfo) -> Self {
Self { cast_to, ..self }
}
}
#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display(
"{}{}{}{}{}",
type_token,
base,
display_option(generics),
equal_token,
declare_as
)]
pub struct TypeDeclaration {
pub(crate) type_token: TokenReference,
pub(crate) base: TokenReference,
pub(crate) generics: Option<GenericDeclaration>,
pub(crate) equal_token: TokenReference,
pub(crate) declare_as: TypeInfo,
}
impl TypeDeclaration {
pub fn new(type_name: TokenReference, type_definition: TypeInfo) -> Self {
Self {
type_token: TokenReference::new(
Vec::new(),
Token::new(TokenType::Identifier {
identifier: "type".into(),
}),
vec![Token::new(TokenType::spaces(1))],
),
base: type_name,
generics: None,
equal_token: TokenReference::symbol(" = ").unwrap(),
declare_as: type_definition,
}
}
pub fn type_token(&self) -> &TokenReference {
&self.type_token
}
pub fn type_name(&self) -> &TokenReference {
&self.base
}
pub fn generics(&self) -> Option<&GenericDeclaration> {
self.generics.as_ref()
}
pub fn equal_token(&self) -> &TokenReference {
&self.equal_token
}
pub fn type_definition(&self) -> &TypeInfo {
&self.declare_as
}
pub fn with_type_token(self, type_token: TokenReference) -> Self {
Self { type_token, ..self }
}
pub fn with_type_name(self, type_name: TokenReference) -> Self {
Self {
base: type_name,
..self
}
}
pub fn with_generics(self, generics: Option<GenericDeclaration>) -> Self {
Self { generics, ..self }
}
pub fn with_equal_token(self, equal_token: TokenReference) -> Self {
Self {
equal_token,
..self
}
}
pub fn with_type_definition(self, type_definition: TypeInfo) -> Self {
Self {
declare_as: type_definition,
..self
}
}
}
#[derive(Clone, Debug, Display, PartialEq, Eq, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[non_exhaustive]
pub enum GenericParameterInfo {
#[display("{_0}")]
Name(TokenReference),
#[display("{name}{ellipsis}")]
Variadic {
name: TokenReference,
ellipsis: TokenReference,
},
}
#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display(
"{}{}{}",
parameter,
display_option(self.equals()),
display_option(self.default_type())
)]
pub struct GenericDeclarationParameter {
pub(crate) parameter: GenericParameterInfo,
pub(crate) default: Option<(TokenReference, TypeInfo)>,
}
impl GenericDeclarationParameter {
pub fn new(parameter: GenericParameterInfo) -> Self {
Self {
parameter,
default: None,
}
}
pub fn parameter(&self) -> &GenericParameterInfo {
&self.parameter
}
pub fn equals(&self) -> Option<&TokenReference> {
self.default.as_ref().map(|(equals, _)| equals)
}
pub fn default_type(&self) -> Option<&TypeInfo> {
self.default.as_ref().map(|(_, default_type)| default_type)
}
pub fn with_parameter(self, parameter: GenericParameterInfo) -> Self {
Self { parameter, ..self }
}
pub fn with_default(self, default: Option<(TokenReference, TypeInfo)>) -> Self {
Self { default, ..self }
}
}
#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display("{}{}{}", arrows.tokens().0, generics, arrows.tokens().1)]
pub struct GenericDeclaration {
#[visit(contains = "generics")]
pub(crate) arrows: ContainedSpan,
pub(crate) generics: Punctuated<GenericDeclarationParameter>,
}
impl GenericDeclaration {
pub fn new() -> Self {
Self {
arrows: ContainedSpan::new(
TokenReference::symbol("<").unwrap(),
TokenReference::symbol(">").unwrap(),
),
generics: Punctuated::new(),
}
}
pub fn arrows(&self) -> &ContainedSpan {
&self.arrows
}
pub fn generics(&self) -> &Punctuated<GenericDeclarationParameter> {
&self.generics
}
pub fn with_arrows(self, arrows: ContainedSpan) -> Self {
Self { arrows, ..self }
}
pub fn with_generics(self, generics: Punctuated<GenericDeclarationParameter>) -> Self {
Self { generics, ..self }
}
}
impl Default for GenericDeclaration {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display("{punctuation}{type_info}")]
pub struct TypeSpecifier {
pub(crate) punctuation: TokenReference,
pub(crate) type_info: TypeInfo,
}
impl TypeSpecifier {
pub fn new(type_info: TypeInfo) -> Self {
Self {
punctuation: TokenReference::symbol(": ").unwrap(),
type_info,
}
}
pub fn punctuation(&self) -> &TokenReference {
&self.punctuation
}
pub fn type_info(&self) -> &TypeInfo {
&self.type_info
}
pub fn with_punctuation(self, punctuation: TokenReference) -> Self {
Self {
punctuation,
..self
}
}
pub fn with_type_info(self, type_info: TypeInfo) -> Self {
Self { type_info, ..self }
}
}
#[derive(Clone, Debug, PartialEq, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct TypeArgument {
pub(crate) name: Option<(TokenReference, TokenReference)>,
pub(crate) type_info: TypeInfo,
}
impl TypeArgument {
pub fn new(type_info: TypeInfo) -> Self {
Self {
name: None,
type_info,
}
}
pub fn name(&self) -> Option<&(TokenReference, TokenReference)> {
self.name.as_ref()
}
pub fn type_info(&self) -> &TypeInfo {
&self.type_info
}
pub fn with_name(self, name: Option<(TokenReference, TokenReference)>) -> Self {
Self { name, ..self }
}
pub fn with_type_info(self, type_info: TypeInfo) -> Self {
Self { type_info, ..self }
}
}
impl fmt::Display for TypeArgument {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
if let Some((identifier, punctuation)) = self.name() {
write!(formatter, "{}{}{}", identifier, punctuation, self.type_info)
} else {
write!(formatter, "{}", self.type_info)
}
}
}
#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display("{export_token}{type_declaration}")]
pub struct ExportedTypeDeclaration {
pub(crate) export_token: TokenReference,
pub(crate) type_declaration: TypeDeclaration,
}
impl ExportedTypeDeclaration {
pub fn new(type_declaration: TypeDeclaration) -> Self {
Self {
export_token: TokenReference::new(
vec![],
Token::new(TokenType::Identifier {
identifier: ShortString::new("export"),
}),
vec![Token::new(TokenType::spaces(1))],
),
type_declaration,
}
}
pub fn export_token(&self) -> &TokenReference {
&self.export_token
}
pub fn type_declaration(&self) -> &TypeDeclaration {
&self.type_declaration
}
pub fn with_export_token(self, export_token: TokenReference) -> Self {
Self {
export_token,
..self
}
}
pub fn with_type_declaration(self, type_declaration: TypeDeclaration) -> Self {
Self {
type_declaration,
..self
}
}
}
#[derive(Clone, Debug, Display, PartialEq, Eq, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[non_exhaustive]
#[allow(missing_docs)]
#[display("{_0}")]
pub enum CompoundOp {
PlusEqual(TokenReference),
MinusEqual(TokenReference),
StarEqual(TokenReference),
SlashEqual(TokenReference),
DoubleSlashEqual(TokenReference),
PercentEqual(TokenReference),
CaretEqual(TokenReference),
TwoDotsEqual(TokenReference),
}
impl CompoundOp {
pub fn token(&self) -> &TokenReference {
match self {
Self::PlusEqual(token)
| Self::MinusEqual(token)
| Self::StarEqual(token)
| Self::SlashEqual(token)
| Self::DoubleSlashEqual(token)
| Self::PercentEqual(token)
| Self::CaretEqual(token)
| Self::TwoDotsEqual(token) => token,
}
}
pub(crate) fn from_token(token: TokenReference) -> Self {
if token.is_symbol(Symbol::PlusEqual) {
Self::PlusEqual(token)
} else if token.is_symbol(Symbol::MinusEqual) {
Self::MinusEqual(token)
} else if token.is_symbol(Symbol::StarEqual) {
Self::StarEqual(token)
} else if token.is_symbol(Symbol::SlashEqual) {
Self::SlashEqual(token)
} else if token.is_symbol(Symbol::DoubleSlashEqual) {
Self::DoubleSlashEqual(token)
} else if token.is_symbol(Symbol::PercentEqual) {
Self::PercentEqual(token)
} else if token.is_symbol(Symbol::CaretEqual) {
Self::CaretEqual(token)
} else if token.is_symbol(Symbol::TwoDotsEqual) {
Self::TwoDotsEqual(token)
} else {
unreachable!("converting an unknown token into a compound operator")
}
}
}
#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display("{lhs}{compound_operator}{rhs}")]
pub struct CompoundAssignment {
pub(crate) lhs: Var,
pub(crate) compound_operator: CompoundOp,
pub(crate) rhs: Expression,
}
impl CompoundAssignment {
pub fn new(lhs: Var, compound_operator: CompoundOp, rhs: Expression) -> Self {
Self {
lhs,
compound_operator,
rhs,
}
}
pub fn lhs(&self) -> &Var {
&self.lhs
}
pub fn compound_operator(&self) -> &CompoundOp {
&self.compound_operator
}
pub fn rhs(&self) -> &Expression {
&self.rhs
}
pub fn with_lhs(self, lhs: Var) -> Self {
Self { lhs, ..self }
}
pub fn with_compound_operator(self, compound_operator: CompoundOp) -> Self {
Self {
compound_operator,
..self
}
}
pub fn with_rhs(self, rhs: Expression) -> Self {
Self { rhs, ..self }
}
}
#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display(
"{}{}{}{}{}{}{}",
if_token,
condition,
then_token,
if_expression,
display_option(else_if_expressions.as_ref().map(join_vec)),
else_token,
else_expression
)]
pub struct IfExpression {
pub(crate) if_token: TokenReference,
pub(crate) condition: Box<Expression>,
pub(crate) then_token: TokenReference,
pub(crate) if_expression: Box<Expression>,
pub(crate) else_if_expressions: Option<Vec<ElseIfExpression>>,
pub(crate) else_token: TokenReference,
pub(crate) else_expression: Box<Expression>,
}
impl IfExpression {
pub fn new(
condition: Expression,
if_expression: Expression,
else_expression: Expression,
) -> Self {
Self {
if_token: TokenReference::symbol("if ").unwrap(),
condition: Box::new(condition),
then_token: TokenReference::symbol(" then").unwrap(),
if_expression: Box::new(if_expression),
else_if_expressions: None,
else_token: TokenReference::symbol(" else ").unwrap(),
else_expression: Box::new(else_expression),
}
}
pub fn if_token(&self) -> &TokenReference {
&self.if_token
}
pub fn condition(&self) -> &Expression {
&self.condition
}
pub fn then_token(&self) -> &TokenReference {
&self.then_token
}
pub fn if_expression(&self) -> &Expression {
&self.if_expression
}
pub fn else_token(&self) -> &TokenReference {
&self.else_token
}
pub fn else_if_expressions(&self) -> Option<&Vec<ElseIfExpression>> {
self.else_if_expressions.as_ref()
}
pub fn else_expression(&self) -> &Expression {
&self.else_expression
}
pub fn with_if_token(self, if_token: TokenReference) -> Self {
Self { if_token, ..self }
}
pub fn with_condition(self, condition: Expression) -> Self {
Self {
condition: Box::new(condition),
..self
}
}
pub fn with_then_token(self, then_token: TokenReference) -> Self {
Self { then_token, ..self }
}
pub fn with_if_expression(self, if_expression: Expression) -> Self {
Self {
if_expression: Box::new(if_expression),
..self
}
}
pub fn with_else_if(self, else_if_expressions: Option<Vec<ElseIfExpression>>) -> Self {
Self {
else_if_expressions,
..self
}
}
pub fn with_else_token(self, else_token: TokenReference) -> Self {
Self { else_token, ..self }
}
pub fn with_else(self, else_expression: Expression) -> Self {
Self {
else_expression: Box::new(else_expression),
..self
}
}
}
#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display("{else_if_token}{condition}{then_token}{expression}")]
pub struct ElseIfExpression {
pub(crate) else_if_token: TokenReference,
pub(crate) condition: Expression,
pub(crate) then_token: TokenReference,
pub(crate) expression: Expression,
}
impl ElseIfExpression {
pub fn new(condition: Expression, expression: Expression) -> Self {
Self {
else_if_token: TokenReference::symbol(" elseif ").unwrap(),
condition,
then_token: TokenReference::symbol(" then ").unwrap(),
expression,
}
}
pub fn else_if_token(&self) -> &TokenReference {
&self.else_if_token
}
pub fn condition(&self) -> &Expression {
&self.condition
}
pub fn then_token(&self) -> &TokenReference {
&self.then_token
}
pub fn expression(&self) -> &Expression {
&self.expression
}
pub fn with_else_if_token(self, else_if_token: TokenReference) -> Self {
Self {
else_if_token,
..self
}
}
pub fn with_condition(self, condition: Expression) -> Self {
Self { condition, ..self }
}
pub fn with_then_token(self, then_token: TokenReference) -> Self {
Self { then_token, ..self }
}
pub fn with_block(self, expression: Expression) -> Self {
Self { expression, ..self }
}
}
#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display("{}{}", join_vec(segments), last_string)]
pub struct InterpolatedString {
pub(crate) segments: Vec<InterpolatedStringSegment>,
pub(crate) last_string: TokenReference,
}
impl InterpolatedString {
pub fn new(segments: Vec<InterpolatedStringSegment>, last_string: TokenReference) -> Self {
Self {
segments,
last_string,
}
}
pub fn segments(&self) -> impl Iterator<Item = &InterpolatedStringSegment> {
self.segments.iter()
}
pub fn last_string(&self) -> &TokenReference {
&self.last_string
}
pub fn expressions(&self) -> impl Iterator<Item = &Expression> {
ExpressionsIterator {
segments: &self.segments,
index: 0,
}
}
pub fn with_segments(self, segments: Vec<InterpolatedStringSegment>) -> Self {
Self { segments, ..self }
}
pub fn with_last_string(self, last_string: TokenReference) -> Self {
Self {
last_string,
..self
}
}
}
#[derive(Clone, Debug, Display, PartialEq, Node)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display("{literal}{expression}")]
pub struct InterpolatedStringSegment {
pub literal: TokenReference,
pub expression: Expression,
}
impl Visit for InterpolatedStringSegment {
fn visit<V: crate::visitors::Visitor>(&self, visitor: &mut V) {
self.literal.visit(visitor);
self.expression.visit(visitor);
}
}
impl VisitMut for InterpolatedStringSegment {
fn visit_mut<V: crate::visitors::VisitorMut>(self, visitor: &mut V) -> Self {
Self {
literal: self.literal.visit_mut(visitor),
expression: self.expression.visit_mut(visitor),
}
}
}
struct ExpressionsIterator<'a> {
segments: &'a [InterpolatedStringSegment],
index: usize,
}
impl<'a> Iterator for ExpressionsIterator<'a> {
type Item = &'a Expression;
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.segments.len() {
return None;
}
let segment = &self.segments[self.index];
self.index += 1;
Some(&segment.expression)
}
}