aboutsummaryrefslogtreecommitdiff
path: root/src/parser/event.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser/event.rs')
-rw-r--r--src/parser/event.rs168
1 files changed, 0 insertions, 168 deletions
diff --git a/src/parser/event.rs b/src/parser/event.rs
deleted file mode 100644
index 0086d32ea..000000000
--- a/src/parser/event.rs
+++ /dev/null
@@ -1,168 +0,0 @@
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 `Sink` 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 {
11 lexer::Token,
12 SyntaxKind::{self, TOMBSTONE},
13 TextUnit,
14};
15
16pub(crate) trait Sink {
17 type Tree;
18
19 fn new(text: String) -> Self;
20
21 fn leaf(&mut self, kind: SyntaxKind, len: TextUnit);
22 fn start_internal(&mut self, kind: SyntaxKind);
23 fn finish_internal(&mut self);
24 fn error(&mut self, err: String);
25 fn finish(self) -> Self::Tree;
26}
27
28/// `Parser` produces a flat list of `Event`s.
29/// They are converted to a tree-structure in
30/// a separate pass, via `TreeBuilder`.
31#[derive(Debug)]
32pub(crate) enum Event {
33 /// This event signifies the start of the node.
34 /// It should be either abandoned (in which case the
35 /// `kind` is `TOMBSTONE`, and the event is ignored),
36 /// or completed via a `Finish` event.
37 ///
38 /// All tokens between a `Start` and a `Finish` would
39 /// become the children of the respective node.
40 ///
41 /// For left-recursive syntactic constructs, the parser produces
42 /// a child node before it sees a parent. `forward_parent`
43 /// exists to allow to tweak parent-child relationships.
44 ///
45 /// Consider this path
46 ///
47 /// foo::bar
48 ///
49 /// The events for it would look like this:
50 ///
51 ///
52 /// START(PATH) IDENT('foo') FINISH START(PATH) COLONCOLON IDENT('bar') FINISH
53 /// | /\
54 /// | |
55 /// +------forward-parent------+
56 ///
57 /// And the tree would look like this
58 ///
59 /// +--PATH---------+
60 /// | | |
61 /// | | |
62 /// | '::' 'bar'
63 /// |
64 /// PATH
65 /// |
66 /// 'foo'
67 ///
68 /// See also `CompletedMarker::precede`.
69 Start {
70 kind: SyntaxKind,
71 forward_parent: Option<u32>,
72 },
73
74 /// Complete the previous `Start` event
75 Finish,
76
77 /// Produce a single leaf-element.
78 /// `n_raw_tokens` is used to glue complex contextual tokens.
79 /// For example, lexer tokenizes `>>` as `>`, `>`, and
80 /// `n_raw_tokens = 2` is used to produced a single `>>`.
81 Token {
82 kind: SyntaxKind,
83 n_raw_tokens: u8,
84 },
85
86 Error {
87 msg: String,
88 },
89}
90
91pub(super) fn process(builder: &mut impl Sink, tokens: &[Token], events: Vec<Event>) {
92 let mut idx = 0;
93
94 let mut holes = Vec::new();
95 let mut forward_parents = Vec::new();
96
97 for (i, event) in events.iter().enumerate() {
98 if holes.last() == Some(&i) {
99 holes.pop();
100 continue;
101 }
102
103 match event {
104 &Event::Start {
105 kind: TOMBSTONE, ..
106 } => (),
107
108 &Event::Start { .. } => {
109 forward_parents.clear();
110 let mut idx = i;
111 loop {
112 let (kind, fwd) = match events[idx] {
113 Event::Start {
114 kind,
115 forward_parent,
116 } => (kind, forward_parent),
117 _ => unreachable!(),
118 };
119 forward_parents.push((idx, kind));
120 if let Some(fwd) = fwd {
121 idx += fwd as usize;
122 } else {
123 break;
124 }
125 }
126 for &(idx, kind) in forward_parents.iter().into_iter().rev() {
127 builder.start_internal(kind);
128 holes.push(idx);
129 }
130 holes.pop();
131 }
132 &Event::Finish => {
133 while idx < tokens.len() {
134 let token = tokens[idx];
135 if token.kind.is_trivia() {
136 idx += 1;
137 builder.leaf(token.kind, token.len);
138 } else {
139 break;
140 }
141 }
142 builder.finish_internal()
143 }
144 &Event::Token {
145 kind,
146 mut n_raw_tokens,
147 } => {
148 // FIXME: currently, we attach whitespace to some random node
149 // this should be done in a sensible manner instead
150 loop {
151 let token = tokens[idx];
152 if !token.kind.is_trivia() {
153 break;
154 }
155 builder.leaf(token.kind, token.len);
156 idx += 1
157 }
158 let mut len = 0.into();
159 for _ in 0..n_raw_tokens {
160 len += tokens[idx].len;
161 idx += 1;
162 }
163 builder.leaf(kind, len);
164 }
165 &Event::Error { ref msg } => builder.error(msg.clone()),
166 }
167 }
168}