]> git.proxmox.com Git - rustc.git/blame - src/tools/rust-analyzer/crates/parser/src/event.rs
New upstream version 1.76.0+dfsg1
[rustc.git] / src / tools / rust-analyzer / crates / parser / src / event.rs
CommitLineData
064997fb
FG
1//! This module provides a way to construct a `File`.
2//! It is intended to be completely decoupled from the
3//! parser, so as to allow to evolve the tree representation
4//! and the parser algorithm independently.
064997fb
FG
5use std::mem;
6
7use crate::{
8 output::Output,
9 SyntaxKind::{self, *},
10};
11
12/// `Parser` produces a flat list of `Event`s.
13/// They are converted to a tree-structure in
14/// a separate pass, via `TreeBuilder`.
15#[derive(Debug)]
16pub(crate) enum Event {
17 /// This event signifies the start of the node.
18 /// It should be either abandoned (in which case the
19 /// `kind` is `TOMBSTONE`, and the event is ignored),
20 /// or completed via a `Finish` event.
21 ///
22 /// All tokens between a `Start` and a `Finish` would
23 /// become the children of the respective node.
24 ///
25 /// For left-recursive syntactic constructs, the parser produces
26 /// a child node before it sees a parent. `forward_parent`
27 /// saves the position of current event's parent.
28 ///
29 /// Consider this path
30 ///
31 /// foo::bar
32 ///
33 /// The events for it would look like this:
34 ///
35 /// ```text
36 /// START(PATH) IDENT('foo') FINISH START(PATH) T![::] IDENT('bar') FINISH
37 /// | /\
38 /// | |
39 /// +------forward-parent------+
40 /// ```
41 ///
42 /// And the tree would look like this
43 ///
44 /// ```text
45 /// +--PATH---------+
46 /// | | |
47 /// | | |
48 /// | '::' 'bar'
49 /// |
50 /// PATH
51 /// |
52 /// 'foo'
53 /// ```
54 ///
55 /// See also `CompletedMarker::precede`.
56 Start {
57 kind: SyntaxKind,
58 forward_parent: Option<u32>,
59 },
60
61 /// Complete the previous `Start` event
62 Finish,
63
64 /// Produce a single leaf-element.
65 /// `n_raw_tokens` is used to glue complex contextual tokens.
66 /// For example, lexer tokenizes `>>` as `>`, `>`, and
67 /// `n_raw_tokens = 2` is used to produced a single `>>`.
68 Token {
69 kind: SyntaxKind,
70 n_raw_tokens: u8,
71 },
9ffffee4
FG
72 /// When we parse `foo.0.0` or `foo. 0. 0` the lexer will hand us a float literal
73 /// instead of an integer literal followed by a dot as the lexer has no contextual knowledge.
74 /// This event instructs whatever consumes the events to split the float literal into
75 /// the corresponding parts.
76 FloatSplitHack {
77 ends_in_dot: bool,
78 },
064997fb
FG
79 Error {
80 msg: String,
81 },
82}
83
84impl Event {
85 pub(crate) fn tombstone() -> Self {
86 Event::Start { kind: TOMBSTONE, forward_parent: None }
87 }
88}
89
90/// Generate the syntax tree with the control of events.
91pub(super) fn process(mut events: Vec<Event>) -> Output {
92 let mut res = Output::default();
93 let mut forward_parents = Vec::new();
94
95 for i in 0..events.len() {
96 match mem::replace(&mut events[i], Event::tombstone()) {
97 Event::Start { kind, forward_parent } => {
98 // For events[A, B, C], B is A's forward_parent, C is B's forward_parent,
99 // in the normal control flow, the parent-child relation: `A -> B -> C`,
100 // while with the magic forward_parent, it writes: `C <- B <- A`.
101
102 // append `A` into parents.
103 forward_parents.push(kind);
104 let mut idx = i;
105 let mut fp = forward_parent;
106 while let Some(fwd) = fp {
107 idx += fwd as usize;
108 // append `A`'s forward_parent `B`
109 fp = match mem::replace(&mut events[idx], Event::tombstone()) {
110 Event::Start { kind, forward_parent } => {
111 forward_parents.push(kind);
112 forward_parent
113 }
114 _ => unreachable!(),
115 };
116 // append `B`'s forward_parent `C` in the next stage.
117 }
118
119 for kind in forward_parents.drain(..).rev() {
120 if kind != TOMBSTONE {
121 res.enter_node(kind);
122 }
123 }
124 }
125 Event::Finish => res.leave_node(),
126 Event::Token { kind, n_raw_tokens } => {
127 res.token(kind, n_raw_tokens);
128 }
9ffffee4
FG
129 Event::FloatSplitHack { ends_in_dot } => {
130 res.float_split_hack(ends_in_dot);
131 let ev = mem::replace(&mut events[i + 1], Event::tombstone());
132 assert!(matches!(ev, Event::Finish), "{ev:?}");
133 }
064997fb
FG
134 Event::Error { msg } => res.error(msg),
135 }
136 }
137
138 res
139}