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::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}