diff options
author | Aleksey Kladov <[email protected]> | 2018-07-31 21:38:19 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-07-31 21:44:31 +0100 |
commit | 7912189ec304b28c4df0030b5282cf3d21074154 (patch) | |
tree | 03a0a1b128439fdefbd1d012b392995ca8a6e264 /src/parser/event.rs | |
parent | d1400e95d7ad701fcba1191cb00968c2eae8b394 (diff) |
reorganize
Diffstat (limited to 'src/parser/event.rs')
-rw-r--r-- | src/parser/event.rs | 168 |
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. | ||
10 | use { | ||
11 | lexer::Token, | ||
12 | SyntaxKind::{self, TOMBSTONE}, | ||
13 | TextUnit, | ||
14 | }; | ||
15 | |||
16 | pub(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)] | ||
32 | pub(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 | |||
91 | pub(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 | } | ||