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, PartialEq, Serialize, Deserialize)]
27pub struct TemplateParam {
28 pub name: Arc<str>,
29 pub bound: Option<Union>,
30}
31
32#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
37pub enum ArrayKey {
38 String(Arc<str>),
39 Int(i64),
40}
41
42#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
43pub struct KeyedProperty {
44 pub ty: Union,
45 pub optional: bool,
46}
47
48#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
53pub enum Atomic {
54 TString,
57 TLiteralString(Arc<str>),
59 TClassString(Option<Arc<str>>),
61 TNonEmptyString,
63 TNumericString,
65
66 TInt,
68 TLiteralInt(i64),
70 TIntRange { min: Option<i64>, max: Option<i64> },
72 TPositiveInt,
74 TNegativeInt,
76 TNonNegativeInt,
78
79 TFloat,
81 TLiteralFloat(i64, i64), TBool,
86 TTrue,
88 TFalse,
90
91 TNull,
93
94 TVoid,
97 TNever,
99 TMixed,
101 TScalar,
103 TNumeric,
105
106 TObject,
109 TNamedObject {
111 fqcn: Arc<str>,
112 type_params: Vec<Union>,
114 },
115 TStaticObject { fqcn: Arc<str> },
117 TSelf { fqcn: Arc<str> },
119 TParent { fqcn: Arc<str> },
121
122 TCallable {
125 params: Option<Vec<FnParam>>,
126 return_type: Option<Box<Union>>,
127 },
128 TClosure {
130 params: Vec<FnParam>,
131 return_type: Box<Union>,
132 this_type: Option<Box<Union>>,
133 },
134
135 TArray { key: Box<Union>, value: Box<Union> },
138 TList { value: Box<Union> },
140 TNonEmptyArray { key: Box<Union>, value: Box<Union> },
142 TNonEmptyList { value: Box<Union> },
144 TKeyedArray {
146 properties: IndexMap<ArrayKey, KeyedProperty>,
147 is_open: bool,
149 is_list: bool,
151 },
152
153 TTemplateParam {
156 name: Arc<str>,
157 as_type: Box<Union>,
158 defining_entity: Arc<str>,
160 },
161 TConditional {
163 subject: Box<Union>,
164 if_true: Box<Union>,
165 if_false: Box<Union>,
166 },
167
168 TInterfaceString,
171 TEnumString,
173 TTraitString,
175}
176
177impl Atomic {
178 pub fn can_be_falsy(&self) -> bool {
180 match self {
181 Atomic::TNull
182 | Atomic::TFalse
183 | Atomic::TBool
184 | Atomic::TNever
185 | Atomic::TLiteralInt(0)
186 | Atomic::TLiteralFloat(0, 0)
187 | Atomic::TInt
188 | Atomic::TFloat
189 | Atomic::TNumeric
190 | Atomic::TScalar
191 | Atomic::TMixed
192 | Atomic::TString
193 | Atomic::TNonEmptyString
194 | Atomic::TArray { .. }
195 | Atomic::TList { .. }
196 | Atomic::TNonEmptyArray { .. }
197 | Atomic::TNonEmptyList { .. } => true,
198
199 Atomic::TLiteralString(s) => s.as_ref().is_empty() || s.as_ref() == "0",
200
201 Atomic::TKeyedArray { properties, .. } => properties.is_empty(),
202
203 _ => false,
204 }
205 }
206
207 pub fn can_be_truthy(&self) -> bool {
209 match self {
210 Atomic::TNever | Atomic::TVoid => false,
211 Atomic::TNull | Atomic::TFalse => false,
212 Atomic::TLiteralInt(0) => false,
213 Atomic::TLiteralFloat(0, 0) => false,
214 Atomic::TLiteralString(s) if s.as_ref() == "" || s.as_ref() == "0" => false,
215 _ => true,
216 }
217 }
218
219 pub fn is_numeric(&self) -> bool {
221 matches!(
222 self,
223 Atomic::TInt
224 | Atomic::TLiteralInt(_)
225 | Atomic::TIntRange { .. }
226 | Atomic::TPositiveInt
227 | Atomic::TNegativeInt
228 | Atomic::TNonNegativeInt
229 | Atomic::TFloat
230 | Atomic::TLiteralFloat(..)
231 | Atomic::TNumeric
232 | Atomic::TNumericString
233 )
234 }
235
236 pub fn is_int(&self) -> bool {
238 matches!(
239 self,
240 Atomic::TInt
241 | Atomic::TLiteralInt(_)
242 | Atomic::TIntRange { .. }
243 | Atomic::TPositiveInt
244 | Atomic::TNegativeInt
245 | Atomic::TNonNegativeInt
246 )
247 }
248
249 pub fn is_string(&self) -> bool {
251 matches!(
252 self,
253 Atomic::TString
254 | Atomic::TLiteralString(_)
255 | Atomic::TClassString(_)
256 | Atomic::TNonEmptyString
257 | Atomic::TNumericString
258 | Atomic::TInterfaceString
259 | Atomic::TEnumString
260 | Atomic::TTraitString
261 )
262 }
263
264 pub fn is_array(&self) -> bool {
266 matches!(
267 self,
268 Atomic::TArray { .. }
269 | Atomic::TList { .. }
270 | Atomic::TNonEmptyArray { .. }
271 | Atomic::TNonEmptyList { .. }
272 | Atomic::TKeyedArray { .. }
273 )
274 }
275
276 pub fn is_object(&self) -> bool {
278 matches!(
279 self,
280 Atomic::TObject
281 | Atomic::TNamedObject { .. }
282 | Atomic::TStaticObject { .. }
283 | Atomic::TSelf { .. }
284 | Atomic::TParent { .. }
285 )
286 }
287
288 pub fn is_callable(&self) -> bool {
290 matches!(self, Atomic::TCallable { .. } | Atomic::TClosure { .. })
291 }
292
293 pub fn named_object_fqcn(&self) -> Option<&str> {
295 match self {
296 Atomic::TNamedObject { fqcn, .. }
297 | Atomic::TStaticObject { fqcn }
298 | Atomic::TSelf { fqcn }
299 | Atomic::TParent { fqcn } => Some(fqcn.as_ref()),
300 _ => None,
301 }
302 }
303
304 pub fn type_name(&self) -> &'static str {
306 match self {
307 Atomic::TString
308 | Atomic::TLiteralString(_)
309 | Atomic::TNonEmptyString
310 | Atomic::TNumericString => "string",
311 Atomic::TClassString(_) => "class-string",
312 Atomic::TInt | Atomic::TLiteralInt(_) | Atomic::TIntRange { .. } => "int",
313 Atomic::TPositiveInt => "positive-int",
314 Atomic::TNegativeInt => "negative-int",
315 Atomic::TNonNegativeInt => "non-negative-int",
316 Atomic::TFloat | Atomic::TLiteralFloat(..) => "float",
317 Atomic::TBool => "bool",
318 Atomic::TTrue => "true",
319 Atomic::TFalse => "false",
320 Atomic::TNull => "null",
321 Atomic::TVoid => "void",
322 Atomic::TNever => "never",
323 Atomic::TMixed => "mixed",
324 Atomic::TScalar => "scalar",
325 Atomic::TNumeric => "numeric",
326 Atomic::TObject => "object",
327 Atomic::TNamedObject { .. } => "object",
328 Atomic::TStaticObject { .. } => "static",
329 Atomic::TSelf { .. } => "self",
330 Atomic::TParent { .. } => "parent",
331 Atomic::TCallable { .. } => "callable",
332 Atomic::TClosure { .. } => "Closure",
333 Atomic::TArray { .. } => "array",
334 Atomic::TList { .. } => "list",
335 Atomic::TNonEmptyArray { .. } => "non-empty-array",
336 Atomic::TNonEmptyList { .. } => "non-empty-list",
337 Atomic::TKeyedArray { .. } => "array",
338 Atomic::TTemplateParam { .. } => "template-param",
339 Atomic::TConditional { .. } => "conditional-type",
340 Atomic::TInterfaceString => "interface-string",
341 Atomic::TEnumString => "enum-string",
342 Atomic::TTraitString => "trait-string",
343 }
344 }
345}