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}