1use std::sync::Arc;
2
3use indexmap::IndexMap;
4use serde::{Deserialize, Serialize};
5
6use crate::Union;
7
8#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13pub struct FnParam {
14 pub name: Arc<str>,
15 pub ty: Option<Union>,
16 pub default: Option<Union>,
17 pub is_variadic: bool,
18 pub is_byref: bool,
19 pub is_optional: bool,
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
27pub enum Variance {
28 #[default]
30 Invariant,
31 Covariant,
33 Contravariant,
35}
36
37#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
42pub struct TemplateParam {
43 pub name: Arc<str>,
44 pub bound: Option<Union>,
45 pub variance: Variance,
46}
47
48#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
53pub enum ArrayKey {
54 String(Arc<str>),
55 Int(i64),
56}
57
58#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
59pub struct KeyedProperty {
60 pub ty: Union,
61 pub optional: bool,
62}
63
64#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
69pub enum Atomic {
70 TString,
73 TLiteralString(Arc<str>),
75 TClassString(Option<Arc<str>>),
77 TNonEmptyString,
79 TNumericString,
81
82 TInt,
84 TLiteralInt(i64),
86 TIntRange { min: Option<i64>, max: Option<i64> },
88 TPositiveInt,
90 TNegativeInt,
92 TNonNegativeInt,
94
95 TFloat,
97 TLiteralFloat(i64, i64), TBool,
102 TTrue,
104 TFalse,
106
107 TNull,
109
110 TVoid,
113 TNever,
115 TMixed,
117 TScalar,
119 TNumeric,
121
122 TObject,
125 TNamedObject {
127 fqcn: Arc<str>,
128 type_params: Vec<Union>,
130 },
131 TStaticObject { fqcn: Arc<str> },
133 TSelf { fqcn: Arc<str> },
135 TParent { fqcn: Arc<str> },
137
138 TCallable {
141 params: Option<Vec<FnParam>>,
142 return_type: Option<Box<Union>>,
143 },
144 TClosure {
146 params: Vec<FnParam>,
147 return_type: Box<Union>,
148 this_type: Option<Box<Union>>,
149 },
150
151 TArray { key: Box<Union>, value: Box<Union> },
154 TList { value: Box<Union> },
156 TNonEmptyArray { key: Box<Union>, value: Box<Union> },
158 TNonEmptyList { value: Box<Union> },
160 TKeyedArray {
162 properties: IndexMap<ArrayKey, KeyedProperty>,
163 is_open: bool,
165 is_list: bool,
167 },
168
169 TTemplateParam {
172 name: Arc<str>,
173 as_type: Box<Union>,
174 defining_entity: Arc<str>,
176 },
177 TConditional {
179 subject: Box<Union>,
180 if_true: Box<Union>,
181 if_false: Box<Union>,
182 },
183
184 TInterfaceString,
187 TEnumString,
189 TTraitString,
191}
192
193impl Atomic {
194 pub fn can_be_falsy(&self) -> bool {
196 match self {
197 Atomic::TNull
198 | Atomic::TFalse
199 | Atomic::TBool
200 | Atomic::TNever
201 | Atomic::TLiteralInt(0)
202 | Atomic::TLiteralFloat(0, 0)
203 | Atomic::TInt
204 | Atomic::TFloat
205 | Atomic::TNumeric
206 | Atomic::TScalar
207 | Atomic::TMixed
208 | Atomic::TString
209 | Atomic::TNonEmptyString
210 | Atomic::TArray { .. }
211 | Atomic::TList { .. }
212 | Atomic::TNonEmptyArray { .. }
213 | Atomic::TNonEmptyList { .. } => true,
214
215 Atomic::TLiteralString(s) => s.as_ref().is_empty() || s.as_ref() == "0",
216
217 Atomic::TKeyedArray { properties, .. } => properties.is_empty(),
218
219 _ => false,
220 }
221 }
222
223 pub fn can_be_truthy(&self) -> bool {
225 match self {
226 Atomic::TNever | Atomic::TVoid => false,
227 Atomic::TNull | Atomic::TFalse => false,
228 Atomic::TLiteralInt(0) => false,
229 Atomic::TLiteralFloat(0, 0) => false,
230 Atomic::TLiteralString(s) if s.as_ref() == "" || s.as_ref() == "0" => false,
231 _ => true,
232 }
233 }
234
235 pub fn is_numeric(&self) -> bool {
237 matches!(
238 self,
239 Atomic::TInt
240 | Atomic::TLiteralInt(_)
241 | Atomic::TIntRange { .. }
242 | Atomic::TPositiveInt
243 | Atomic::TNegativeInt
244 | Atomic::TNonNegativeInt
245 | Atomic::TFloat
246 | Atomic::TLiteralFloat(..)
247 | Atomic::TNumeric
248 | Atomic::TNumericString
249 )
250 }
251
252 pub fn is_int(&self) -> bool {
254 matches!(
255 self,
256 Atomic::TInt
257 | Atomic::TLiteralInt(_)
258 | Atomic::TIntRange { .. }
259 | Atomic::TPositiveInt
260 | Atomic::TNegativeInt
261 | Atomic::TNonNegativeInt
262 )
263 }
264
265 pub fn is_string(&self) -> bool {
267 matches!(
268 self,
269 Atomic::TString
270 | Atomic::TLiteralString(_)
271 | Atomic::TClassString(_)
272 | Atomic::TNonEmptyString
273 | Atomic::TNumericString
274 | Atomic::TInterfaceString
275 | Atomic::TEnumString
276 | Atomic::TTraitString
277 )
278 }
279
280 pub fn is_array(&self) -> bool {
282 matches!(
283 self,
284 Atomic::TArray { .. }
285 | Atomic::TList { .. }
286 | Atomic::TNonEmptyArray { .. }
287 | Atomic::TNonEmptyList { .. }
288 | Atomic::TKeyedArray { .. }
289 )
290 }
291
292 pub fn is_object(&self) -> bool {
294 matches!(
295 self,
296 Atomic::TObject
297 | Atomic::TNamedObject { .. }
298 | Atomic::TStaticObject { .. }
299 | Atomic::TSelf { .. }
300 | Atomic::TParent { .. }
301 )
302 }
303
304 pub fn is_callable(&self) -> bool {
306 matches!(self, Atomic::TCallable { .. } | Atomic::TClosure { .. })
307 }
308
309 pub fn named_object_fqcn(&self) -> Option<&str> {
311 match self {
312 Atomic::TNamedObject { fqcn, .. }
313 | Atomic::TStaticObject { fqcn }
314 | Atomic::TSelf { fqcn }
315 | Atomic::TParent { fqcn } => Some(fqcn.as_ref()),
316 _ => None,
317 }
318 }
319
320 pub fn type_name(&self) -> &'static str {
322 match self {
323 Atomic::TString
324 | Atomic::TLiteralString(_)
325 | Atomic::TNonEmptyString
326 | Atomic::TNumericString => "string",
327 Atomic::TClassString(_) => "class-string",
328 Atomic::TInt | Atomic::TLiteralInt(_) | Atomic::TIntRange { .. } => "int",
329 Atomic::TPositiveInt => "positive-int",
330 Atomic::TNegativeInt => "negative-int",
331 Atomic::TNonNegativeInt => "non-negative-int",
332 Atomic::TFloat | Atomic::TLiteralFloat(..) => "float",
333 Atomic::TBool => "bool",
334 Atomic::TTrue => "true",
335 Atomic::TFalse => "false",
336 Atomic::TNull => "null",
337 Atomic::TVoid => "void",
338 Atomic::TNever => "never",
339 Atomic::TMixed => "mixed",
340 Atomic::TScalar => "scalar",
341 Atomic::TNumeric => "numeric",
342 Atomic::TObject => "object",
343 Atomic::TNamedObject { .. } => "object",
344 Atomic::TStaticObject { .. } => "static",
345 Atomic::TSelf { .. } => "self",
346 Atomic::TParent { .. } => "parent",
347 Atomic::TCallable { .. } => "callable",
348 Atomic::TClosure { .. } => "Closure",
349 Atomic::TArray { .. } => "array",
350 Atomic::TList { .. } => "list",
351 Atomic::TNonEmptyArray { .. } => "non-empty-array",
352 Atomic::TNonEmptyList { .. } => "non-empty-list",
353 Atomic::TKeyedArray { .. } => "array",
354 Atomic::TTemplateParam { .. } => "template-param",
355 Atomic::TConditional { .. } => "conditional-type",
356 Atomic::TInterfaceString => "interface-string",
357 Atomic::TEnumString => "enum-string",
358 Atomic::TTraitString => "trait-string",
359 }
360 }
361}