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