ara_parser/parser/internal/
identifier.rs

1use crate::lexer::token::TokenKind;
2use crate::parser::internal::definition::template;
3use crate::parser::result::ParseResult;
4use crate::parser::state::State;
5use crate::tree::identifier::Identifier;
6use crate::tree::identifier::TemplatedIdentifier;
7
8/// Expect an identifier such as `Foo`, `Foo\Bar` for a namespace name.
9///
10/// The identifier can be either a simple identifier or a qualified identifier.
11/// The identifier can be a reserved keyword.
12#[inline(always)]
13pub fn namespace_identifier(state: &mut State) -> ParseResult<Identifier> {
14    let current = state.iterator.current();
15
16    match &current.kind {
17        TokenKind::Identifier | TokenKind::QualifiedIdentifier => {
18            let position = current.position;
19
20            state.iterator.next();
21
22            Ok(Identifier {
23                position,
24                value: current.value.clone(),
25            })
26        }
27        _ if is_reserved_identifier(&current.kind) => {
28            let name = current.to_string().into();
29            let position = current.position;
30            state.iterator.next();
31
32            Ok(Identifier {
33                position,
34                value: name,
35            })
36        }
37        _ => {
38            crate::parser_bail!(
39                state,
40                unexpected_token(vec!["an identifier".to_owned()], current)
41            )
42        }
43    }
44}
45
46/// Expect an unqualified identifier such as Foo or Bar for a `class`, `interface`, or an `enum` name.
47///
48/// The identifier can only be a simple identifier.
49/// The identifier may be one of the following reserved keywords:
50///
51/// - `enum`
52/// - `from`
53/// - `vec`
54/// - `dict`
55/// - `where`
56/// - `type`
57/// - `in`
58/// - `into`
59/// - `using`
60/// - `async`
61/// - `await`
62/// - `concurrently`
63pub fn classname_identifier(state: &mut State) -> ParseResult<Identifier> {
64    let current = state.iterator.current();
65    match &current.kind {
66        TokenKind::Identifier => {
67            let position = current.position;
68
69            state.iterator.next();
70
71            Ok(Identifier {
72                position,
73                value: current.value.clone(),
74            })
75        }
76        TokenKind::Enum
77        | TokenKind::From
78        | TokenKind::Where
79        | TokenKind::Type
80        | TokenKind::In
81        | TokenKind::Into
82        | TokenKind::Using
83        | TokenKind::Dict
84        | TokenKind::Vec
85        | TokenKind::Async
86        | TokenKind::Await
87        | TokenKind::Concurrently => {
88            let position = current.position;
89            let name = current.to_string().into();
90
91            state.iterator.next();
92
93            Ok(Identifier {
94                position,
95                value: name,
96            })
97        }
98        t if is_reserved_identifier(t) => {
99            state.iterator.next();
100
101            let identifier = Identifier {
102                position: current.position,
103                value: current.to_string().into(),
104            };
105
106            crate::parser_report!(
107                state,
108                reserved_keyword_cannot_be_used_for_type_name(&identifier)
109            );
110
111            Ok(identifier)
112        }
113        _ => {
114            crate::parser_bail!(
115                state,
116                unexpected_token(vec!["an identifier".to_owned()], current)
117            )
118        }
119    }
120}
121
122/// Expect an unqualified identifier such as FOO or BAR for a `constant` name.
123///
124/// The identifier can only be a simple identifier.
125/// The identifier may be one of the following reserved keywords:
126///
127/// - `enum`
128/// - `from`
129/// - `where`
130/// - `type`
131#[inline(always)]
132pub fn constant_identifier(state: &mut State) -> ParseResult<Identifier> {
133    let current = state.iterator.current();
134    match &current.kind {
135        TokenKind::Identifier => {
136            let position = current.position;
137
138            state.iterator.next();
139
140            Ok(Identifier {
141                position,
142                value: current.value.clone(),
143            })
144        }
145        TokenKind::Class => {
146            let position = current.position;
147            let name = current.to_string().into();
148
149            state.iterator.next();
150
151            let identifier = Identifier {
152                position,
153                value: name,
154            };
155
156            crate::parser_report!(
157                state,
158                reserved_keyword_cannot_be_used_for_constant_name(&identifier)
159            );
160
161            Ok(identifier)
162        }
163        t if is_reserved_identifier(t) => {
164            state.iterator.next();
165
166            let identifier = Identifier {
167                position: current.position,
168                value: current.to_string().into(),
169            };
170
171            Ok(identifier)
172        }
173        _ => {
174            crate::parser_bail!(
175                state,
176                unexpected_token(vec!["an identifier".to_owned()], current)
177            )
178        }
179    }
180}
181
182/// Expect an unqualified identifier such as FOO or BAR for a `type` name.
183///
184/// The identifier can only be a simple identifier.
185/// The identifier may be one of the following reserved keywords:
186///
187/// - `enum`
188/// - `from`
189/// - `where`
190/// - `type`
191/// - `in`
192/// - `into`
193/// - `using`
194///
195/// Unlike `constant` name, `type` name can be templated ( e.g `Callback<U, V>` )
196#[inline(always)]
197pub fn type_identifier(state: &mut State) -> ParseResult<TemplatedIdentifier> {
198    let current = state.iterator.current();
199    let name = match &current.kind {
200        TokenKind::Identifier => {
201            state.iterator.next();
202
203            Identifier {
204                position: current.position,
205                value: current.value.clone(),
206            }
207        }
208        TokenKind::Enum
209        | TokenKind::From
210        | TokenKind::Where
211        | TokenKind::Type
212        | TokenKind::In
213        | TokenKind::Into
214        | TokenKind::Using => {
215            state.iterator.next();
216
217            Identifier {
218                position: current.position,
219                value: current.value.clone(),
220            }
221        }
222        t if is_reserved_identifier(t) => {
223            state.iterator.next();
224
225            let identifier = Identifier {
226                position: current.position,
227                value: current.to_string().into(),
228            };
229
230            crate::parser_report!(
231                state,
232                reserved_keyword_cannot_be_used_for_type_name(&identifier)
233            );
234
235            identifier
236        }
237        _ => {
238            crate::parser_bail!(
239                state,
240                unexpected_token(vec!["an identifier".to_owned()], current)
241            )
242        }
243    };
244
245    let templates = if state.iterator.current().kind == TokenKind::LessThan {
246        Some(template::type_template_group_definition(state)?)
247    } else {
248        None
249    };
250
251    Ok(TemplatedIdentifier { name, templates })
252}
253
254pub fn fully_qualified_templated_identifier(state: &mut State) -> ParseResult<TemplatedIdentifier> {
255    let name = fully_qualified_type_identifier(state)?;
256    let templates = if state.iterator.current().kind == TokenKind::LessThan {
257        Some(template::type_template_group_definition(state)?)
258    } else {
259        None
260    };
261
262    Ok(TemplatedIdentifier { name, templates })
263}
264
265pub fn fully_qualified_templated_identifier_including_self(
266    state: &mut State,
267) -> ParseResult<TemplatedIdentifier> {
268    let name = fully_qualified_type_identifier_including_self(state)?;
269    let templates = if state.iterator.current().kind == TokenKind::LessThan {
270        Some(template::type_template_group_definition(state)?)
271    } else {
272        None
273    };
274
275    Ok(TemplatedIdentifier { name, templates })
276}
277
278/// Expect an unqualified identifier such as Foo or Bar.
279pub fn identifier(state: &mut State) -> ParseResult<Identifier> {
280    let current = state.iterator.current();
281    if let TokenKind::Identifier = &current.kind {
282        let position = current.position;
283
284        state.iterator.next();
285
286        Ok(Identifier {
287            position,
288            value: current.value.clone(),
289        })
290    } else {
291        crate::parser_bail!(
292            state,
293            unexpected_token(vec!["an identifier".to_owned()], current)
294        );
295    }
296}
297
298/// Expect an unqualified, qualified or fully qualified identifier such as Foo, Foo\Bar or \Foo\Bar.
299pub fn fully_qualified_type_identifier(state: &mut State) -> ParseResult<Identifier> {
300    let current = state.iterator.current();
301    match &current.kind {
302        TokenKind::Identifier
303        | TokenKind::QualifiedIdentifier
304        | TokenKind::FullyQualifiedIdentifier => {
305            let position = current.position;
306
307            state.iterator.next();
308
309            Ok(Identifier {
310                position,
311                value: current.value.clone(),
312            })
313        }
314        TokenKind::Enum
315        | TokenKind::From
316        | TokenKind::Where
317        | TokenKind::Type
318        | TokenKind::In
319        | TokenKind::Into
320        | TokenKind::Using
321        | TokenKind::Dict
322        | TokenKind::Vec
323        | TokenKind::Async
324        | TokenKind::Await
325        | TokenKind::Concurrently => {
326            let position = current.position;
327            let name = current.to_string().into();
328
329            state.iterator.next();
330
331            Ok(Identifier {
332                position,
333                value: name,
334            })
335        }
336        TokenKind::Self_ | TokenKind::Static | TokenKind::Parent => {
337            state.iterator.next();
338
339            let identifier = Identifier {
340                position: current.position,
341                value: current.to_string().into(),
342            };
343
344            crate::parser_report!(state, type_cannot_be_used_in_current_context(&identifier));
345
346            Ok(identifier)
347        }
348        t if is_reserved_identifier(t) => {
349            state.iterator.next();
350
351            let identifier = Identifier {
352                position: current.position,
353                value: current.to_string().into(),
354            };
355
356            crate::parser_report!(
357                state,
358                reserved_keyword_cannot_be_used_for_type_name(&identifier)
359            );
360
361            Ok(identifier)
362        }
363        _ => crate::parser_bail!(
364            state,
365            unexpected_token(vec!["an identifier".to_owned()], current)
366        ),
367    }
368}
369
370/// Expect an unqualified, qualified or fully qualified identifier such as Foo, Foo\Bar or \Foo\Bar.
371pub fn fully_qualified_type_identifier_including_self(
372    state: &mut State,
373) -> ParseResult<Identifier> {
374    let current = state.iterator.current();
375    match &current.kind {
376        TokenKind::Identifier
377        | TokenKind::QualifiedIdentifier
378        | TokenKind::FullyQualifiedIdentifier => {
379            let position = current.position;
380
381            state.iterator.next();
382
383            Ok(Identifier {
384                position,
385                value: current.value.clone(),
386            })
387        }
388        TokenKind::Enum
389        | TokenKind::From
390        | TokenKind::Self_
391        | TokenKind::Static
392        | TokenKind::Parent
393        | TokenKind::Type
394        | TokenKind::In
395        | TokenKind::Into
396        | TokenKind::Using
397        | TokenKind::Where
398        | TokenKind::Dict
399        | TokenKind::Vec
400        | TokenKind::Async
401        | TokenKind::Await
402        | TokenKind::Concurrently => {
403            let position = current.position;
404            let name = current.to_string().into();
405
406            state.iterator.next();
407
408            Ok(Identifier {
409                position,
410                value: name,
411            })
412        }
413        t if is_reserved_identifier(t) => {
414            state.iterator.next();
415
416            let identifier = Identifier {
417                position: current.position,
418                value: current.to_string().into(),
419            };
420
421            crate::parser_report!(
422                state,
423                reserved_keyword_cannot_be_used_for_type_name(&identifier)
424            );
425
426            Ok(identifier)
427        }
428        _ => crate::parser_bail!(
429            state,
430            unexpected_token(vec!["an identifier".to_owned()], current)
431        ),
432    }
433}
434
435pub fn identifier_maybe_reserved(state: &mut State) -> ParseResult<Identifier> {
436    let current = state.iterator.current();
437
438    if is_reserved_identifier(&current.kind) {
439        let name = current.to_string().into();
440        let position = current.position;
441        state.iterator.next();
442
443        Ok(Identifier {
444            position,
445            value: name,
446        })
447    } else {
448        identifier(state)
449    }
450}
451
452pub fn identifier_maybe_soft_reserved(state: &mut State) -> ParseResult<Identifier> {
453    let current = state.iterator.current();
454
455    if is_soft_reserved_identifier(&current.kind) {
456        let name = current.to_string().into();
457        let position = current.position;
458        state.iterator.next();
459
460        Ok(Identifier {
461            position,
462            value: name,
463        })
464    } else {
465        identifier(state)
466    }
467}
468
469pub fn is_identifier_maybe_reserved(kind: &TokenKind) -> bool {
470    if let TokenKind::Identifier = kind {
471        return true;
472    }
473
474    is_reserved_identifier(kind)
475}
476
477pub fn is_soft_reserved_identifier(kind: &TokenKind) -> bool {
478    matches!(kind, |TokenKind::Parent| TokenKind::Self_
479        | TokenKind::True
480        | TokenKind::False
481        | TokenKind::Type
482        | TokenKind::In
483        | TokenKind::Into
484        | TokenKind::Using
485        | TokenKind::Is
486        | TokenKind::List
487        | TokenKind::Null
488        | TokenKind::Concurrently
489        | TokenKind::Async
490        | TokenKind::Await
491        | TokenKind::Where
492        | TokenKind::Enum
493        | TokenKind::From
494        | TokenKind::Readonly)
495}
496
497pub fn is_reserved_identifier(kind: &TokenKind) -> bool {
498    if is_soft_reserved_identifier(kind) {
499        return true;
500    }
501
502    matches!(
503        kind,
504        TokenKind::Static
505            | TokenKind::Abstract
506            | TokenKind::Final
507            | TokenKind::For
508            | TokenKind::Private
509            | TokenKind::Protected
510            | TokenKind::Public
511            | TokenKind::Dict
512            | TokenKind::Vec
513            | TokenKind::LogicalOr
514            | TokenKind::LogicalXor
515            | TokenKind::LogicalAnd
516            | TokenKind::Instanceof
517            | TokenKind::New
518            | TokenKind::Clone
519            | TokenKind::Exit
520            | TokenKind::If
521            | TokenKind::ElseIf
522            | TokenKind::Else
523            | TokenKind::EndIf
524            | TokenKind::Echo
525            | TokenKind::Do
526            | TokenKind::While
527            | TokenKind::EndWhile
528            | TokenKind::EndFor
529            | TokenKind::Foreach
530            | TokenKind::EndForeach
531            | TokenKind::Declare
532            | TokenKind::EndDeclare
533            | TokenKind::As
534            | TokenKind::Try
535            | TokenKind::Catch
536            | TokenKind::Finally
537            | TokenKind::Throw
538            | TokenKind::Use
539            | TokenKind::Insteadof
540            | TokenKind::Global
541            | TokenKind::Var
542            | TokenKind::Unset
543            | TokenKind::Isset
544            | TokenKind::Empty
545            | TokenKind::Continue
546            | TokenKind::Goto
547            | TokenKind::Function
548            | TokenKind::Const
549            | TokenKind::Return
550            | TokenKind::Print
551            | TokenKind::Yield
552            | TokenKind::List
553            | TokenKind::Switch
554            | TokenKind::EndSwitch
555            | TokenKind::Case
556            | TokenKind::Default
557            | TokenKind::Break
558            | TokenKind::Array
559            | TokenKind::Callable
560            | TokenKind::Extends
561            | TokenKind::Implements
562            | TokenKind::Namespace
563            | TokenKind::Trait
564            | TokenKind::Interface
565            | TokenKind::Class
566            | TokenKind::ClassConstant
567            | TokenKind::TraitConstant
568            | TokenKind::FunctionConstant
569            | TokenKind::MethodConstant
570            | TokenKind::LineConstant
571            | TokenKind::FileConstant
572            | TokenKind::DirConstant
573            | TokenKind::NamespaceConstant
574            | TokenKind::HaltCompiler
575            | TokenKind::Fn
576            | TokenKind::Match
577            | TokenKind::Include
578            | TokenKind::IncludeOnce
579            | TokenKind::Eval
580            | TokenKind::Require
581            | TokenKind::RequireOnce
582            | TokenKind::Die
583    )
584}