aboutsummaryrefslogtreecommitdiff
path: root/src/parser/event.rs
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2018-02-04 11:04:02 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2018-02-04 11:04:02 +0000
commitaa36ad008eae28d1251a4bf276b1d13398fcf89f (patch)
tree838d2875f00d1d0c4b3d747dfd7c314abf9ac404 /src/parser/event.rs
parent5e5313a7c71d8aa873b418575f56d23b2eac6e7f (diff)
parentd4179550cd69a23a79ed27a96b93f9f760c02b69 (diff)
Merge #41
41: G: unsafe impl & trait r=matklad a=matklad bors r+
Diffstat (limited to 'src/parser/event.rs')
-rw-r--r--src/parser/event.rs140
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 @@
1use {File, FileBuilder, Sink, SyntaxKind, Token};
2use syntax_kinds::TOMBSTONE;
3use 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)]
9pub(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
68pub(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}