1use serde::Serialize;
2use strum::Display;
3
4use mago_span::HasSpan;
5use mago_span::Span;
6
7use crate::ast::Type;
8use crate::ast::keyword::Keyword;
9
10#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord, Display)]
11#[serde(tag = "type", content = "value")]
12pub enum CallableTypeKind {
13 Callable,
14 PureCallable,
15 Closure,
16 PureClosure,
17}
18
19#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
20#[repr(C)]
21pub struct CallableType<'input> {
22 pub kind: CallableTypeKind,
23 pub keyword: Keyword<'input>,
24 pub specification: Option<CallableTypeSpecification<'input>>,
25}
26
27#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
28#[repr(C)]
29pub struct CallableTypeSpecification<'input> {
30 pub parameters: CallableTypeParameters<'input>,
31 pub return_type: Option<CallableTypeReturnType<'input>>,
32}
33
34#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
35#[repr(C)]
36pub struct CallableTypeParameters<'input> {
37 pub left_parenthesis: Span,
38 pub entries: Vec<CallableTypeParameter<'input>>,
39 pub right_parenthesis: Span,
40}
41
42#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
43#[repr(C)]
44pub struct CallableTypeParameter<'input> {
45 pub parameter_type: Box<Type<'input>>,
46 pub equals: Option<Span>,
47 pub ellipsis: Option<Span>,
48 pub comma: Option<Span>,
49}
50
51#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
52#[repr(C)]
53pub struct CallableTypeReturnType<'input> {
54 pub colon: Span,
55 pub return_type: Box<Type<'input>>,
56}
57
58impl CallableTypeKind {
59 #[inline]
60 pub fn is_pure(&self) -> bool {
61 matches!(self, CallableTypeKind::PureCallable | CallableTypeKind::PureClosure)
62 }
63
64 #[inline]
65 pub fn is_closure(&self) -> bool {
66 matches!(self, CallableTypeKind::Closure | CallableTypeKind::PureClosure)
67 }
68}
69
70impl CallableTypeParameter<'_> {
71 #[inline]
72 pub const fn is_variadic(&self) -> bool {
73 self.ellipsis.is_some()
74 }
75
76 #[inline]
77 pub const fn is_optional(&self) -> bool {
78 self.equals.is_some()
79 }
80}
81
82impl HasSpan for CallableType<'_> {
83 fn span(&self) -> Span {
84 match &self.specification {
85 Some(specification) => self.keyword.span.join(specification.span()),
86 None => self.keyword.span,
87 }
88 }
89}
90
91impl HasSpan for CallableTypeSpecification<'_> {
92 fn span(&self) -> Span {
93 match &self.return_type {
94 Some(return_type) => self.parameters.span().join(return_type.span()),
95 None => self.parameters.span(),
96 }
97 }
98}
99
100impl HasSpan for CallableTypeParameters<'_> {
101 fn span(&self) -> Span {
102 self.left_parenthesis.join(self.right_parenthesis)
103 }
104}
105
106impl HasSpan for CallableTypeParameter<'_> {
107 fn span(&self) -> Span {
108 match &self.comma {
109 Some(comma) => self.parameter_type.span().join(*comma),
110 None => match &self.ellipsis {
111 Some(ellipsis) => self.parameter_type.span().join(*ellipsis),
112 None => match &self.equals {
113 Some(equals) => self.parameter_type.span().join(*equals),
114 None => self.parameter_type.span(),
115 },
116 },
117 }
118 }
119}
120
121impl HasSpan for CallableTypeReturnType<'_> {
122 fn span(&self) -> Span {
123 self.colon.join(self.return_type.span())
124 }
125}
126
127impl std::fmt::Display for CallableTypeReturnType<'_> {
128 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129 write!(f, ": {}", self.return_type)
130 }
131}
132
133impl std::fmt::Display for CallableTypeParameter<'_> {
134 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
135 write!(f, "{}", self.parameter_type)?;
136 if self.equals.is_some() {
137 write!(f, "=")?;
138 } else if self.ellipsis.is_some() {
139 write!(f, "...")?;
140 }
141
142 Ok(())
143 }
144}
145
146impl std::fmt::Display for CallableTypeParameters<'_> {
147 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
148 write!(f, "(")?;
149 for (i, entry) in self.entries.iter().enumerate() {
150 if i > 0 {
151 write!(f, ", ")?;
152 }
153 write!(f, "{entry}")?;
154 }
155 write!(f, ")")?;
156 Ok(())
157 }
158}
159
160impl std::fmt::Display for CallableTypeSpecification<'_> {
161 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
162 write!(f, "{}", self.parameters)?;
163 if let Some(return_type) = &self.return_type {
164 write!(f, "{return_type}")?;
165 }
166 Ok(())
167 }
168}
169
170impl std::fmt::Display for CallableType<'_> {
171 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172 write!(f, "{}", self.keyword)?;
173 if let Some(specification) = &self.specification {
174 write!(f, "{specification}")?;
175 }
176 Ok(())
177 }
178}