aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_parser/src/event.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_parser/src/event.rs')
-rw-r--r--crates/ra_parser/src/event.rs128
1 files changed, 128 insertions, 0 deletions
diff --git a/crates/ra_parser/src/event.rs b/crates/ra_parser/src/event.rs
new file mode 100644
index 000000000..d6e8454d4
--- /dev/null
+++ b/crates/ra_parser/src/event.rs
@@ -0,0 +1,128 @@
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.
5//!
6//! The `TreeSink` trait is the bridge between the parser and the
7//! tree builder: the parser produces a stream of events like
8//! `start node`, `finish node`, and `FileBuilder` converts
9//! this stream to a real tree.
10use std::mem;
11
12use crate::{
13 ParseError, TreeSink,
14 SyntaxKind::{self, *},
15};
16
17/// `Parser` produces a flat list of `Event`s.
18/// They are converted to a tree-structure in
19/// a separate pass, via `TreeBuilder`.
20#[derive(Debug)]
21pub(crate) enum Event {
22 /// This event signifies the start of the node.
23 /// It should be either abandoned (in which case the
24 /// `kind` is `TOMBSTONE`, and the event is ignored),
25 /// or completed via a `Finish` event.
26 ///
27 /// All tokens between a `Start` and a `Finish` would
28 /// become the children of the respective node.
29 ///
30 /// For left-recursive syntactic constructs, the parser produces
31 /// a child node before it sees a parent. `forward_parent`
32 /// saves the position of current event's parent.
33 ///
34 /// Consider this path
35 ///
36 /// foo::bar
37 ///
38 /// The events for it would look like this:
39 ///
40 ///
41 /// START(PATH) IDENT('foo') FINISH START(PATH) COLONCOLON IDENT('bar') FINISH
42 /// | /\
43 /// | |
44 /// +------forward-parent------+
45 ///
46 /// And the tree would look like this
47 ///
48 /// +--PATH---------+
49 /// | | |
50 /// | | |
51 /// | '::' 'bar'
52 /// |
53 /// PATH
54 /// |
55 /// 'foo'
56 ///
57 /// See also `CompletedMarker::precede`.
58 Start {
59 kind: SyntaxKind,
60 forward_parent: Option<u32>,
61 },
62
63 /// Complete the previous `Start` event
64 Finish,
65
66 /// Produce a single leaf-element.
67 /// `n_raw_tokens` is used to glue complex contextual tokens.
68 /// For example, lexer tokenizes `>>` as `>`, `>`, and
69 /// `n_raw_tokens = 2` is used to produced a single `>>`.
70 Token {
71 kind: SyntaxKind,
72 n_raw_tokens: u8,
73 },
74
75 Error {
76 msg: ParseError,
77 },
78}
79
80impl Event {
81 pub(crate) fn tombstone() -> Self {
82 Event::Start { kind: TOMBSTONE, forward_parent: None }
83 }
84}
85
86/// Generate the syntax tree with the control of events.
87pub(super) fn process(sink: &mut dyn TreeSink, mut events: Vec<Event>) {
88 let mut forward_parents = Vec::new();
89
90 for i in 0..events.len() {
91 match mem::replace(&mut events[i], Event::tombstone()) {
92 Event::Start { kind: TOMBSTONE, .. } => (),
93
94 Event::Start { kind, forward_parent } => {
95 // For events[A, B, C], B is A's forward_parent, C is B's forward_parent,
96 // in the normal control flow, the parent-child relation: `A -> B -> C`,
97 // while with the magic forward_parent, it writes: `C <- B <- A`.
98
99 // append `A` into parents.
100 forward_parents.push(kind);
101 let mut idx = i;
102 let mut fp = forward_parent;
103 while let Some(fwd) = fp {
104 idx += fwd as usize;
105 // append `A`'s forward_parent `B`
106 fp = match mem::replace(&mut events[idx], Event::tombstone()) {
107 Event::Start { kind, forward_parent } => {
108 forward_parents.push(kind);
109 forward_parent
110 }
111 _ => unreachable!(),
112 };
113 // append `B`'s forward_parent `C` in the next stage.
114 }
115
116 for (j, kind) in forward_parents.drain(..).rev().enumerate() {
117 let is_root_node = i == 0 && j == 0;
118 sink.start_branch(kind, is_root_node);
119 }
120 }
121 Event::Finish => sink.finish_branch(i == events.len() - 1),
122 Event::Token { kind, n_raw_tokens } => {
123 sink.leaf(kind, n_raw_tokens);
124 }
125 Event::Error { msg } => sink.error(msg),
126 }
127 }
128}