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