mago_typing/
constant.rs

1use mago_interner::ThreadedInterner;
2use mago_names::ResolvedNames;
3use mago_reflection::CodebaseReflection;
4use mago_reflection::r#type::kind::*;
5use mago_syntax::ast::Identifier;
6use mago_trinary::Trinary;
7use ordered_float::OrderedFloat;
8
9pub struct ConstantTypeResolver<'i, 'c> {
10    interner: &'i ThreadedInterner,
11    names: &'c ResolvedNames,
12    codebase: Option<&'c CodebaseReflection>,
13}
14
15impl<'i, 'c> ConstantTypeResolver<'i, 'c> {
16    pub fn new(
17        interner: &'i ThreadedInterner,
18        names: &'c ResolvedNames,
19        codebase: Option<&'c CodebaseReflection>,
20    ) -> Self {
21        Self { interner, names, codebase }
22    }
23
24    pub fn resolve(&self, constant: &Identifier) -> TypeKind {
25        let (short_name, full_name) = if self.names.is_imported(constant) {
26            let name = self.interner.lookup(self.names.get(constant));
27
28            (name, name)
29        } else {
30            let short_name = self.interner.lookup(constant.value());
31            let imported_name = self.interner.lookup(self.names.get(constant));
32
33            if let Some(stripped) = short_name.strip_prefix('\\') {
34                (stripped, imported_name)
35            } else {
36                (short_name, imported_name)
37            }
38        };
39
40        match short_name {
41            "PHP_VERSION" => non_empty_string_kind(),
42            "PHP_MAJOR_VERSION" => integer_range_kind(7, 9),
43            "PHP_MINOR_VERSION" => non_negative_integer_kind(),
44            "PHP_RELEASE_VERSION" => non_negative_integer_kind(),
45            "PHP_VERSION_ID" => integer_range_kind(70000, 99999),
46            "PHP_ZTS" => union_kind(vec![value_integer_kind(0), value_integer_kind(1)]),
47            "PHP_DEBUG" => union_kind(vec![value_integer_kind(0), value_integer_kind(1)]),
48            "PHP_MAXPATHLEN" => positive_integer_kind(),
49            "PHP_OS" => non_empty_string_kind(),
50            "PHP_OS_FAMILY" => union_kind(vec![
51                value_string_kind(
52                    self.interner.intern("Windows"),
53                    7,
54                    Trinary::False,
55                    Trinary::False,
56                    Trinary::False,
57                    Trinary::False,
58                ),
59                value_string_kind(
60                    self.interner.intern("BSD"),
61                    3,
62                    Trinary::True,
63                    Trinary::True,
64                    Trinary::False,
65                    Trinary::False,
66                ),
67                value_string_kind(
68                    self.interner.intern("Darwin"),
69                    6,
70                    Trinary::False,
71                    Trinary::False,
72                    Trinary::False,
73                    Trinary::False,
74                ),
75                value_string_kind(
76                    self.interner.intern("Linux"),
77                    5,
78                    Trinary::False,
79                    Trinary::False,
80                    Trinary::False,
81                    Trinary::False,
82                ),
83                value_string_kind(
84                    self.interner.intern("Solaris"),
85                    7,
86                    Trinary::False,
87                    Trinary::False,
88                    Trinary::False,
89                    Trinary::False,
90                ),
91                value_string_kind(
92                    self.interner.intern("Unknown"),
93                    7,
94                    Trinary::False,
95                    Trinary::False,
96                    Trinary::False,
97                    Trinary::False,
98                ),
99            ]),
100            "PHP_SAPI" => union_kind(vec![
101                value_string_kind(
102                    self.interner.intern("apache"),
103                    6,
104                    Trinary::False,
105                    Trinary::False,
106                    Trinary::True,
107                    Trinary::True,
108                ),
109                value_string_kind(
110                    self.interner.intern("apache2handler"),
111                    14,
112                    Trinary::False,
113                    Trinary::False,
114                    Trinary::True,
115                    Trinary::True,
116                ),
117                value_string_kind(
118                    self.interner.intern("cgi"),
119                    3,
120                    Trinary::False,
121                    Trinary::False,
122                    Trinary::True,
123                    Trinary::True,
124                ),
125                value_string_kind(
126                    self.interner.intern("cli"),
127                    3,
128                    Trinary::False,
129                    Trinary::False,
130                    Trinary::True,
131                    Trinary::True,
132                ),
133                value_string_kind(
134                    self.interner.intern("cli-server"),
135                    10,
136                    Trinary::False,
137                    Trinary::False,
138                    Trinary::True,
139                    Trinary::True,
140                ),
141                value_string_kind(
142                    self.interner.intern("embed"),
143                    5,
144                    Trinary::False,
145                    Trinary::False,
146                    Trinary::True,
147                    Trinary::True,
148                ),
149                value_string_kind(
150                    self.interner.intern("fpm-fcgi"),
151                    8,
152                    Trinary::False,
153                    Trinary::False,
154                    Trinary::True,
155                    Trinary::True,
156                ),
157                value_string_kind(
158                    self.interner.intern("litespeed"),
159                    9,
160                    Trinary::False,
161                    Trinary::False,
162                    Trinary::True,
163                    Trinary::True,
164                ),
165                value_string_kind(
166                    self.interner.intern("phpdbg"),
167                    6,
168                    Trinary::False,
169                    Trinary::False,
170                    Trinary::True,
171                    Trinary::True,
172                ),
173                non_empty_string_kind(),
174            ]),
175            "PHP_EOL" => union_kind(vec![
176                value_string_kind(
177                    self.interner.intern("\n"),
178                    1,
179                    Trinary::False,
180                    Trinary::False,
181                    Trinary::False,
182                    Trinary::False,
183                ),
184                value_string_kind(
185                    self.interner.intern("\r\n"),
186                    2,
187                    Trinary::False,
188                    Trinary::False,
189                    Trinary::False,
190                    Trinary::False,
191                ),
192            ]),
193            "PHP_INT_MAX" => union_kind(vec![value_integer_kind(9223372036854775807), value_integer_kind(2147483647)]),
194            "PHP_INT_MIN" => {
195                union_kind(vec![value_integer_kind(-9223372036854775808), value_integer_kind(-2147483648)])
196            }
197            "PHP_INT_SIZE" => union_kind(vec![value_integer_kind(4), value_integer_kind(8)]),
198            "PHP_FLOAT_DIG" => positive_integer_kind(),
199            "PHP_FLOAT_EPSILON" => union_kind(vec![
200                value_float_kind(OrderedFloat(2.220_446_049_250_313e-16)),
201                value_float_kind(OrderedFloat(1.19209290e-7)),
202            ]),
203            "PHP_EXTENSION_DIR" => non_empty_string_kind(),
204            "PHP_PREFIX" => non_empty_string_kind(),
205            "PHP_BINDIR" => non_empty_string_kind(),
206            "PHP_BINARY" => non_empty_string_kind(),
207            "PHP_MANDIR" => non_empty_string_kind(),
208            "PHP_LIBDIR" => non_empty_string_kind(),
209            "PHP_DATADIR" => non_empty_string_kind(),
210            "PHP_SYSCONFDIR" => non_empty_string_kind(),
211            "PHP_LOCALSTATEDIR" => non_empty_string_kind(),
212            "PHP_CONFIG_FILE_PATH" => non_empty_string_kind(),
213            "PHP_SHLIB_SUFFIX" => union_kind(vec![
214                value_string_kind(
215                    self.interner.intern("so"),
216                    2,
217                    Trinary::False,
218                    Trinary::False,
219                    Trinary::True,
220                    Trinary::True,
221                ),
222                value_string_kind(
223                    self.interner.intern("dll"),
224                    3,
225                    Trinary::False,
226                    Trinary::False,
227                    Trinary::True,
228                    Trinary::True,
229                ),
230            ]),
231            "PHP_FD_SETSIZE" => positive_integer_kind(),
232            "PHP_WINDOWS_VERSION_MAJOR" => union_kind(vec![
233                value_integer_kind(4), // NT4/Me/98/95
234                value_integer_kind(5), // XP/2003 R2/2003/2000
235                value_integer_kind(6), // Vista/2008/7/8/8.1
236            ]),
237            "PHP_WINDOWS_VERSION_MINOR" => union_kind(vec![
238                value_integer_kind(0),  // Vista/2008/2000/NT4/95
239                value_integer_kind(1),  // XP
240                value_integer_kind(2),  // 2003 R2/2003/XP x64
241                value_integer_kind(10), // 98
242                value_integer_kind(90), // Me
243            ]),
244            "PHP_WINDOWS_VERSION_BUILD" => positive_integer_kind(),
245            "DIRECTORY_SEPARATOR" => union_kind(vec![
246                value_string_kind(
247                    self.interner.intern("/"),
248                    1,
249                    Trinary::False,
250                    Trinary::False,
251                    Trinary::False,
252                    Trinary::False,
253                ),
254                value_string_kind(
255                    self.interner.intern("\\"),
256                    1,
257                    Trinary::False,
258                    Trinary::False,
259                    Trinary::False,
260                    Trinary::False,
261                ),
262            ]),
263            "PATH_SEPARATOR" => union_kind(vec![
264                value_string_kind(
265                    self.interner.intern(";"),
266                    1,
267                    Trinary::False,
268                    Trinary::False,
269                    Trinary::False,
270                    Trinary::False,
271                ),
272                value_string_kind(
273                    self.interner.intern(":"),
274                    1,
275                    Trinary::False,
276                    Trinary::False,
277                    Trinary::False,
278                    Trinary::False,
279                ),
280            ]),
281            "ICONV_IMPL" => non_empty_string_kind(),
282            "LIBXML_VERSION" => positive_integer_kind(),
283            "LIBXML_DOTTED_VERSION" => non_empty_string_kind(),
284            "OPENSSL_VERSION_NUMBER" => positive_integer_kind(),
285            "PCRE_VERSION" => non_empty_string_kind(),
286            "STDIN" | "STDOUT" | "STDERR" => resource_kind(),
287            "NAN" => value_float_kind(OrderedFloat(f64::NAN)),
288            "INF" => value_float_kind(OrderedFloat(f64::INFINITY)),
289            _ => {
290                if let Some(codebase) = self.codebase {
291                    let short_name_id = self.interner.intern(short_name);
292                    let full_name_id = self.interner.intern(full_name);
293
294                    let Some(constant) = codebase
295                        .get_constant(self.interner, &full_name_id)
296                        .or_else(|| codebase.get_constant(self.interner, &short_name_id))
297                    else {
298                        return mixed_kind(false);
299                    };
300
301                    constant.type_reflection.kind.clone()
302                } else {
303                    mixed_kind(false)
304                }
305            }
306        }
307    }
308}