diff options
Diffstat (limited to 'src/parser/event_parser/grammar')
-rw-r--r-- | src/parser/event_parser/grammar/mod.rs | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/src/parser/event_parser/grammar/mod.rs b/src/parser/event_parser/grammar/mod.rs new file mode 100644 index 000000000..acf27aec9 --- /dev/null +++ b/src/parser/event_parser/grammar/mod.rs | |||
@@ -0,0 +1,194 @@ | |||
1 | use super::parser::Parser; | ||
2 | use {SyntaxKind}; | ||
3 | use tree::EOF; | ||
4 | use syntax_kinds::*; | ||
5 | |||
6 | // Items // | ||
7 | |||
8 | pub(crate) fn file(p: &mut Parser) { | ||
9 | node(p, FILE, |p| { | ||
10 | p.optional(SHEBANG); | ||
11 | inner_attributes(p); | ||
12 | many(p, |p| { | ||
13 | skip_to_first( | ||
14 | p, item_first, item, | ||
15 | "expected item", | ||
16 | ) | ||
17 | }); | ||
18 | }) | ||
19 | } | ||
20 | |||
21 | fn item_first(p: &Parser) -> bool { | ||
22 | match p.current() { | ||
23 | STRUCT_KW | FN_KW => true, | ||
24 | _ => false, | ||
25 | } | ||
26 | } | ||
27 | |||
28 | fn item(p: &mut Parser) { | ||
29 | outer_attributes(p); | ||
30 | visibility(p); | ||
31 | node_if(p, STRUCT_KW, STRUCT_ITEM, struct_item) | ||
32 | || node_if(p, FN_KW, FN_ITEM, fn_item); | ||
33 | } | ||
34 | |||
35 | fn struct_item(p: &mut Parser) { | ||
36 | p.expect(IDENT) | ||
37 | && p.curly_block(|p| comma_list(p, EOF, struct_field)); | ||
38 | } | ||
39 | |||
40 | fn struct_field(p: &mut Parser) -> bool { | ||
41 | node_if(p, IDENT, STRUCT_FIELD, |p| { | ||
42 | p.expect(COLON) && p.expect(IDENT); | ||
43 | }) | ||
44 | } | ||
45 | |||
46 | fn fn_item(p: &mut Parser) { | ||
47 | p.expect(IDENT) && p.expect(L_PAREN) && p.expect(R_PAREN) | ||
48 | && p.curly_block(|p| ()); | ||
49 | } | ||
50 | |||
51 | |||
52 | // Paths, types, attributes, and stuff // | ||
53 | |||
54 | fn inner_attributes(p: &mut Parser) { | ||
55 | many(p, |p| attribute(p, true)) | ||
56 | } | ||
57 | |||
58 | fn attribute(p: &mut Parser, inner: bool) -> bool { | ||
59 | let attr_start = inner && p.lookahead(&[POUND, EXCL, L_BRACK]) | ||
60 | || !inner && p.lookahead(&[POUND, L_BRACK]); | ||
61 | if !attr_start { | ||
62 | return false; | ||
63 | } | ||
64 | node(p, ATTR, |p| { | ||
65 | p.bump_n(if inner { 3 } else { 2 }); | ||
66 | meta_item(p) && p.expect(R_BRACK); | ||
67 | }); | ||
68 | true | ||
69 | } | ||
70 | |||
71 | fn meta_item(p: &mut Parser) -> bool { | ||
72 | node_if(p, IDENT, META_ITEM, |p| { | ||
73 | if p.eat(EQ) { | ||
74 | if !literal(p) { | ||
75 | p.error() | ||
76 | .message("expected literal") | ||
77 | .emit(); | ||
78 | } | ||
79 | } else if p.eat(L_PAREN) { | ||
80 | comma_list(p, R_PAREN, meta_item_inner); | ||
81 | p.expect(R_PAREN); | ||
82 | } | ||
83 | }) | ||
84 | } | ||
85 | |||
86 | fn meta_item_inner(p: &mut Parser) -> bool { | ||
87 | meta_item(p) || literal(p) | ||
88 | } | ||
89 | |||
90 | fn literal(p: &mut Parser) -> bool { | ||
91 | p.eat(INT_NUMBER) || p.eat(FLOAT_NUMBER) | ||
92 | } | ||
93 | |||
94 | fn outer_attributes(_: &mut Parser) { | ||
95 | } | ||
96 | |||
97 | fn visibility(_: &mut Parser) { | ||
98 | } | ||
99 | |||
100 | // Expressions // | ||
101 | |||
102 | // Error recovery and high-order utils // | ||
103 | |||
104 | fn node_if<F: FnOnce(&mut Parser)>( | ||
105 | p: &mut Parser, | ||
106 | first: SyntaxKind, | ||
107 | node_kind: SyntaxKind, | ||
108 | rest: F | ||
109 | ) -> bool { | ||
110 | p.current() == first && { node(p, node_kind, |p| { p.bump(); rest(p); }); true } | ||
111 | } | ||
112 | |||
113 | fn node<F: FnOnce(&mut Parser)>(p: &mut Parser, node_kind: SyntaxKind, rest: F) { | ||
114 | p.start(node_kind); | ||
115 | rest(p); | ||
116 | p.finish(); | ||
117 | } | ||
118 | |||
119 | fn many<F: Fn(&mut Parser) -> bool>(p: &mut Parser, f: F) { | ||
120 | while f(p) { } | ||
121 | } | ||
122 | |||
123 | fn comma_list<F: Fn(&mut Parser) -> bool>(p: &mut Parser, end: SyntaxKind, f: F) { | ||
124 | many(p, |p| { | ||
125 | if !f(p) || p.current() == end { | ||
126 | false | ||
127 | } else { | ||
128 | p.expect(COMMA); | ||
129 | true | ||
130 | } | ||
131 | }) | ||
132 | } | ||
133 | |||
134 | |||
135 | fn skip_to_first<C, F>(p: &mut Parser, cond: C, f: F, message: &str) -> bool | ||
136 | where | ||
137 | C: Fn(&Parser) -> bool, | ||
138 | F: FnOnce(&mut Parser), | ||
139 | { | ||
140 | let mut skipped = false; | ||
141 | loop { | ||
142 | if cond(p) { | ||
143 | if skipped { | ||
144 | p.finish(); | ||
145 | } | ||
146 | f(p); | ||
147 | return true; | ||
148 | } | ||
149 | if p.current() == EOF { | ||
150 | if skipped { | ||
151 | p.finish(); | ||
152 | } | ||
153 | return false; | ||
154 | } | ||
155 | if !skipped { | ||
156 | p.start(ERROR); | ||
157 | p.error() | ||
158 | .message(message) | ||
159 | .emit(); | ||
160 | } | ||
161 | p.bump(); | ||
162 | skipped = true; | ||
163 | } | ||
164 | } | ||
165 | |||
166 | impl<'p> Parser<'p> { | ||
167 | pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool { | ||
168 | if self.current() == kind { | ||
169 | self.bump(); | ||
170 | true | ||
171 | } else { | ||
172 | self.error() | ||
173 | .message(format!("expected {:?}", kind)) | ||
174 | .emit(); | ||
175 | false | ||
176 | } | ||
177 | } | ||
178 | |||
179 | fn optional(&mut self, kind: SyntaxKind) { | ||
180 | if self.current() == kind { | ||
181 | self.bump(); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | fn bump_n(&mut self, n: u8) { | ||
186 | for _ in 0..n { | ||
187 | self.bump(); | ||
188 | } | ||
189 | } | ||
190 | |||
191 | fn eat(&mut self, kind: SyntaxKind) -> bool { | ||
192 | self.current() == kind && { self.bump(); true } | ||
193 | } | ||
194 | } \ No newline at end of file | ||