Skip to main content

mir_types/
display.rs

1use std::fmt;
2
3use crate::atomic::Atomic;
4use crate::union::Union;
5
6impl fmt::Display for Union {
7    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
8        if self.types.is_empty() {
9            return write!(f, "never");
10        }
11        let strs: Vec<String> = self.types.iter().map(|a| format!("{a}")).collect();
12        write!(f, "{}", strs.join("|"))
13    }
14}
15
16impl fmt::Display for Atomic {
17    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18        match self {
19            Atomic::TString => write!(f, "string"),
20            Atomic::TLiteralString(s) => write!(f, "\"{s}\""),
21            Atomic::TClassString(None) => write!(f, "class-string"),
22            Atomic::TClassString(Some(cls)) => write!(f, "class-string<{cls}>"),
23            Atomic::TNonEmptyString => write!(f, "non-empty-string"),
24            Atomic::TNumericString => write!(f, "numeric-string"),
25
26            Atomic::TInt => write!(f, "int"),
27            Atomic::TLiteralInt(n) => write!(f, "{n}"),
28            Atomic::TIntRange { min, max } => {
29                let lo = min.map_or_else(|| "min".to_string(), |n| n.to_string());
30                let hi = max.map_or_else(|| "max".to_string(), |n| n.to_string());
31                write!(f, "int<{lo}, {hi}>")
32            }
33            Atomic::TPositiveInt => write!(f, "positive-int"),
34            Atomic::TNegativeInt => write!(f, "negative-int"),
35            Atomic::TNonNegativeInt => write!(f, "non-negative-int"),
36
37            Atomic::TFloat => write!(f, "float"),
38            Atomic::TLiteralFloat(i, frac) => write!(f, "{i}.{frac}"),
39
40            Atomic::TBool => write!(f, "bool"),
41            Atomic::TTrue => write!(f, "true"),
42            Atomic::TFalse => write!(f, "false"),
43
44            Atomic::TNull => write!(f, "null"),
45            Atomic::TVoid => write!(f, "void"),
46            Atomic::TNever => write!(f, "never"),
47            Atomic::TMixed => write!(f, "mixed"),
48            Atomic::TScalar => write!(f, "scalar"),
49            Atomic::TNumeric => write!(f, "numeric"),
50
51            Atomic::TObject => write!(f, "object"),
52            Atomic::TNamedObject { fqcn, type_params } => {
53                if type_params.is_empty() {
54                    write!(f, "{fqcn}")
55                } else {
56                    let params: Vec<String> = type_params.iter().map(|p| format!("{p}")).collect();
57                    write!(f, "{}<{}>", fqcn, params.join(", "))
58                }
59            }
60            Atomic::TStaticObject { fqcn } => write!(f, "static({fqcn})"),
61            Atomic::TSelf { fqcn } => write!(f, "self({fqcn})"),
62            Atomic::TParent { fqcn } => write!(f, "parent({fqcn})"),
63
64            Atomic::TCallable {
65                params: None,
66                return_type: None,
67            } => write!(f, "callable"),
68            Atomic::TCallable {
69                params: Some(params),
70                return_type,
71            } => {
72                let ps: Vec<String> = params
73                    .iter()
74                    .map(|p| {
75                        if let Some(ty) = &p.ty {
76                            format!("{ty}")
77                        } else {
78                            "mixed".to_string()
79                        }
80                    })
81                    .collect();
82                let ret = return_type
83                    .as_ref()
84                    .map_or_else(|| "mixed".to_string(), |r| format!("{r}"));
85                write!(f, "callable({}): {}", ps.join(", "), ret)
86            }
87            Atomic::TCallable {
88                params: None,
89                return_type: Some(ret),
90            } => {
91                write!(f, "callable(): {ret}")
92            }
93            Atomic::TClosure {
94                params,
95                return_type,
96                ..
97            } => {
98                let ps: Vec<String> = params
99                    .iter()
100                    .map(|p| {
101                        if let Some(ty) = &p.ty {
102                            format!("{ty}")
103                        } else {
104                            "mixed".to_string()
105                        }
106                    })
107                    .collect();
108                write!(f, "Closure({}): {}", ps.join(", "), return_type)
109            }
110
111            Atomic::TArray { key, value } => {
112                write!(f, "array<{key}, {value}>")
113            }
114            Atomic::TList { value } => write!(f, "list<{value}>"),
115            Atomic::TNonEmptyArray { key, value } => {
116                write!(f, "non-empty-array<{key}, {value}>")
117            }
118            Atomic::TNonEmptyList { value } => write!(f, "non-empty-list<{value}>"),
119            Atomic::TKeyedArray { properties, .. } => {
120                let entries: Vec<String> = properties
121                    .iter()
122                    .map(|(k, v)| {
123                        let key_str = match k {
124                            crate::atomic::ArrayKey::String(s) => format!("'{s}'"),
125                            crate::atomic::ArrayKey::Int(n) => n.to_string(),
126                        };
127                        let opt = if v.optional { "?" } else { "" };
128                        format!("{}{}: {}", key_str, opt, v.ty)
129                    })
130                    .collect();
131                write!(f, "array{{{}}}", entries.join(", "))
132            }
133
134            Atomic::TTemplateParam { name, .. } => write!(f, "{name}"),
135            Atomic::TConditional {
136                subject,
137                if_true,
138                if_false,
139            } => {
140                write!(f, "({subject} is ? {if_true} : {if_false})")
141            }
142
143            Atomic::TInterfaceString => write!(f, "interface-string"),
144            Atomic::TEnumString => write!(f, "enum-string"),
145            Atomic::TTraitString => write!(f, "trait-string"),
146
147            Atomic::TIntersection { parts } => {
148                let mut iter = parts.iter();
149                if let Some(first) = iter.next() {
150                    write!(f, "{first}")?;
151                    for part in iter {
152                        write!(f, "&{part}")?;
153                    }
154                }
155                Ok(())
156            }
157        }
158    }
159}