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