1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use crate::ast;
16 use codespan_reporting::diagnostic::Diagnostic;
17 use codespan_reporting::files;
18 use pest::iterators::{Pair, Pairs};
19 use pest::{Parser, Token};
20 use std::iter::{Filter, Peekable};
21 
22 // Generate the PDL parser.
23 //
24 // TODO:
25 // - use #[grammar = "pdl.pest"]
26 //   currently not possible because CARGO_MANIFEST_DIR is not set
27 //   in soong environment.
28 // - use silent atomic rules for keywords like
29 //   ENUM = @{ "enum" ~ WHITESPACE }
30 //   currently not implemented in pest:
31 //   https://github.com/pest-parser/pest/issues/520
32 #[derive(pest_derive::Parser)]
33 #[grammar_inline = r#"
34 WHITESPACE = _{ " " | "\n" | "\r" | "\t" }
35 COMMENT = { block_comment | line_comment }
36 
37 block_comment = { "/*" ~ (!"*/" ~ ANY)* ~ "*/" }
38 line_comment = { "//" ~ (!"\n" ~ ANY)* }
39 
40 alpha = { 'a'..'z' | 'A'..'Z' }
41 digit = { '0'..'9' }
42 hexdigit = { digit | 'a'..'f' | 'A'..'F' }
43 alphanum = { alpha | digit | "_" }
44 
45 identifier = @{ alpha ~ alphanum* }
46 payload_identifier = @{ "_payload_" }
47 body_identifier = @{ "_body_" }
48 intvalue = @{ digit+ }
49 hexvalue = @{ ("0x"|"0X") ~ hexdigit+ }
50 integer = @{ hexvalue | intvalue }
51 string = @{ "\"" ~ (!"\"" ~ ANY)* ~ "\"" }
52 size_modifier = @{ "+" ~ intvalue }
53 
54 ENUM = @{ "enum" ~ WHITESPACE }
55 PACKET = @{ "packet" ~ WHITESPACE }
56 STRUCT = @{ "struct" ~ WHITESPACE }
57 GROUP = @{ "group" ~ WHITESPACE }
58 CHECKSUM = @{ "checksum" ~ WHITESPACE }
59 CUSTOM_FIELD = @{ "custom_field" ~ WHITESPACE }
60 TEST = @{ "test" ~ WHITESPACE }
61 
62 endianness_declaration = ${ ("little_endian_packets" | "big_endian_packets") ~ WHITESPACE }
63 
64 enum_value = { identifier ~ "=" ~ integer }
65 enum_value_list = { enum_value ~ ("," ~ enum_value)* ~ ","? }
66 enum_range = {
67     identifier ~ "=" ~ integer ~ ".." ~ integer ~ ("{" ~
68         enum_value_list ~
69     "}")?
70 }
71 enum_other = { identifier ~ "=" ~ ".." }
72 enum_tag = { enum_range | enum_value | enum_other }
73 enum_tag_list = { enum_tag ~ ("," ~ enum_tag)* ~ ","? }
74 enum_declaration = {
75     ENUM ~ identifier ~ ":" ~ integer ~ "{" ~
76         enum_tag_list ~
77     "}"
78 }
79 
80 constraint = { identifier ~ "=" ~ (identifier|integer) }
81 constraint_list = { constraint ~ ("," ~ constraint)* }
82 
83 checksum_field = { "_checksum_start_" ~ "(" ~ identifier ~ ")" }
84 padding_field = { "_padding_" ~ "[" ~ integer ~ "]" }
85 size_field = { "_size_" ~ "(" ~ (identifier|payload_identifier|body_identifier)  ~ ")" ~ ":" ~ integer }
86 count_field = { "_count_" ~ "(" ~ identifier ~ ")" ~ ":" ~ integer }
87 elementsize_field = { "_elementsize_" ~ "(" ~ identifier ~ ")" ~ ":" ~ integer }
88 body_field = @{ "_body_" }
89 payload_field = { "_payload_" ~ (":" ~ "[" ~ size_modifier ~ "]")? }
90 fixed_field = { "_fixed_" ~ "=" ~ (
91     (integer ~ ":" ~ integer) |
92     (identifier ~ ":" ~ identifier)
93 )}
94 reserved_field = { "_reserved_" ~ ":" ~ integer }
95 array_field = { identifier ~ ":" ~ (integer|identifier) ~
96     "[" ~ (size_modifier|integer)? ~ "]"
97 }
98 scalar_field = { identifier ~ ":" ~ integer }
99 typedef_field = { identifier ~ ":" ~ identifier }
100 group_field = { identifier ~ ("{" ~ constraint_list? ~ "}")? }
101 
102 field_desc = _{
103     checksum_field |
104     padding_field |
105     size_field |
106     count_field |
107     elementsize_field |
108     body_field |
109     payload_field |
110     fixed_field |
111     reserved_field |
112     array_field |
113     scalar_field |
114     typedef_field |
115     group_field
116 }
117 field = { field_desc ~ ("if" ~ constraint)? }
118 field_list = { field ~ ("," ~ field)* ~ ","? }
119 
120 packet_declaration = {
121    PACKET ~ identifier ~
122         (":" ~ identifier)? ~
123            ("(" ~ constraint_list ~ ")")? ~
124     "{" ~
125         field_list? ~
126     "}"
127 }
128 
129 struct_declaration = {
130     STRUCT ~ identifier ~
131         (":" ~ identifier)? ~
132            ("(" ~ constraint_list ~ ")")? ~
133     "{" ~
134         field_list? ~
135     "}"
136 }
137 
138 group_declaration = {
139     GROUP ~ identifier ~ "{" ~ field_list ~ "}"
140 }
141 
142 checksum_declaration = {
143     CHECKSUM ~ identifier ~ ":" ~ integer ~ string
144 }
145 
146 custom_field_declaration = {
147     CUSTOM_FIELD ~ identifier ~ (":" ~ integer)? ~ string
148 }
149 
150 test_case = { string }
151 test_case_list = _{ test_case ~ ("," ~ test_case)* ~ ","? }
152 test_declaration = {
153     TEST ~ identifier ~ "{" ~
154         test_case_list ~
155     "}"
156 }
157 
158 declaration = _{
159     enum_declaration |
160     packet_declaration |
161     struct_declaration |
162     group_declaration |
163     checksum_declaration |
164     custom_field_declaration |
165     test_declaration
166 }
167 
168 file = {
169     SOI ~
170     endianness_declaration ~
171     declaration* ~
172     EOI
173 }
174 "#]
175 pub struct PDLParser;
176 
177 type Node<'i> = Pair<'i, Rule>;
178 type NodeIterator<'i> = Peekable<Filter<Pairs<'i, Rule>, fn(&Node<'i>) -> bool>>;
179 struct Context<'a> {
180     file: ast::FileId,
181     line_starts: &'a Vec<usize>,
182     key: std::cell::Cell<usize>,
183 }
184 
185 trait Helpers<'i> {
children(self) -> NodeIterator<'i>186     fn children(self) -> NodeIterator<'i>;
as_loc(&self, context: &Context) -> ast::SourceRange187     fn as_loc(&self, context: &Context) -> ast::SourceRange;
as_string(&self) -> String188     fn as_string(&self) -> String;
as_usize(&self) -> Result<usize, String>189     fn as_usize(&self) -> Result<usize, String>;
190 }
191 
192 impl<'a> Context<'a> {
field_key(&self) -> ast::FieldKey193     fn field_key(&self) -> ast::FieldKey {
194         ast::FieldKey(self.key.replace(self.key.get() + 1))
195     }
196 
decl_key(&self) -> ast::DeclKey197     fn decl_key(&self) -> ast::DeclKey {
198         ast::DeclKey(self.key.replace(self.key.get() + 1))
199     }
200 }
201 
202 impl<'i> Helpers<'i> for Node<'i> {
children(self) -> NodeIterator<'i>203     fn children(self) -> NodeIterator<'i> {
204         self.into_inner().filter((|n| n.as_rule() != Rule::COMMENT) as fn(&Self) -> bool).peekable()
205     }
206 
as_loc(&self, context: &Context) -> ast::SourceRange207     fn as_loc(&self, context: &Context) -> ast::SourceRange {
208         let span = self.as_span();
209         ast::SourceRange {
210             file: context.file,
211             start: ast::SourceLocation::new(span.start_pos().pos(), context.line_starts),
212             end: ast::SourceLocation::new(span.end_pos().pos(), context.line_starts),
213         }
214     }
215 
as_string(&self) -> String216     fn as_string(&self) -> String {
217         self.as_str().to_owned()
218     }
219 
as_usize(&self) -> Result<usize, String>220     fn as_usize(&self) -> Result<usize, String> {
221         let text = self.as_str();
222         if let Some(num) = text.strip_prefix("0x") {
223             usize::from_str_radix(num, 16)
224                 .map_err(|_| format!("cannot convert '{}' to usize", self.as_str()))
225         } else {
226             #[allow(clippy::from_str_radix_10)]
227             usize::from_str_radix(text, 10)
228                 .map_err(|_| format!("cannot convert '{}' to usize", self.as_str()))
229         }
230     }
231 }
232 
err_unexpected_rule<T>(expected: Rule, found: Rule) -> Result<T, String>233 fn err_unexpected_rule<T>(expected: Rule, found: Rule) -> Result<T, String> {
234     Err(format!("expected rule {:?}, got {:?}", expected, found))
235 }
236 
err_missing_rule<T>(expected: Rule) -> Result<T, String>237 fn err_missing_rule<T>(expected: Rule) -> Result<T, String> {
238     Err(format!("expected rule {:?}, got nothing", expected))
239 }
240 
expect<'i>(iter: &mut impl Iterator<Item = Node<'i>>, rule: Rule) -> Result<Node<'i>, String>241 fn expect<'i>(iter: &mut impl Iterator<Item = Node<'i>>, rule: Rule) -> Result<Node<'i>, String> {
242     match iter.next() {
243         Some(node) if node.as_rule() == rule => Ok(node),
244         Some(node) => err_unexpected_rule(rule, node.as_rule()),
245         None => err_missing_rule(rule),
246     }
247 }
248 
maybe<'i>(iter: &mut NodeIterator<'i>, rule: Rule) -> Option<Node<'i>>249 fn maybe<'i>(iter: &mut NodeIterator<'i>, rule: Rule) -> Option<Node<'i>> {
250     iter.next_if(|n| n.as_rule() == rule)
251 }
252 
parse_identifier(iter: &mut NodeIterator<'_>) -> Result<String, String>253 fn parse_identifier(iter: &mut NodeIterator<'_>) -> Result<String, String> {
254     expect(iter, Rule::identifier).map(|n| n.as_string())
255 }
256 
parse_integer(iter: &mut NodeIterator<'_>) -> Result<usize, String>257 fn parse_integer(iter: &mut NodeIterator<'_>) -> Result<usize, String> {
258     expect(iter, Rule::integer).and_then(|n| n.as_usize())
259 }
260 
parse_identifier_opt(iter: &mut NodeIterator<'_>) -> Result<Option<String>, String>261 fn parse_identifier_opt(iter: &mut NodeIterator<'_>) -> Result<Option<String>, String> {
262     Ok(maybe(iter, Rule::identifier).map(|n| n.as_string()))
263 }
264 
parse_integer_opt(iter: &mut NodeIterator<'_>) -> Result<Option<usize>, String>265 fn parse_integer_opt(iter: &mut NodeIterator<'_>) -> Result<Option<usize>, String> {
266     maybe(iter, Rule::integer).map(|n| n.as_usize()).transpose()
267 }
268 
parse_identifier_or_integer( iter: &mut NodeIterator<'_>, ) -> Result<(Option<String>, Option<usize>), String>269 fn parse_identifier_or_integer(
270     iter: &mut NodeIterator<'_>,
271 ) -> Result<(Option<String>, Option<usize>), String> {
272     match iter.next() {
273         Some(n) if n.as_rule() == Rule::identifier => Ok((Some(n.as_string()), None)),
274         Some(n) if n.as_rule() == Rule::integer => Ok((None, Some(n.as_usize()?))),
275         Some(n) => Err(format!(
276             "expected rule {:?} or {:?}, got {:?}",
277             Rule::identifier,
278             Rule::integer,
279             n.as_rule()
280         )),
281         None => {
282             Err(format!("expected rule {:?} or {:?}, got nothing", Rule::identifier, Rule::integer))
283         }
284     }
285 }
286 
parse_string<'i>(iter: &mut impl Iterator<Item = Node<'i>>) -> Result<String, String>287 fn parse_string<'i>(iter: &mut impl Iterator<Item = Node<'i>>) -> Result<String, String> {
288     expect(iter, Rule::string)
289         .map(|n| n.as_str())
290         .and_then(|s| s.strip_prefix('"').ok_or_else(|| "expected \" prefix".to_owned()))
291         .and_then(|s| s.strip_suffix('"').ok_or_else(|| "expected \" suffix".to_owned()))
292         .map(|s| s.to_owned())
293 }
294 
parse_size_modifier_opt(iter: &mut NodeIterator<'_>) -> Option<String>295 fn parse_size_modifier_opt(iter: &mut NodeIterator<'_>) -> Option<String> {
296     maybe(iter, Rule::size_modifier).map(|n| n.as_string())
297 }
298 
parse_endianness(node: Node<'_>, context: &Context) -> Result<ast::Endianness, String>299 fn parse_endianness(node: Node<'_>, context: &Context) -> Result<ast::Endianness, String> {
300     if node.as_rule() != Rule::endianness_declaration {
301         err_unexpected_rule(Rule::endianness_declaration, node.as_rule())
302     } else {
303         Ok(ast::Endianness {
304             loc: node.as_loc(context),
305             value: match node.as_str().trim() {
306                 "little_endian_packets" => ast::EndiannessValue::LittleEndian,
307                 "big_endian_packets" => ast::EndiannessValue::BigEndian,
308                 _ => unreachable!(),
309             },
310         })
311     }
312 }
313 
parse_constraint(node: Node<'_>, context: &Context) -> Result<ast::Constraint, String>314 fn parse_constraint(node: Node<'_>, context: &Context) -> Result<ast::Constraint, String> {
315     if node.as_rule() != Rule::constraint {
316         err_unexpected_rule(Rule::constraint, node.as_rule())
317     } else {
318         let loc = node.as_loc(context);
319         let mut children = node.children();
320         let id = parse_identifier(&mut children)?;
321         let (tag_id, value) = parse_identifier_or_integer(&mut children)?;
322         Ok(ast::Constraint { id, loc, value, tag_id })
323     }
324 }
325 
parse_constraint_list_opt( iter: &mut NodeIterator<'_>, context: &Context, ) -> Result<Vec<ast::Constraint>, String>326 fn parse_constraint_list_opt(
327     iter: &mut NodeIterator<'_>,
328     context: &Context,
329 ) -> Result<Vec<ast::Constraint>, String> {
330     maybe(iter, Rule::constraint_list)
331         .map_or(Ok(vec![]), |n| n.children().map(|n| parse_constraint(n, context)).collect())
332 }
333 
parse_enum_value(node: Node<'_>, context: &Context) -> Result<ast::TagValue, String>334 fn parse_enum_value(node: Node<'_>, context: &Context) -> Result<ast::TagValue, String> {
335     if node.as_rule() != Rule::enum_value {
336         err_unexpected_rule(Rule::enum_value, node.as_rule())
337     } else {
338         let loc = node.as_loc(context);
339         let mut children = node.children();
340         let id = parse_identifier(&mut children)?;
341         let value = parse_integer(&mut children)?;
342         Ok(ast::TagValue { id, loc, value })
343     }
344 }
345 
parse_enum_value_list_opt( iter: &mut NodeIterator<'_>, context: &Context, ) -> Result<Vec<ast::TagValue>, String>346 fn parse_enum_value_list_opt(
347     iter: &mut NodeIterator<'_>,
348     context: &Context,
349 ) -> Result<Vec<ast::TagValue>, String> {
350     maybe(iter, Rule::enum_value_list)
351         .map_or(Ok(vec![]), |n| n.children().map(|n| parse_enum_value(n, context)).collect())
352 }
353 
parse_enum_range(node: Node<'_>, context: &Context) -> Result<ast::TagRange, String>354 fn parse_enum_range(node: Node<'_>, context: &Context) -> Result<ast::TagRange, String> {
355     if node.as_rule() != Rule::enum_range {
356         err_unexpected_rule(Rule::enum_range, node.as_rule())
357     } else {
358         let loc = node.as_loc(context);
359         let mut children = node.children();
360         let id = parse_identifier(&mut children)?;
361         let start = parse_integer(&mut children)?;
362         let end = parse_integer(&mut children)?;
363         let tags = parse_enum_value_list_opt(&mut children, context)?;
364         Ok(ast::TagRange { id, loc, range: start..=end, tags })
365     }
366 }
367 
parse_enum_other(node: Node<'_>, context: &Context) -> Result<ast::TagOther, String>368 fn parse_enum_other(node: Node<'_>, context: &Context) -> Result<ast::TagOther, String> {
369     if node.as_rule() != Rule::enum_other {
370         err_unexpected_rule(Rule::enum_other, node.as_rule())
371     } else {
372         let loc = node.as_loc(context);
373         let mut children = node.children();
374         let id = parse_identifier(&mut children)?;
375         Ok(ast::TagOther { id, loc })
376     }
377 }
378 
parse_enum_tag(node: Node<'_>, context: &Context) -> Result<ast::Tag, String>379 fn parse_enum_tag(node: Node<'_>, context: &Context) -> Result<ast::Tag, String> {
380     if node.as_rule() != Rule::enum_tag {
381         err_unexpected_rule(Rule::enum_tag, node.as_rule())
382     } else {
383         match node.children().next() {
384             Some(node) if node.as_rule() == Rule::enum_value => {
385                 Ok(ast::Tag::Value(parse_enum_value(node, context)?))
386             }
387             Some(node) if node.as_rule() == Rule::enum_range => {
388                 Ok(ast::Tag::Range(parse_enum_range(node, context)?))
389             }
390             Some(node) if node.as_rule() == Rule::enum_other => {
391                 Ok(ast::Tag::Other(parse_enum_other(node, context)?))
392             }
393             Some(node) => Err(format!(
394                 "expected rule {:?} or {:?}, got {:?}",
395                 Rule::enum_value,
396                 Rule::enum_range,
397                 node.as_rule()
398             )),
399             None => Err(format!(
400                 "expected rule {:?} or {:?}, got nothing",
401                 Rule::enum_value,
402                 Rule::enum_range
403             )),
404         }
405     }
406 }
407 
parse_enum_tag_list( iter: &mut NodeIterator<'_>, context: &Context, ) -> Result<Vec<ast::Tag>, String>408 fn parse_enum_tag_list(
409     iter: &mut NodeIterator<'_>,
410     context: &Context,
411 ) -> Result<Vec<ast::Tag>, String> {
412     expect(iter, Rule::enum_tag_list)
413         .and_then(|n| n.children().map(|n| parse_enum_tag(n, context)).collect())
414 }
415 
parse_field(node: Node<'_>, context: &Context) -> Result<ast::Field, String>416 fn parse_field(node: Node<'_>, context: &Context) -> Result<ast::Field, String> {
417     let loc = node.as_loc(context);
418     let mut children = node.children();
419     let desc = children.next().unwrap();
420     let cond = children.next();
421     let rule = desc.as_rule();
422     let mut children = desc.children();
423     Ok(ast::Field {
424         loc,
425         key: context.field_key(),
426         cond: cond.map(|constraint| parse_constraint(constraint, context)).transpose()?,
427         desc: match rule {
428             Rule::checksum_field => {
429                 let field_id = parse_identifier(&mut children)?;
430                 ast::FieldDesc::Checksum { field_id }
431             }
432             Rule::padding_field => {
433                 let size = parse_integer(&mut children)?;
434                 ast::FieldDesc::Padding { size }
435             }
436             Rule::size_field => {
437                 let field_id = match children.next() {
438                     Some(n) if n.as_rule() == Rule::identifier => n.as_string(),
439                     Some(n) if n.as_rule() == Rule::payload_identifier => n.as_string(),
440                     Some(n) if n.as_rule() == Rule::body_identifier => n.as_string(),
441                     Some(n) => err_unexpected_rule(Rule::identifier, n.as_rule())?,
442                     None => err_missing_rule(Rule::identifier)?,
443                 };
444                 let width = parse_integer(&mut children)?;
445                 ast::FieldDesc::Size { field_id, width }
446             }
447             Rule::count_field => {
448                 let field_id = parse_identifier(&mut children)?;
449                 let width = parse_integer(&mut children)?;
450                 ast::FieldDesc::Count { field_id, width }
451             }
452             Rule::elementsize_field => {
453                 let field_id = parse_identifier(&mut children)?;
454                 let width = parse_integer(&mut children)?;
455                 ast::FieldDesc::ElementSize { field_id, width }
456             }
457             Rule::body_field => ast::FieldDesc::Body,
458             Rule::payload_field => {
459                 let size_modifier = parse_size_modifier_opt(&mut children);
460                 ast::FieldDesc::Payload { size_modifier }
461             }
462             Rule::fixed_field => match children.next() {
463                 Some(n) if n.as_rule() == Rule::integer => {
464                     let value = n.as_usize()?;
465                     let width = parse_integer(&mut children)?;
466                     ast::FieldDesc::FixedScalar { width, value }
467                 }
468                 Some(n) if n.as_rule() == Rule::identifier => {
469                     let tag_id = n.as_string();
470                     let enum_id = parse_identifier(&mut children)?;
471                     ast::FieldDesc::FixedEnum { enum_id, tag_id }
472                 }
473                 _ => unreachable!(),
474             },
475             Rule::reserved_field => {
476                 let width = parse_integer(&mut children)?;
477                 ast::FieldDesc::Reserved { width }
478             }
479             Rule::array_field => {
480                 let id = parse_identifier(&mut children)?;
481                 let (type_id, width) = parse_identifier_or_integer(&mut children)?;
482                 let (size, size_modifier) = match children.next() {
483                     Some(n) if n.as_rule() == Rule::integer => (Some(n.as_usize()?), None),
484                     Some(n) if n.as_rule() == Rule::size_modifier => (None, Some(n.as_string())),
485                     Some(n) => {
486                         return Err(format!(
487                             "expected rule {:?} or {:?}, got {:?}",
488                             Rule::integer,
489                             Rule::size_modifier,
490                             n.as_rule()
491                         ))
492                     }
493                     None => (None, None),
494                 };
495                 ast::FieldDesc::Array { id, type_id, width, size, size_modifier }
496             }
497             Rule::scalar_field => {
498                 let id = parse_identifier(&mut children)?;
499                 let width = parse_integer(&mut children)?;
500                 ast::FieldDesc::Scalar { id, width }
501             }
502             Rule::typedef_field => {
503                 let id = parse_identifier(&mut children)?;
504                 let type_id = parse_identifier(&mut children)?;
505                 ast::FieldDesc::Typedef { id, type_id }
506             }
507             Rule::group_field => {
508                 let group_id = parse_identifier(&mut children)?;
509                 let constraints = parse_constraint_list_opt(&mut children, context)?;
510                 ast::FieldDesc::Group { group_id, constraints }
511             }
512             _ => return Err(format!("expected rule *_field, got {:?}", rule)),
513         },
514     })
515 }
516 
parse_field_list(iter: &mut NodeIterator, context: &Context) -> Result<Vec<ast::Field>, String>517 fn parse_field_list(iter: &mut NodeIterator, context: &Context) -> Result<Vec<ast::Field>, String> {
518     expect(iter, Rule::field_list)
519         .and_then(|n| n.children().map(|n| parse_field(n, context)).collect())
520 }
521 
parse_field_list_opt( iter: &mut NodeIterator, context: &Context, ) -> Result<Vec<ast::Field>, String>522 fn parse_field_list_opt(
523     iter: &mut NodeIterator,
524     context: &Context,
525 ) -> Result<Vec<ast::Field>, String> {
526     maybe(iter, Rule::field_list)
527         .map_or(Ok(vec![]), |n| n.children().map(|n| parse_field(n, context)).collect())
528 }
529 
parse_toplevel(root: Node<'_>, context: &Context) -> Result<ast::File, String>530 fn parse_toplevel(root: Node<'_>, context: &Context) -> Result<ast::File, String> {
531     let mut toplevel_comments = vec![];
532     let mut file = ast::File::new(context.file);
533 
534     let mut comment_start = vec![];
535     for token in root.clone().tokens() {
536         match token {
537             Token::Start { rule: Rule::COMMENT, pos } => comment_start.push(pos),
538             Token::End { rule: Rule::COMMENT, pos } => {
539                 let start_pos = comment_start.pop().unwrap();
540                 file.comments.push(ast::Comment {
541                     loc: ast::SourceRange {
542                         file: context.file,
543                         start: ast::SourceLocation::new(start_pos.pos(), context.line_starts),
544                         end: ast::SourceLocation::new(pos.pos(), context.line_starts),
545                     },
546                     text: start_pos.span(&pos).as_str().to_owned(),
547                 })
548             }
549             _ => (),
550         }
551     }
552 
553     for node in root.children() {
554         let loc = node.as_loc(context);
555         let rule = node.as_rule();
556         match rule {
557             Rule::endianness_declaration => file.endianness = parse_endianness(node, context)?,
558             Rule::checksum_declaration => {
559                 let mut children = node.children();
560                 expect(&mut children, Rule::CHECKSUM)?;
561                 let id = parse_identifier(&mut children)?;
562                 let width = parse_integer(&mut children)?;
563                 let function = parse_string(&mut children)?;
564                 file.declarations.push(ast::Decl {
565                     loc,
566                     key: context.decl_key(),
567                     desc: ast::DeclDesc::Checksum { id, function, width },
568                 })
569             }
570             Rule::custom_field_declaration => {
571                 let mut children = node.children();
572                 expect(&mut children, Rule::CUSTOM_FIELD)?;
573                 let id = parse_identifier(&mut children)?;
574                 let width = parse_integer_opt(&mut children)?;
575                 let function = parse_string(&mut children)?;
576                 file.declarations.push(ast::Decl {
577                     loc,
578                     key: context.decl_key(),
579                     desc: ast::DeclDesc::CustomField { id, function, width },
580                 })
581             }
582             Rule::enum_declaration => {
583                 let mut children = node.children();
584                 expect(&mut children, Rule::ENUM)?;
585                 let id = parse_identifier(&mut children)?;
586                 let width = parse_integer(&mut children)?;
587                 let tags = parse_enum_tag_list(&mut children, context)?;
588                 file.declarations.push(ast::Decl {
589                     loc,
590                     key: context.decl_key(),
591                     desc: ast::DeclDesc::Enum { id, width, tags },
592                 })
593             }
594             Rule::packet_declaration => {
595                 let mut children = node.children();
596                 expect(&mut children, Rule::PACKET)?;
597                 let id = parse_identifier(&mut children)?;
598                 let parent_id = parse_identifier_opt(&mut children)?;
599                 let constraints = parse_constraint_list_opt(&mut children, context)?;
600                 let fields = parse_field_list_opt(&mut children, context)?;
601                 file.declarations.push(ast::Decl {
602                     loc,
603                     key: context.decl_key(),
604                     desc: ast::DeclDesc::Packet { id, parent_id, constraints, fields },
605                 })
606             }
607             Rule::struct_declaration => {
608                 let mut children = node.children();
609                 expect(&mut children, Rule::STRUCT)?;
610                 let id = parse_identifier(&mut children)?;
611                 let parent_id = parse_identifier_opt(&mut children)?;
612                 let constraints = parse_constraint_list_opt(&mut children, context)?;
613                 let fields = parse_field_list_opt(&mut children, context)?;
614                 file.declarations.push(ast::Decl {
615                     loc,
616                     key: context.decl_key(),
617                     desc: ast::DeclDesc::Struct { id, parent_id, constraints, fields },
618                 })
619             }
620             Rule::group_declaration => {
621                 let mut children = node.children();
622                 expect(&mut children, Rule::GROUP)?;
623                 let id = parse_identifier(&mut children)?;
624                 let fields = parse_field_list(&mut children, context)?;
625                 file.declarations.push(ast::Decl {
626                     loc,
627                     key: context.decl_key(),
628                     desc: ast::DeclDesc::Group { id, fields },
629                 })
630             }
631             Rule::test_declaration => {}
632             Rule::EOI => (),
633             _ => unreachable!(),
634         }
635     }
636     file.comments.append(&mut toplevel_comments);
637     file.max_key = context.key.get();
638     Ok(file)
639 }
640 
641 /// Parse PDL source code from a string.
642 ///
643 /// The file is added to the compilation database under the provided
644 /// name.
parse_inline( sources: &mut ast::SourceDatabase, name: &str, source: String, ) -> Result<ast::File, Diagnostic<ast::FileId>>645 pub fn parse_inline(
646     sources: &mut ast::SourceDatabase,
647     name: &str,
648     source: String,
649 ) -> Result<ast::File, Diagnostic<ast::FileId>> {
650     let root = PDLParser::parse(Rule::file, &source)
651         .map_err(|e| {
652             Diagnostic::error()
653                 .with_message(format!("failed to parse input file '{}': {}", name, e))
654         })?
655         .next()
656         .unwrap();
657     let line_starts: Vec<_> = files::line_starts(&source).collect();
658     let file = sources.add(name.to_owned(), source.clone());
659     parse_toplevel(root, &Context { file, line_starts: &line_starts, key: std::cell::Cell::new(0) })
660         .map_err(|e| Diagnostic::error().with_message(e))
661 }
662 
663 /// Parse a new source file.
664 ///
665 /// The source file is fully read and added to the compilation
666 /// database. Returns the constructed AST, or a descriptive error
667 /// message in case of syntax error.
parse_file( sources: &mut ast::SourceDatabase, name: &str, ) -> Result<ast::File, Diagnostic<ast::FileId>>668 pub fn parse_file(
669     sources: &mut ast::SourceDatabase,
670     name: &str,
671 ) -> Result<ast::File, Diagnostic<ast::FileId>> {
672     let source = std::fs::read_to_string(name).map_err(|e| {
673         Diagnostic::error().with_message(format!("failed to read input file '{}': {}", name, e))
674     })?;
675     parse_inline(sources, name, source)
676 }
677 
678 #[cfg(test)]
679 mod test {
680     use super::*;
681 
682     #[test]
endianness_is_set()683     fn endianness_is_set() {
684         // The file starts out with a placeholder little-endian value.
685         // This tests that we update it while parsing.
686         let mut db = ast::SourceDatabase::new();
687         let file = parse_inline(&mut db, "stdin", String::from("  big_endian_packets  ")).unwrap();
688         assert_eq!(file.endianness.value, ast::EndiannessValue::BigEndian);
689         assert_ne!(file.endianness.loc, ast::SourceRange::default());
690     }
691 
692     #[test]
test_parse_string_bare()693     fn test_parse_string_bare() {
694         let mut pairs = PDLParser::parse(Rule::string, r#""test""#).unwrap();
695 
696         assert_eq!(parse_string(&mut pairs).as_deref(), Ok("test"));
697         assert_eq!(pairs.next(), None, "pairs is empty");
698     }
699 
700     #[test]
test_parse_string_space()701     fn test_parse_string_space() {
702         let mut pairs = PDLParser::parse(Rule::string, r#""test with space""#).unwrap();
703 
704         assert_eq!(parse_string(&mut pairs).as_deref(), Ok("test with space"));
705         assert_eq!(pairs.next(), None, "pairs is empty");
706     }
707 
708     #[test]
709     #[should_panic] /* This is not supported */
test_parse_string_escape()710     fn test_parse_string_escape() {
711         let mut pairs = PDLParser::parse(Rule::string, r#""\"test\"""#).unwrap();
712 
713         assert_eq!(parse_string(&mut pairs).as_deref(), Ok(r#""test""#));
714         assert_eq!(pairs.next(), None, "pairs is empty");
715     }
716 
717     #[test]
test_no_whitespace_between_keywords()718     fn test_no_whitespace_between_keywords() {
719         // Validate that the parser rejects inputs where whitespaces
720         // are not applied between alphabetical keywords and identifiers.
721         let mut db = ast::SourceDatabase::new();
722         assert!(parse_inline(
723             &mut db,
724             "test",
725             r#"
726             little_endian_packetsstructx{foo:8}
727             "#
728             .to_owned()
729         )
730         .is_err());
731 
732         let result = parse_inline(
733             &mut db,
734             "test",
735             r#"
736             little_endian_packets
737             struct x { foo:8 }
738             "#
739             .to_owned(),
740         );
741         println!("{:?}", result);
742         assert!(result.is_ok());
743     }
744 }
745