• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 codespan_reporting::diagnostic::Diagnostic;
16 use codespan_reporting::files;
17 use pest::iterators::{Pair, Pairs};
18 use pest::{Parser, Token};
19 use std::iter::{Filter, Peekable};
20 
21 pub mod ast {
22     use serde::Serialize;
23 
24     #[derive(Debug, Serialize, Default, PartialEq, Eq)]
25     pub struct Annotation;
26 
27     impl crate::ast::Annotation for Annotation {
28         type FieldAnnotation = ();
29         type DeclAnnotation = ();
30     }
31 
32     pub type Field = crate::ast::Field<Annotation>;
33     pub type Decl = crate::ast::Decl<Annotation>;
34     pub type File = crate::ast::File<Annotation>;
35 }
36 
37 // Generate the PDL parser.
38 // TODO: use #[grammar = "pdl.pest"]
39 // currently not possible because CARGO_MANIFEST_DIR is not set
40 // in soong environment.
41 #[derive(pest_derive::Parser)]
42 #[grammar_inline = r#"
43 WHITESPACE = _{ " " | "\n" }
44 COMMENT = { block_comment | line_comment }
45 
46 block_comment = { "/*" ~ (!"*/" ~ ANY)* ~ "*/" }
47 line_comment = { "//" ~ (!"\n" ~ ANY)* }
48 
49 alpha = { 'a'..'z' | 'A'..'Z' }
50 digit = { '0'..'9' }
51 hexdigit = { digit | 'a'..'f' | 'A'..'F' }
52 alphanum = { alpha | digit | "_" }
53 
54 identifier = @{ alpha ~ alphanum* }
55 payload_identifier = @{ "_payload_" }
56 body_identifier = @{ "_body_" }
57 intvalue = @{ digit+ }
58 hexvalue = @{ ("0x"|"0X") ~ hexdigit+ }
59 integer = @{ hexvalue | intvalue }
60 string = @{ "\"" ~ (!"\"" ~ ANY)* ~ "\"" }
61 size_modifier = @{ "+" ~ intvalue }
62 
63 endianness_declaration = { "little_endian_packets" | "big_endian_packets" }
64 
65 enum_value = { identifier ~ "=" ~ integer }
66 enum_value_list = { enum_value ~ ("," ~ enum_value)* ~ ","? }
67 enum_range = {
68     identifier ~ "=" ~ integer ~ ".." ~ integer ~ ("{" ~
69         enum_value_list ~
70     "}")?
71 }
72 enum_tag = { enum_range | enum_value }
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 = _{
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_list = { field ~ ("," ~ field)* ~ ","? }
118 
119 packet_declaration = {
120    "packet" ~ identifier ~
121         (":" ~ identifier)? ~
122            ("(" ~ constraint_list ~ ")")? ~
123     "{" ~
124         field_list? ~
125     "}"
126 }
127 
128 struct_declaration = {
129     "struct" ~ identifier ~
130         (":" ~ identifier)? ~
131            ("(" ~ constraint_list ~ ")")? ~
132     "{" ~
133         field_list? ~
134     "}"
135 }
136 
137 group_declaration = {
138     "group" ~ identifier ~ "{" ~ field_list ~ "}"
139 }
140 
141 checksum_declaration = {
142     "checksum" ~ identifier ~ ":" ~ integer ~ string
143 }
144 
145 custom_field_declaration = {
146     "custom_field" ~ identifier ~ (":" ~ integer)? ~ string
147 }
148 
149 test_case = { string }
150 test_case_list = _{ test_case ~ ("," ~ test_case)* ~ ","? }
151 test_declaration = {
152     "test" ~ identifier ~ "{" ~
153         test_case_list ~
154     "}"
155 }
156 
157 declaration = _{
158     enum_declaration |
159     packet_declaration |
160     struct_declaration |
161     group_declaration |
162     checksum_declaration |
163     custom_field_declaration |
164     test_declaration
165 }
166 
167 file = {
168     SOI ~
169     endianness_declaration ~
170     declaration* ~
171     EOI
172 }
173 "#]
174 pub struct PDLParser;
175 
176 type Node<'i> = Pair<'i, Rule>;
177 type NodeIterator<'i> = Peekable<Filter<Pairs<'i, Rule>, fn(&Node<'i>) -> bool>>;
178 type Context<'a> = (crate::ast::FileId, &'a Vec<usize>);
179 
180 trait Helpers<'i> {
children(self) -> NodeIterator<'i>181     fn children(self) -> NodeIterator<'i>;
as_loc(&self, context: &Context) -> crate::ast::SourceRange182     fn as_loc(&self, context: &Context) -> crate::ast::SourceRange;
as_string(&self) -> String183     fn as_string(&self) -> String;
as_usize(&self) -> Result<usize, String>184     fn as_usize(&self) -> Result<usize, String>;
185 }
186 
187 impl<'i> Helpers<'i> for Node<'i> {
children(self) -> NodeIterator<'i>188     fn children(self) -> NodeIterator<'i> {
189         self.into_inner().filter((|n| n.as_rule() != Rule::COMMENT) as fn(&Self) -> bool).peekable()
190     }
191 
as_loc(&self, context: &Context) -> crate::ast::SourceRange192     fn as_loc(&self, context: &Context) -> crate::ast::SourceRange {
193         let span = self.as_span();
194         crate::ast::SourceRange {
195             file: context.0,
196             start: crate::ast::SourceLocation::new(span.start_pos().pos(), context.1),
197             end: crate::ast::SourceLocation::new(span.end_pos().pos(), context.1),
198         }
199     }
200 
as_string(&self) -> String201     fn as_string(&self) -> String {
202         self.as_str().to_owned()
203     }
204 
as_usize(&self) -> Result<usize, String>205     fn as_usize(&self) -> Result<usize, String> {
206         let text = self.as_str();
207         if let Some(num) = text.strip_prefix("0x") {
208             usize::from_str_radix(num, 16)
209                 .map_err(|_| format!("cannot convert '{}' to usize", self.as_str()))
210         } else {
211             #[allow(clippy::from_str_radix_10)]
212             usize::from_str_radix(text, 10)
213                 .map_err(|_| format!("cannot convert '{}' to usize", self.as_str()))
214         }
215     }
216 }
217 
err_unexpected_rule<T>(expected: Rule, found: Rule) -> Result<T, String>218 fn err_unexpected_rule<T>(expected: Rule, found: Rule) -> Result<T, String> {
219     Err(format!("expected rule {:?}, got {:?}", expected, found))
220 }
221 
err_missing_rule<T>(expected: Rule) -> Result<T, String>222 fn err_missing_rule<T>(expected: Rule) -> Result<T, String> {
223     Err(format!("expected rule {:?}, got nothing", expected))
224 }
225 
expect<'i>(iter: &mut impl Iterator<Item = Node<'i>>, rule: Rule) -> Result<Node<'i>, String>226 fn expect<'i>(iter: &mut impl Iterator<Item = Node<'i>>, rule: Rule) -> Result<Node<'i>, String> {
227     match iter.next() {
228         Some(node) if node.as_rule() == rule => Ok(node),
229         Some(node) => err_unexpected_rule(rule, node.as_rule()),
230         None => err_missing_rule(rule),
231     }
232 }
233 
maybe<'i>(iter: &mut NodeIterator<'i>, rule: Rule) -> Option<Node<'i>>234 fn maybe<'i>(iter: &mut NodeIterator<'i>, rule: Rule) -> Option<Node<'i>> {
235     iter.next_if(|n| n.as_rule() == rule)
236 }
237 
parse_identifier(iter: &mut NodeIterator<'_>) -> Result<String, String>238 fn parse_identifier(iter: &mut NodeIterator<'_>) -> Result<String, String> {
239     expect(iter, Rule::identifier).map(|n| n.as_string())
240 }
241 
parse_integer(iter: &mut NodeIterator<'_>) -> Result<usize, String>242 fn parse_integer(iter: &mut NodeIterator<'_>) -> Result<usize, String> {
243     expect(iter, Rule::integer).and_then(|n| n.as_usize())
244 }
245 
parse_identifier_opt(iter: &mut NodeIterator<'_>) -> Result<Option<String>, String>246 fn parse_identifier_opt(iter: &mut NodeIterator<'_>) -> Result<Option<String>, String> {
247     Ok(maybe(iter, Rule::identifier).map(|n| n.as_string()))
248 }
249 
parse_integer_opt(iter: &mut NodeIterator<'_>) -> Result<Option<usize>, String>250 fn parse_integer_opt(iter: &mut NodeIterator<'_>) -> Result<Option<usize>, String> {
251     maybe(iter, Rule::integer).map(|n| n.as_usize()).transpose()
252 }
253 
parse_identifier_or_integer( iter: &mut NodeIterator<'_>, ) -> Result<(Option<String>, Option<usize>), String>254 fn parse_identifier_or_integer(
255     iter: &mut NodeIterator<'_>,
256 ) -> Result<(Option<String>, Option<usize>), String> {
257     match iter.next() {
258         Some(n) if n.as_rule() == Rule::identifier => Ok((Some(n.as_string()), None)),
259         Some(n) if n.as_rule() == Rule::integer => Ok((None, Some(n.as_usize()?))),
260         Some(n) => Err(format!(
261             "expected rule {:?} or {:?}, got {:?}",
262             Rule::identifier,
263             Rule::integer,
264             n.as_rule()
265         )),
266         None => {
267             Err(format!("expected rule {:?} or {:?}, got nothing", Rule::identifier, Rule::integer))
268         }
269     }
270 }
271 
parse_string<'i>(iter: &mut impl Iterator<Item = Node<'i>>) -> Result<String, String>272 fn parse_string<'i>(iter: &mut impl Iterator<Item = Node<'i>>) -> Result<String, String> {
273     expect(iter, Rule::string)
274         .map(|n| n.as_str())
275         .and_then(|s| s.strip_prefix('"').ok_or_else(|| "expected \" prefix".to_owned()))
276         .and_then(|s| s.strip_suffix('"').ok_or_else(|| "expected \" suffix".to_owned()))
277         .map(|s| s.to_owned())
278 }
279 
parse_size_modifier_opt(iter: &mut NodeIterator<'_>) -> Option<String>280 fn parse_size_modifier_opt(iter: &mut NodeIterator<'_>) -> Option<String> {
281     maybe(iter, Rule::size_modifier).map(|n| n.as_string())
282 }
283 
parse_endianness(node: Node<'_>, context: &Context) -> Result<crate::ast::Endianness, String>284 fn parse_endianness(node: Node<'_>, context: &Context) -> Result<crate::ast::Endianness, String> {
285     if node.as_rule() != Rule::endianness_declaration {
286         err_unexpected_rule(Rule::endianness_declaration, node.as_rule())
287     } else {
288         Ok(crate::ast::Endianness {
289             loc: node.as_loc(context),
290             value: match node.as_str() {
291                 "little_endian_packets" => crate::ast::EndiannessValue::LittleEndian,
292                 "big_endian_packets" => crate::ast::EndiannessValue::BigEndian,
293                 _ => unreachable!(),
294             },
295         })
296     }
297 }
298 
parse_constraint(node: Node<'_>, context: &Context) -> Result<crate::ast::Constraint, String>299 fn parse_constraint(node: Node<'_>, context: &Context) -> Result<crate::ast::Constraint, String> {
300     if node.as_rule() != Rule::constraint {
301         err_unexpected_rule(Rule::constraint, node.as_rule())
302     } else {
303         let loc = node.as_loc(context);
304         let mut children = node.children();
305         let id = parse_identifier(&mut children)?;
306         let (tag_id, value) = parse_identifier_or_integer(&mut children)?;
307         Ok(crate::ast::Constraint { id, loc, value, tag_id })
308     }
309 }
310 
parse_constraint_list_opt( iter: &mut NodeIterator<'_>, context: &Context, ) -> Result<Vec<crate::ast::Constraint>, String>311 fn parse_constraint_list_opt(
312     iter: &mut NodeIterator<'_>,
313     context: &Context,
314 ) -> Result<Vec<crate::ast::Constraint>, String> {
315     maybe(iter, Rule::constraint_list)
316         .map_or(Ok(vec![]), |n| n.children().map(|n| parse_constraint(n, context)).collect())
317 }
318 
parse_enum_value(node: Node<'_>, context: &Context) -> Result<crate::ast::TagValue, String>319 fn parse_enum_value(node: Node<'_>, context: &Context) -> Result<crate::ast::TagValue, String> {
320     if node.as_rule() != Rule::enum_value {
321         err_unexpected_rule(Rule::enum_value, node.as_rule())
322     } else {
323         let loc = node.as_loc(context);
324         let mut children = node.children();
325         let id = parse_identifier(&mut children)?;
326         let value = parse_integer(&mut children)?;
327         Ok(crate::ast::TagValue { id, loc, value })
328     }
329 }
330 
parse_enum_value_list_opt( iter: &mut NodeIterator<'_>, context: &Context, ) -> Result<Vec<crate::ast::TagValue>, String>331 fn parse_enum_value_list_opt(
332     iter: &mut NodeIterator<'_>,
333     context: &Context,
334 ) -> Result<Vec<crate::ast::TagValue>, String> {
335     maybe(iter, Rule::enum_value_list)
336         .map_or(Ok(vec![]), |n| n.children().map(|n| parse_enum_value(n, context)).collect())
337 }
338 
parse_enum_range(node: Node<'_>, context: &Context) -> Result<crate::ast::TagRange, String>339 fn parse_enum_range(node: Node<'_>, context: &Context) -> Result<crate::ast::TagRange, String> {
340     if node.as_rule() != Rule::enum_range {
341         err_unexpected_rule(Rule::enum_range, node.as_rule())
342     } else {
343         let loc = node.as_loc(context);
344         let mut children = node.children();
345         let id = parse_identifier(&mut children)?;
346         let start = parse_integer(&mut children)?;
347         let end = parse_integer(&mut children)?;
348         let tags = parse_enum_value_list_opt(&mut children, context)?;
349         Ok(crate::ast::TagRange { id, loc, range: start..=end, tags })
350     }
351 }
352 
parse_enum_tag(node: Node<'_>, context: &Context) -> Result<crate::ast::Tag, String>353 fn parse_enum_tag(node: Node<'_>, context: &Context) -> Result<crate::ast::Tag, String> {
354     if node.as_rule() != Rule::enum_tag {
355         err_unexpected_rule(Rule::enum_tag, node.as_rule())
356     } else {
357         match node.children().next() {
358             Some(node) if node.as_rule() == Rule::enum_value => {
359                 Ok(crate::ast::Tag::Value(parse_enum_value(node, context)?))
360             }
361             Some(node) if node.as_rule() == Rule::enum_range => {
362                 Ok(crate::ast::Tag::Range(parse_enum_range(node, context)?))
363             }
364             Some(node) => Err(format!(
365                 "expected rule {:?} or {:?}, got {:?}",
366                 Rule::enum_value,
367                 Rule::enum_range,
368                 node.as_rule()
369             )),
370             None => Err(format!(
371                 "expected rule {:?} or {:?}, got nothing",
372                 Rule::enum_value,
373                 Rule::enum_range
374             )),
375         }
376     }
377 }
378 
parse_enum_tag_list( iter: &mut NodeIterator<'_>, context: &Context, ) -> Result<Vec<crate::ast::Tag>, String>379 fn parse_enum_tag_list(
380     iter: &mut NodeIterator<'_>,
381     context: &Context,
382 ) -> Result<Vec<crate::ast::Tag>, String> {
383     expect(iter, Rule::enum_tag_list)
384         .and_then(|n| n.children().map(|n| parse_enum_tag(n, context)).collect())
385 }
386 
parse_field(node: Node<'_>, context: &Context) -> Result<ast::Field, String>387 fn parse_field(node: Node<'_>, context: &Context) -> Result<ast::Field, String> {
388     let loc = node.as_loc(context);
389     let rule = node.as_rule();
390     let mut children = node.children();
391     Ok(crate::ast::Field {
392         loc,
393         annot: Default::default(),
394         desc: match rule {
395             Rule::checksum_field => {
396                 let field_id = parse_identifier(&mut children)?;
397                 crate::ast::FieldDesc::Checksum { field_id }
398             }
399             Rule::padding_field => {
400                 let size = parse_integer(&mut children)?;
401                 crate::ast::FieldDesc::Padding { size }
402             }
403             Rule::size_field => {
404                 let field_id = match children.next() {
405                     Some(n) if n.as_rule() == Rule::identifier => n.as_string(),
406                     Some(n) if n.as_rule() == Rule::payload_identifier => n.as_string(),
407                     Some(n) if n.as_rule() == Rule::body_identifier => n.as_string(),
408                     Some(n) => err_unexpected_rule(Rule::identifier, n.as_rule())?,
409                     None => err_missing_rule(Rule::identifier)?,
410                 };
411                 let width = parse_integer(&mut children)?;
412                 crate::ast::FieldDesc::Size { field_id, width }
413             }
414             Rule::count_field => {
415                 let field_id = parse_identifier(&mut children)?;
416                 let width = parse_integer(&mut children)?;
417                 crate::ast::FieldDesc::Count { field_id, width }
418             }
419             Rule::elementsize_field => {
420                 let field_id = parse_identifier(&mut children)?;
421                 let width = parse_integer(&mut children)?;
422                 crate::ast::FieldDesc::ElementSize { field_id, width }
423             }
424             Rule::body_field => crate::ast::FieldDesc::Body,
425             Rule::payload_field => {
426                 let size_modifier = parse_size_modifier_opt(&mut children);
427                 crate::ast::FieldDesc::Payload { size_modifier }
428             }
429             Rule::fixed_field => match children.next() {
430                 Some(n) if n.as_rule() == Rule::integer => {
431                     let value = n.as_usize()?;
432                     let width = parse_integer(&mut children)?;
433                     crate::ast::FieldDesc::FixedScalar { width, value }
434                 }
435                 Some(n) if n.as_rule() == Rule::identifier => {
436                     let tag_id = n.as_string();
437                     let enum_id = parse_identifier(&mut children)?;
438                     crate::ast::FieldDesc::FixedEnum { enum_id, tag_id }
439                 }
440                 _ => unreachable!(),
441             },
442             Rule::reserved_field => {
443                 let width = parse_integer(&mut children)?;
444                 crate::ast::FieldDesc::Reserved { width }
445             }
446             Rule::array_field => {
447                 let id = parse_identifier(&mut children)?;
448                 let (type_id, width) = parse_identifier_or_integer(&mut children)?;
449                 let (size, size_modifier) = match children.next() {
450                     Some(n) if n.as_rule() == Rule::integer => (Some(n.as_usize()?), None),
451                     Some(n) if n.as_rule() == Rule::size_modifier => (None, Some(n.as_string())),
452                     Some(n) => {
453                         return Err(format!(
454                             "expected rule {:?} or {:?}, got {:?}",
455                             Rule::integer,
456                             Rule::size_modifier,
457                             n.as_rule()
458                         ))
459                     }
460                     None => (None, None),
461                 };
462                 crate::ast::FieldDesc::Array { id, type_id, width, size, size_modifier }
463             }
464             Rule::scalar_field => {
465                 let id = parse_identifier(&mut children)?;
466                 let width = parse_integer(&mut children)?;
467                 crate::ast::FieldDesc::Scalar { id, width }
468             }
469             Rule::typedef_field => {
470                 let id = parse_identifier(&mut children)?;
471                 let type_id = parse_identifier(&mut children)?;
472                 crate::ast::FieldDesc::Typedef { id, type_id }
473             }
474             Rule::group_field => {
475                 let group_id = parse_identifier(&mut children)?;
476                 let constraints = parse_constraint_list_opt(&mut children, context)?;
477                 crate::ast::FieldDesc::Group { group_id, constraints }
478             }
479             _ => return Err(format!("expected rule *_field, got {:?}", rule)),
480         },
481     })
482 }
483 
parse_field_list(iter: &mut NodeIterator, context: &Context) -> Result<Vec<ast::Field>, String>484 fn parse_field_list(iter: &mut NodeIterator, context: &Context) -> Result<Vec<ast::Field>, String> {
485     expect(iter, Rule::field_list)
486         .and_then(|n| n.children().map(|n| parse_field(n, context)).collect())
487 }
488 
parse_field_list_opt( iter: &mut NodeIterator, context: &Context, ) -> Result<Vec<ast::Field>, String>489 fn parse_field_list_opt(
490     iter: &mut NodeIterator,
491     context: &Context,
492 ) -> Result<Vec<ast::Field>, String> {
493     maybe(iter, Rule::field_list)
494         .map_or(Ok(vec![]), |n| n.children().map(|n| parse_field(n, context)).collect())
495 }
496 
parse_toplevel(root: Node<'_>, context: &Context) -> Result<ast::File, String>497 fn parse_toplevel(root: Node<'_>, context: &Context) -> Result<ast::File, String> {
498     let mut toplevel_comments = vec![];
499     let mut file = crate::ast::File::new(context.0);
500 
501     let mut comment_start = vec![];
502     for token in root.clone().tokens() {
503         match token {
504             Token::Start { rule: Rule::COMMENT, pos } => comment_start.push(pos),
505             Token::End { rule: Rule::COMMENT, pos } => {
506                 let start_pos = comment_start.pop().unwrap();
507                 file.comments.push(crate::ast::Comment {
508                     loc: crate::ast::SourceRange {
509                         file: context.0,
510                         start: crate::ast::SourceLocation::new(start_pos.pos(), context.1),
511                         end: crate::ast::SourceLocation::new(pos.pos(), context.1),
512                     },
513                     text: start_pos.span(&pos).as_str().to_owned(),
514                 })
515             }
516             _ => (),
517         }
518     }
519 
520     for node in root.children() {
521         let loc = node.as_loc(context);
522         let rule = node.as_rule();
523         match rule {
524             Rule::endianness_declaration => file.endianness = parse_endianness(node, context)?,
525             Rule::checksum_declaration => {
526                 let mut children = node.children();
527                 let id = parse_identifier(&mut children)?;
528                 let width = parse_integer(&mut children)?;
529                 let function = parse_string(&mut children)?;
530                 file.declarations.push(crate::ast::Decl::new(
531                     loc,
532                     crate::ast::DeclDesc::Checksum { id, function, width },
533                 ))
534             }
535             Rule::custom_field_declaration => {
536                 let mut children = node.children();
537                 let id = parse_identifier(&mut children)?;
538                 let width = parse_integer_opt(&mut children)?;
539                 let function = parse_string(&mut children)?;
540                 file.declarations.push(crate::ast::Decl::new(
541                     loc,
542                     crate::ast::DeclDesc::CustomField { id, function, width },
543                 ))
544             }
545             Rule::enum_declaration => {
546                 let mut children = node.children();
547                 let id = parse_identifier(&mut children)?;
548                 let width = parse_integer(&mut children)?;
549                 let tags = parse_enum_tag_list(&mut children, context)?;
550                 file.declarations.push(crate::ast::Decl::new(
551                     loc,
552                     crate::ast::DeclDesc::Enum { id, width, tags },
553                 ))
554             }
555             Rule::packet_declaration => {
556                 let mut children = node.children();
557                 let id = parse_identifier(&mut children)?;
558                 let parent_id = parse_identifier_opt(&mut children)?;
559                 let constraints = parse_constraint_list_opt(&mut children, context)?;
560                 let fields = parse_field_list_opt(&mut children, context)?;
561                 file.declarations.push(crate::ast::Decl::new(
562                     loc,
563                     crate::ast::DeclDesc::Packet { id, parent_id, constraints, fields },
564                 ))
565             }
566             Rule::struct_declaration => {
567                 let mut children = node.children();
568                 let id = parse_identifier(&mut children)?;
569                 let parent_id = parse_identifier_opt(&mut children)?;
570                 let constraints = parse_constraint_list_opt(&mut children, context)?;
571                 let fields = parse_field_list_opt(&mut children, context)?;
572                 file.declarations.push(crate::ast::Decl::new(
573                     loc,
574                     crate::ast::DeclDesc::Struct { id, parent_id, constraints, fields },
575                 ))
576             }
577             Rule::group_declaration => {
578                 let mut children = node.children();
579                 let id = parse_identifier(&mut children)?;
580                 let fields = parse_field_list(&mut children, context)?;
581                 file.declarations
582                     .push(crate::ast::Decl::new(loc, crate::ast::DeclDesc::Group { id, fields }))
583             }
584             Rule::test_declaration => {}
585             Rule::EOI => (),
586             _ => unreachable!(),
587         }
588     }
589     file.comments.append(&mut toplevel_comments);
590     Ok(file)
591 }
592 
593 /// Parse PDL source code from a string.
594 ///
595 /// The file is added to the compilation database under the provided
596 /// name.
parse_inline( sources: &mut crate::ast::SourceDatabase, name: String, source: String, ) -> Result<ast::File, Diagnostic<crate::ast::FileId>>597 pub fn parse_inline(
598     sources: &mut crate::ast::SourceDatabase,
599     name: String,
600     source: String,
601 ) -> Result<ast::File, Diagnostic<crate::ast::FileId>> {
602     let root = PDLParser::parse(Rule::file, &source)
603         .map_err(|e| {
604             Diagnostic::error()
605                 .with_message(format!("failed to parse input file '{}': {}", &name, e))
606         })?
607         .next()
608         .unwrap();
609     let line_starts: Vec<_> = files::line_starts(&source).collect();
610     let file = sources.add(name, source.clone());
611     parse_toplevel(root, &(file, &line_starts)).map_err(|e| Diagnostic::error().with_message(e))
612 }
613 
614 /// Parse a new source file.
615 ///
616 /// The source file is fully read and added to the compilation
617 /// database. Returns the constructed AST, or a descriptive error
618 /// message in case of syntax error.
parse_file( sources: &mut crate::ast::SourceDatabase, name: String, ) -> Result<ast::File, Diagnostic<crate::ast::FileId>>619 pub fn parse_file(
620     sources: &mut crate::ast::SourceDatabase,
621     name: String,
622 ) -> Result<ast::File, Diagnostic<crate::ast::FileId>> {
623     let source = std::fs::read_to_string(&name).map_err(|e| {
624         Diagnostic::error().with_message(format!("failed to read input file '{}': {}", &name, e))
625     })?;
626     parse_inline(sources, name, source)
627 }
628 
629 #[cfg(test)]
630 mod test {
631     use super::*;
632 
633     #[test]
endianness_is_set()634     fn endianness_is_set() {
635         // The file starts out with a placeholder little-endian value.
636         // This tests that we update it while parsing.
637         let mut db = crate::ast::SourceDatabase::new();
638         let file =
639             parse_inline(&mut db, String::from("stdin"), String::from("  big_endian_packets  "))
640                 .unwrap();
641         assert_eq!(file.endianness.value, crate::ast::EndiannessValue::BigEndian);
642         assert_ne!(file.endianness.loc, crate::ast::SourceRange::default());
643     }
644 
645     #[test]
test_parse_string_bare()646     fn test_parse_string_bare() {
647         let mut pairs = PDLParser::parse(Rule::string, r#""test""#).unwrap();
648 
649         assert_eq!(parse_string(&mut pairs).as_deref(), Ok("test"));
650         assert_eq!(pairs.next(), None, "pairs is empty");
651     }
652 
653     #[test]
test_parse_string_space()654     fn test_parse_string_space() {
655         let mut pairs = PDLParser::parse(Rule::string, r#""test with space""#).unwrap();
656 
657         assert_eq!(parse_string(&mut pairs).as_deref(), Ok("test with space"));
658         assert_eq!(pairs.next(), None, "pairs is empty");
659     }
660 
661     #[test]
662     #[should_panic] /* This is not supported */
test_parse_string_escape()663     fn test_parse_string_escape() {
664         let mut pairs = PDLParser::parse(Rule::string, r#""\"test\"""#).unwrap();
665 
666         assert_eq!(parse_string(&mut pairs).as_deref(), Ok(r#""test""#));
667         assert_eq!(pairs.next(), None, "pairs is empty");
668     }
669 }
670