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, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display("{}{}{}{}", type_token, function_token, function_name, function_body)]
pub struct TypeFunction {
pub(crate) type_token: TokenReference,
pub(crate) function_token: TokenReference,
pub(crate) function_name: TokenReference,
pub(crate) function_body: FunctionBody,
}
impl TypeFunction {
pub fn new(function_name: TokenReference, function_body: FunctionBody) -> Self {
Self {
type_token: TokenReference::new(
Vec::new(),
Token::new(TokenType::Identifier {
identifier: "type".into(),
}),
vec![Token::new(TokenType::spaces(1))],
),
function_token: TokenReference::basic_symbol("function "),
function_name,
function_body,
}
}
pub fn type_token(&self) -> &TokenReference {
&self.type_token
}
pub fn function_token(&self) -> &TokenReference {
&self.function_token
}
pub fn function_name(&self) -> &TokenReference {
&self.function_name
}
pub fn function_body(&self) -> &FunctionBody {
&self.function_body
}
pub fn with_type_token(self, type_token: TokenReference) -> Self {
Self { type_token, ..self }
}
pub fn with_function_token(self, function_token: TokenReference) -> Self {
Self {
function_token,
..self
}
}
pub fn with_function_name(self, function_name: TokenReference) -> Self {
Self {
function_name,
..self
}
}
pub fn with_function_body(self, function_body: FunctionBody) -> Self {
Self {
function_body,
..self
}
}
}
#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display("{export_token}{type_function}")]
pub struct ExportedTypeFunction {
pub(crate) export_token: TokenReference,
pub(crate) type_function: TypeFunction,
}
impl ExportedTypeFunction {
pub fn new(type_function: TypeFunction) -> Self {
Self {
export_token: TokenReference::new(
vec![],
Token::new(TokenType::Identifier {
identifier: ShortString::new("export"),
}),
vec![Token::new(TokenType::spaces(1))],
),
type_function,
}
}
pub fn export_token(&self) -> &TokenReference {
&self.export_token
}
pub fn type_function(&self) -> &TypeFunction {
&self.type_function
}
pub fn with_export_token(self, export_token: TokenReference) -> Self {
Self {
export_token,
..self
}
}
pub fn with_type_function(self, type_function: TypeFunction) -> Self {
Self {
type_function,
..self
}
}
}
#[derive(Clone, Debug, PartialEq, Node)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct ConstAssignment {
pub(crate) const_token: TokenReference,
#[cfg_attr(
feature = "serde",
serde(skip_serializing_if = "empty_optional_vector")
)]
pub(crate) type_specifiers: Vec<Option<TypeSpecifier>>,
pub(crate) name_list: Punctuated<TokenReference>,
pub(crate) equal_token: Option<TokenReference>,
pub(crate) expr_list: Punctuated<Expression>,
}
impl ConstAssignment {
pub fn new(name_list: Punctuated<TokenReference>) -> Self {
Self {
const_token: TokenReference::new(
Vec::new(),
Token::new(TokenType::Identifier {
identifier: "const".into(),
}),
vec![Token::new(TokenType::spaces(1))],
),
type_specifiers: Vec::new(),
name_list,
equal_token: None,
expr_list: Punctuated::new(),
}
}
pub fn const_token(&self) -> &TokenReference {
&self.const_token
}
pub fn equal_token(&self) -> Option<&TokenReference> {
self.equal_token.as_ref()
}
pub fn expressions(&self) -> &Punctuated<Expression> {
&self.expr_list
}
pub fn names(&self) -> &Punctuated<TokenReference> {
&self.name_list
}
pub fn type_specifiers(&self) -> impl Iterator<Item = Option<&TypeSpecifier>> {
self.type_specifiers.iter().map(Option::as_ref)
}
pub fn with_const_token(self, const_token: TokenReference) -> Self {
Self {
const_token,
..self
}
}
pub fn with_type_specifiers(self, type_specifiers: Vec<Option<TypeSpecifier>>) -> Self {
Self {
type_specifiers,
..self
}
}
pub fn with_names(self, name_list: Punctuated<TokenReference>) -> Self {
Self { name_list, ..self }
}
pub fn with_equal_token(self, equal_token: Option<TokenReference>) -> Self {
Self {
equal_token,
..self
}
}
pub fn with_expressions(self, expr_list: Punctuated<Expression>) -> Self {
Self { expr_list, ..self }
}
}
impl fmt::Display for ConstAssignment {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(
formatter,
"{}{}{}{}",
self.const_token,
join_type_specifiers(&self.name_list, self.type_specifiers()),
display_option(&self.equal_token),
self.expr_list
)
}
}
#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display(
"{}{}{}{}{}",
join_vec(attributes),
const_token,
function_token,
name,
body
)]
pub struct ConstFunction {
pub(crate) attributes: Vec<LuauAttribute>,
pub(crate) const_token: TokenReference,
pub(crate) function_token: TokenReference,
pub(crate) name: TokenReference,
pub(crate) body: FunctionBody,
}
impl ConstFunction {
pub fn new(name: TokenReference) -> Self {
ConstFunction {
attributes: Vec::new(),
const_token: TokenReference::new(
Vec::new(),
Token::new(TokenType::Identifier {
identifier: "const".into(),
}),
vec![Token::new(TokenType::spaces(1))],
),
function_token: TokenReference::basic_symbol("function "),
name,
body: FunctionBody::new(),
}
}
pub fn attributes(&self) -> impl Iterator<Item = &LuauAttribute> {
self.attributes.iter()
}
pub fn const_token(&self) -> &TokenReference {
&self.const_token
}
pub fn function_token(&self) -> &TokenReference {
&self.function_token
}
pub fn body(&self) -> &FunctionBody {
&self.body
}
pub fn name(&self) -> &TokenReference {
&self.name
}
pub fn with_attributes(self, attributes: Vec<LuauAttribute>) -> Self {
Self { attributes, ..self }
}
pub fn with_const_token(self, const_token: TokenReference) -> Self {
Self {
const_token,
..self
}
}
pub fn with_function_token(self, function_token: TokenReference) -> Self {
Self {
function_token,
..self
}
}
pub fn with_name(self, name: TokenReference) -> Self {
Self { name, ..self }
}
pub fn with_body(self, body: FunctionBody) -> Self {
Self { body, ..self }
}
}
#[cfg(not(feature = "luau"))]
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
#[deprecated(
note = "CompoundAssignment has been moved to full_moon::ast::compound::CompoundAssignment"
)]
pub type CompoundAssignment = crate::ast::compound::CompoundAssignment;
#[cfg(not(feature = "luau"))]
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
#[deprecated(note = "CompoundOp has been moved to full_moon::ast::compound::CompoundOp")]
pub type CompoundOp = crate::ast::compound::CompoundOp;
#[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)
}
}
#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display("{at_sign}{name}")]
pub struct LuauAttribute {
pub(crate) at_sign: TokenReference,
pub(crate) name: TokenReference,
}
impl LuauAttribute {
pub fn new(name: TokenReference) -> Self {
Self {
at_sign: TokenReference::symbol("@").unwrap(),
name,
}
}
pub fn at_sign(&self) -> &TokenReference {
&self.at_sign
}
pub fn name(&self) -> &TokenReference {
&self.name
}
pub fn with_at_sign(self, at_sign: TokenReference) -> Self {
Self { at_sign, ..self }
}
pub fn with_name(self, name: TokenReference) -> Self {
Self { name, ..self }
}
}
#[derive(Clone, Debug, Display, PartialEq, Node)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display(
"{}{}{}{}{}",
outer_arrows.tokens().0,
inner_arrows.tokens().0,
types,
inner_arrows.tokens().1,
outer_arrows.tokens().1
)]
pub struct TypeInstantiation {
#[node(full_range)]
pub(crate) outer_arrows: ContainedSpan,
pub(crate) inner_arrows: ContainedSpan,
pub(crate) types: Punctuated<TypeInfo>,
}
impl Default for TypeInstantiation {
fn default() -> Self {
Self::new()
}
}
impl TypeInstantiation {
pub fn new() -> Self {
Self {
outer_arrows: ContainedSpan::new(
TokenReference::symbol("<").unwrap(),
TokenReference::symbol(">").unwrap(),
),
inner_arrows: ContainedSpan::new(
TokenReference::symbol("<").unwrap(),
TokenReference::symbol(">").unwrap(),
),
types: Punctuated::new(),
}
}
pub fn outer_arrows(&self) -> &ContainedSpan {
&self.outer_arrows
}
pub fn inner_arrows(&self) -> &ContainedSpan {
&self.inner_arrows
}
pub fn types(&self) -> &Punctuated<TypeInfo> {
&self.types
}
pub fn with_outer_arrows(self, outer_arrows: ContainedSpan) -> Self {
Self {
outer_arrows,
..self
}
}
pub fn with_inner_arrows(self, inner_arrows: ContainedSpan) -> Self {
Self {
inner_arrows,
..self
}
}
pub fn with_types(self, types: Punctuated<TypeInfo>) -> Self {
Self { types, ..self }
}
}