mago_type_syntax/ast/
callable.rs

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