• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use super::ast;
2 use codespan_reporting::diagnostic::Diagnostic;
3 use codespan_reporting::files;
4 use pest::iterators::{Pair, Pairs};
5 use pest::{Parser, Token};
6 use std::iter::{Filter, Peekable};
7 
8 // Generate the PDL parser.
9 // TODO: use #[grammar = "pdl.pest"]
10 // currently not possible because CARGO_MANIFEST_DIR is not set
11 // in soong environment.
12 #[derive(pest_derive::Parser)]
13 #[grammar_inline = r#"
14 WHITESPACE = _{ " " | "\n" }
15 COMMENT = { block_comment | line_comment }
16 
17 block_comment = { "/*" ~ (!"*/" ~ ANY)* ~ "*/" }
18 line_comment = { "//" ~ (!"\n" ~ ANY)* }
19 
20 alpha = { 'a'..'z' | 'A'..'Z' }
21 digit = { '0'..'9' }
22 hexdigit = { digit | 'a'..'f' | 'A'..'F' }
23 alphanum = { alpha | digit | "_" }
24 
25 identifier = @{ alpha ~ alphanum* }
26 payload_identifier = @{ "_payload_" }
27 body_identifier = @{ "_body_" }
28 intvalue = @{ digit+ }
29 hexvalue = @{ ("0x"|"0X") ~ hexdigit+ }
30 integer = @{ hexvalue | intvalue }
31 string = @{ "\"" ~ (!"\"" ~ ANY)* ~ "\"" }
32 size_modifier = @{
33     ("+"|"-"|"*"|"/") ~ (digit|"+"|"-"|"*"|"/")+
34 }
35 
36 endianness_declaration = { "little_endian_packets" | "big_endian_packets" }
37 
38 enum_tag = { identifier ~ "=" ~ integer }
39 enum_tag_list = { enum_tag ~ ("," ~ enum_tag)* ~ ","? }
40 enum_declaration = {
41     "enum" ~ identifier ~ ":" ~ integer ~ "{" ~
42         enum_tag_list ~
43     "}"
44 }
45 
46 constraint = { identifier ~ "=" ~ (identifier|integer) }
47 constraint_list = { constraint ~ ("," ~ constraint)* }
48 
49 checksum_field = { "_checksum_start_" ~ "(" ~ identifier ~ ")" }
50 padding_field = { "_padding_" ~ "[" ~ integer ~ "]" }
51 size_field = { "_size_" ~ "(" ~ (identifier|payload_identifier|body_identifier)  ~ ")" ~ ":" ~ integer }
52 count_field = { "_count_" ~ "(" ~ identifier ~ ")" ~ ":" ~ integer }
53 body_field = @{ "_body_" }
54 payload_field = { "_payload_" ~ (":" ~ "[" ~ size_modifier ~ "]")? }
55 fixed_field = { "_fixed_" ~ "=" ~ (
56     (integer ~ ":" ~ integer) |
57     (identifier ~ ":" ~ identifier)
58 )}
59 reserved_field = { "_reserved_" ~ ":" ~ integer }
60 array_field = { identifier ~ ":" ~ (integer|identifier) ~
61     "[" ~ (size_modifier|integer)? ~ "]"
62 }
63 scalar_field = { identifier ~ ":" ~ integer }
64 typedef_field = { identifier ~ ":" ~ identifier }
65 group_field = { identifier ~ ("{" ~ constraint_list ~ "}")? }
66 
67 field = _{
68     checksum_field |
69     padding_field |
70     size_field |
71     count_field |
72     body_field |
73     payload_field |
74     fixed_field |
75     reserved_field |
76     array_field |
77     scalar_field |
78     typedef_field |
79     group_field
80 }
81 field_list = { field ~ ("," ~ field)* ~ ","? }
82 
83 packet_declaration = {
84    "packet" ~ identifier ~
85         (":" ~ identifier)? ~
86            ("(" ~ constraint_list ~ ")")? ~
87     "{" ~
88         field_list? ~
89     "}"
90 }
91 
92 struct_declaration = {
93     "struct" ~ identifier ~
94         (":" ~ identifier)? ~
95            ("(" ~ constraint_list ~ ")")? ~
96     "{" ~
97         field_list? ~
98     "}"
99 }
100 
101 group_declaration = {
102     "group" ~ identifier ~ "{" ~ field_list ~ "}"
103 }
104 
105 checksum_declaration = {
106     "checksum" ~ identifier ~ ":" ~ integer ~ string
107 }
108 
109 custom_field_declaration = {
110     "custom_field" ~ identifier ~ (":" ~ integer)? ~ string
111 }
112 
113 test_case = { string }
114 test_case_list = _{ test_case ~ ("," ~ test_case)* ~ ","? }
115 test_declaration = {
116     "test" ~ identifier ~ "{" ~
117         test_case_list ~
118     "}"
119 }
120 
121 declaration = _{
122     enum_declaration |
123     packet_declaration |
124     struct_declaration |
125     group_declaration |
126     checksum_declaration |
127     custom_field_declaration |
128     test_declaration
129 }
130 
131 grammar = {
132     SOI ~
133     endianness_declaration? ~
134     declaration* ~
135     EOI
136 }
137 "#]
138 pub struct PDLParser;
139 
140 type Node<'i> = Pair<'i, Rule>;
141 type NodeIterator<'i> = Peekable<Filter<Pairs<'i, Rule>, fn(&Node<'i>) -> bool>>;
142 type Context<'a> = (ast::FileId, &'a Vec<usize>);
143 
144 trait Helpers<'i> {
children(self) -> NodeIterator<'i>145     fn children(self) -> NodeIterator<'i>;
as_loc(&self, context: &Context) -> ast::SourceRange146     fn as_loc(&self, context: &Context) -> ast::SourceRange;
as_string(&self) -> String147     fn as_string(&self) -> String;
as_usize(&self) -> Result<usize, String>148     fn as_usize(&self) -> Result<usize, String>;
149 }
150 
151 impl<'i> Helpers<'i> for Node<'i> {
children(self) -> NodeIterator<'i>152     fn children(self) -> NodeIterator<'i> {
153         self.into_inner().filter((|n| n.as_rule() != Rule::COMMENT) as fn(&Self) -> bool).peekable()
154     }
155 
as_loc(&self, context: &Context) -> ast::SourceRange156     fn as_loc(&self, context: &Context) -> ast::SourceRange {
157         let span = self.as_span();
158         ast::SourceRange {
159             file: context.0,
160             start: ast::SourceLocation::new(span.start_pos().pos(), context.1),
161             end: ast::SourceLocation::new(span.end_pos().pos(), context.1),
162         }
163     }
164 
as_string(&self) -> String165     fn as_string(&self) -> String {
166         self.as_str().to_owned()
167     }
168 
as_usize(&self) -> Result<usize, String>169     fn as_usize(&self) -> Result<usize, String> {
170         let text = self.as_str();
171         if let Some(num) = text.strip_prefix("0x") {
172             usize::from_str_radix(num, 16)
173                 .map_err(|_| format!("cannot convert '{}' to usize", self.as_str()))
174         } else {
175             #[allow(clippy::from_str_radix_10)]
176             usize::from_str_radix(text, 10)
177                 .map_err(|_| format!("cannot convert '{}' to usize", self.as_str()))
178         }
179     }
180 }
181 
err_unexpected_rule<T>(expected: Rule, found: Rule) -> Result<T, String>182 fn err_unexpected_rule<T>(expected: Rule, found: Rule) -> Result<T, String> {
183     Err(format!("expected rule {:?}, got {:?}", expected, found))
184 }
185 
err_missing_rule<T>(expected: Rule) -> Result<T, String>186 fn err_missing_rule<T>(expected: Rule) -> Result<T, String> {
187     Err(format!("expected rule {:?}, got nothing", expected))
188 }
189 
expect<'i>(iter: &mut NodeIterator<'i>, rule: Rule) -> Result<Node<'i>, String>190 fn expect<'i>(iter: &mut NodeIterator<'i>, rule: Rule) -> Result<Node<'i>, String> {
191     match iter.next() {
192         Some(node) if node.as_rule() == rule => Ok(node),
193         Some(node) => err_unexpected_rule(rule, node.as_rule()),
194         None => err_missing_rule(rule),
195     }
196 }
197 
maybe<'i>(iter: &mut NodeIterator<'i>, rule: Rule) -> Option<Node<'i>>198 fn maybe<'i>(iter: &mut NodeIterator<'i>, rule: Rule) -> Option<Node<'i>> {
199     iter.next_if(|n| n.as_rule() == rule)
200 }
201 
parse_identifier(iter: &mut NodeIterator<'_>) -> Result<String, String>202 fn parse_identifier(iter: &mut NodeIterator<'_>) -> Result<String, String> {
203     expect(iter, Rule::identifier).map(|n| n.as_string())
204 }
205 
parse_integer(iter: &mut NodeIterator<'_>) -> Result<usize, String>206 fn parse_integer(iter: &mut NodeIterator<'_>) -> Result<usize, String> {
207     expect(iter, Rule::integer).and_then(|n| n.as_usize())
208 }
209 
parse_identifier_opt(iter: &mut NodeIterator<'_>) -> Result<Option<String>, String>210 fn parse_identifier_opt(iter: &mut NodeIterator<'_>) -> Result<Option<String>, String> {
211     Ok(maybe(iter, Rule::identifier).map(|n| n.as_string()))
212 }
213 
parse_integer_opt(iter: &mut NodeIterator<'_>) -> Result<Option<usize>, String>214 fn parse_integer_opt(iter: &mut NodeIterator<'_>) -> Result<Option<usize>, String> {
215     maybe(iter, Rule::integer).map(|n| n.as_usize()).transpose()
216 }
217 
parse_identifier_or_integer( iter: &mut NodeIterator<'_>, ) -> Result<(Option<String>, Option<usize>), String>218 fn parse_identifier_or_integer(
219     iter: &mut NodeIterator<'_>,
220 ) -> Result<(Option<String>, Option<usize>), String> {
221     match iter.next() {
222         Some(n) if n.as_rule() == Rule::identifier => Ok((Some(n.as_string()), None)),
223         Some(n) if n.as_rule() == Rule::integer => Ok((None, Some(n.as_usize()?))),
224         Some(n) => Err(format!(
225             "expected rule {:?} or {:?}, got {:?}",
226             Rule::identifier,
227             Rule::integer,
228             n.as_rule()
229         )),
230         None => {
231             Err(format!("expected rule {:?} or {:?}, got nothing", Rule::identifier, Rule::integer))
232         }
233     }
234 }
235 
parse_string(iter: &mut NodeIterator<'_>) -> Result<String, String>236 fn parse_string(iter: &mut NodeIterator<'_>) -> Result<String, String> {
237     expect(iter, Rule::string).map(|n| n.as_string())
238 }
239 
parse_atomic_expr(iter: &mut NodeIterator<'_>, context: &Context) -> Result<ast::Expr, String>240 fn parse_atomic_expr(iter: &mut NodeIterator<'_>, context: &Context) -> Result<ast::Expr, String> {
241     match iter.next() {
242         Some(n) if n.as_rule() == Rule::identifier => {
243             Ok(ast::Expr::Identifier { loc: n.as_loc(context), name: n.as_string() })
244         }
245         Some(n) if n.as_rule() == Rule::integer => {
246             Ok(ast::Expr::Integer { loc: n.as_loc(context), value: n.as_usize()? })
247         }
248         Some(n) => Err(format!(
249             "expected rule {:?} or {:?}, got {:?}",
250             Rule::identifier,
251             Rule::integer,
252             n.as_rule()
253         )),
254         None => {
255             Err(format!("expected rule {:?} or {:?}, got nothing", Rule::identifier, Rule::integer))
256         }
257     }
258 }
259 
parse_size_modifier_opt(iter: &mut NodeIterator<'_>) -> Option<String>260 fn parse_size_modifier_opt(iter: &mut NodeIterator<'_>) -> Option<String> {
261     maybe(iter, Rule::size_modifier).map(|n| n.as_string())
262 }
263 
parse_endianness(node: Node<'_>, context: &Context) -> Result<ast::Endianness, String>264 fn parse_endianness(node: Node<'_>, context: &Context) -> Result<ast::Endianness, String> {
265     if node.as_rule() != Rule::endianness_declaration {
266         err_unexpected_rule(Rule::endianness_declaration, node.as_rule())
267     } else {
268         Ok(ast::Endianness {
269             loc: node.as_loc(context),
270             value: match node.as_str() {
271                 "little_endian_packets" => ast::EndiannessValue::LittleEndian,
272                 "big_endian_packets" => ast::EndiannessValue::BigEndian,
273                 _ => unreachable!(),
274             },
275         })
276     }
277 }
278 
parse_constraint(node: Node<'_>, context: &Context) -> Result<ast::Constraint, String>279 fn parse_constraint(node: Node<'_>, context: &Context) -> Result<ast::Constraint, String> {
280     if node.as_rule() != Rule::constraint {
281         err_unexpected_rule(Rule::constraint, node.as_rule())
282     } else {
283         let loc = node.as_loc(context);
284         let mut children = node.children();
285         let id = parse_identifier(&mut children)?;
286         let value = parse_atomic_expr(&mut children, context)?;
287         Ok(ast::Constraint { id, loc, value })
288     }
289 }
290 
parse_constraint_list_opt( iter: &mut NodeIterator<'_>, context: &Context, ) -> Result<Vec<ast::Constraint>, String>291 fn parse_constraint_list_opt(
292     iter: &mut NodeIterator<'_>,
293     context: &Context,
294 ) -> Result<Vec<ast::Constraint>, String> {
295     maybe(iter, Rule::constraint_list)
296         .map_or(Ok(vec![]), |n| n.children().map(|n| parse_constraint(n, context)).collect())
297 }
298 
parse_enum_tag(node: Node<'_>, context: &Context) -> Result<ast::Tag, String>299 fn parse_enum_tag(node: Node<'_>, context: &Context) -> Result<ast::Tag, String> {
300     if node.as_rule() != Rule::enum_tag {
301         err_unexpected_rule(Rule::enum_tag, 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 value = parse_integer(&mut children)?;
307         Ok(ast::Tag { id, loc, value })
308     }
309 }
310 
parse_enum_tag_list( iter: &mut NodeIterator<'_>, context: &Context, ) -> Result<Vec<ast::Tag>, String>311 fn parse_enum_tag_list(
312     iter: &mut NodeIterator<'_>,
313     context: &Context,
314 ) -> Result<Vec<ast::Tag>, String> {
315     expect(iter, Rule::enum_tag_list)
316         .and_then(|n| n.children().map(|n| parse_enum_tag(n, context)).collect())
317 }
318 
parse_field(node: Node<'_>, context: &Context) -> Result<ast::Field, String>319 fn parse_field(node: Node<'_>, context: &Context) -> Result<ast::Field, String> {
320     let loc = node.as_loc(context);
321     let rule = node.as_rule();
322     let mut children = node.children();
323     Ok(match rule {
324         Rule::checksum_field => {
325             let field_id = parse_identifier(&mut children)?;
326             ast::Field::Checksum { loc, field_id }
327         }
328         Rule::padding_field => {
329             let width = parse_integer(&mut children)?;
330             ast::Field::Padding { loc, width }
331         }
332         Rule::size_field => {
333             let field_id = match children.next() {
334                 Some(n) if n.as_rule() == Rule::identifier => n.as_string(),
335                 Some(n) if n.as_rule() == Rule::payload_identifier => n.as_string(),
336                 Some(n) if n.as_rule() == Rule::body_identifier => n.as_string(),
337                 Some(n) => err_unexpected_rule(Rule::identifier, n.as_rule())?,
338                 None => err_missing_rule(Rule::identifier)?,
339             };
340             let width = parse_integer(&mut children)?;
341             ast::Field::Size { loc, field_id, width }
342         }
343         Rule::count_field => {
344             let field_id = parse_identifier(&mut children)?;
345             let width = parse_integer(&mut children)?;
346             ast::Field::Count { loc, field_id, width }
347         }
348         Rule::body_field => ast::Field::Body { loc },
349         Rule::payload_field => {
350             let size_modifier = parse_size_modifier_opt(&mut children);
351             ast::Field::Payload { loc, size_modifier }
352         }
353         Rule::fixed_field => {
354             let (tag_id, value) = parse_identifier_or_integer(&mut children)?;
355             let (enum_id, width) = parse_identifier_or_integer(&mut children)?;
356             ast::Field::Fixed { loc, enum_id, tag_id, width, value }
357         }
358         Rule::reserved_field => {
359             let width = parse_integer(&mut children)?;
360             ast::Field::Reserved { loc, width }
361         }
362         Rule::array_field => {
363             let id = parse_identifier(&mut children)?;
364             let (type_id, width) = parse_identifier_or_integer(&mut children)?;
365             let (size, size_modifier) = match children.next() {
366                 Some(n) if n.as_rule() == Rule::integer => (Some(n.as_usize()?), None),
367                 Some(n) if n.as_rule() == Rule::size_modifier => (None, Some(n.as_string())),
368                 Some(n) => {
369                     return Err(format!(
370                         "expected rule {:?} or {:?}, got {:?}",
371                         Rule::integer,
372                         Rule::size_modifier,
373                         n.as_rule()
374                     ))
375                 }
376                 None => (None, None),
377             };
378             ast::Field::Array { loc, id, type_id, width, size, size_modifier }
379         }
380         Rule::scalar_field => {
381             let id = parse_identifier(&mut children)?;
382             let width = parse_integer(&mut children)?;
383             ast::Field::Scalar { loc, id, width }
384         }
385         Rule::typedef_field => {
386             let id = parse_identifier(&mut children)?;
387             let type_id = parse_identifier(&mut children)?;
388             ast::Field::Typedef { loc, id, type_id }
389         }
390         Rule::group_field => {
391             let group_id = parse_identifier(&mut children)?;
392             let constraints = parse_constraint_list_opt(&mut children, context)?;
393             ast::Field::Group { loc, group_id, constraints }
394         }
395         _ => return Err(format!("expected rule *_field, got {:?}", rule)),
396     })
397 }
398 
parse_field_list<'i>( iter: &mut NodeIterator<'i>, context: &Context, ) -> Result<Vec<ast::Field>, String>399 fn parse_field_list<'i>(
400     iter: &mut NodeIterator<'i>,
401     context: &Context,
402 ) -> Result<Vec<ast::Field>, String> {
403     expect(iter, Rule::field_list)
404         .and_then(|n| n.children().map(|n| parse_field(n, context)).collect())
405 }
406 
parse_field_list_opt<'i>( iter: &mut NodeIterator<'i>, context: &Context, ) -> Result<Vec<ast::Field>, String>407 fn parse_field_list_opt<'i>(
408     iter: &mut NodeIterator<'i>,
409     context: &Context,
410 ) -> Result<Vec<ast::Field>, String> {
411     maybe(iter, Rule::field_list)
412         .map_or(Ok(vec![]), |n| n.children().map(|n| parse_field(n, context)).collect())
413 }
414 
parse_grammar(root: Node<'_>, context: &Context) -> Result<ast::Grammar, String>415 fn parse_grammar(root: Node<'_>, context: &Context) -> Result<ast::Grammar, String> {
416     let mut toplevel_comments = vec![];
417     let mut grammar = ast::Grammar::new(context.0);
418 
419     let mut comment_start = vec![];
420     for token in root.clone().tokens() {
421         match token {
422             Token::Start { rule: Rule::COMMENT, pos } => comment_start.push(pos),
423             Token::End { rule: Rule::COMMENT, pos } => {
424                 let start_pos = comment_start.pop().unwrap();
425                 grammar.comments.push(ast::Comment {
426                     loc: ast::SourceRange {
427                         file: context.0,
428                         start: ast::SourceLocation::new(start_pos.pos(), context.1),
429                         end: ast::SourceLocation::new(pos.pos(), context.1),
430                     },
431                     text: start_pos.span(&pos).as_str().to_owned(),
432                 })
433             }
434             _ => (),
435         }
436     }
437 
438     for node in root.children() {
439         let loc = node.as_loc(context);
440         let rule = node.as_rule();
441         match rule {
442             Rule::endianness_declaration => {
443                 grammar.endianness = Some(parse_endianness(node, context)?)
444             }
445             Rule::checksum_declaration => {
446                 let mut children = node.children();
447                 let id = parse_identifier(&mut children)?;
448                 let width = parse_integer(&mut children)?;
449                 let function = parse_string(&mut children)?;
450                 grammar.declarations.push(ast::Decl::Checksum { id, loc, function, width })
451             }
452             Rule::custom_field_declaration => {
453                 let mut children = node.children();
454                 let id = parse_identifier(&mut children)?;
455                 let width = parse_integer_opt(&mut children)?;
456                 let function = parse_string(&mut children)?;
457                 grammar.declarations.push(ast::Decl::CustomField { id, loc, function, width })
458             }
459             Rule::enum_declaration => {
460                 let mut children = node.children();
461                 let id = parse_identifier(&mut children)?;
462                 let width = parse_integer(&mut children)?;
463                 let tags = parse_enum_tag_list(&mut children, context)?;
464                 grammar.declarations.push(ast::Decl::Enum { id, loc, width, tags })
465             }
466             Rule::packet_declaration => {
467                 let mut children = node.children();
468                 let id = parse_identifier(&mut children)?;
469                 let parent_id = parse_identifier_opt(&mut children)?;
470                 let constraints = parse_constraint_list_opt(&mut children, context)?;
471                 let fields = parse_field_list_opt(&mut children, context)?;
472                 grammar.declarations.push(ast::Decl::Packet {
473                     id,
474                     loc,
475                     parent_id,
476                     constraints,
477                     fields,
478                 })
479             }
480             Rule::struct_declaration => {
481                 let mut children = node.children();
482                 let id = parse_identifier(&mut children)?;
483                 let parent_id = parse_identifier_opt(&mut children)?;
484                 let constraints = parse_constraint_list_opt(&mut children, context)?;
485                 let fields = parse_field_list_opt(&mut children, context)?;
486                 grammar.declarations.push(ast::Decl::Struct {
487                     id,
488                     loc,
489                     parent_id,
490                     constraints,
491                     fields,
492                 })
493             }
494             Rule::group_declaration => {
495                 let mut children = node.children();
496                 let id = parse_identifier(&mut children)?;
497                 let fields = parse_field_list(&mut children, context)?;
498                 grammar.declarations.push(ast::Decl::Group { id, loc, fields })
499             }
500             Rule::test_declaration => {}
501             Rule::EOI => (),
502             _ => unreachable!(),
503         }
504     }
505     grammar.comments.append(&mut toplevel_comments);
506     Ok(grammar)
507 }
508 
509 /// Parse a PDL grammar text.
510 /// The grammar is added to the compilation database under the
511 /// provided name.
parse_inline( sources: &mut ast::SourceDatabase, name: String, source: String, ) -> Result<ast::Grammar, Diagnostic<ast::FileId>>512 pub fn parse_inline(
513     sources: &mut ast::SourceDatabase,
514     name: String,
515     source: String,
516 ) -> Result<ast::Grammar, Diagnostic<ast::FileId>> {
517     let root = PDLParser::parse(Rule::grammar, &source)
518         .map_err(|e| {
519             Diagnostic::error()
520                 .with_message(format!("failed to parse input file '{}': {}", &name, e))
521         })?
522         .next()
523         .unwrap();
524     let line_starts: Vec<_> = files::line_starts(&source).collect();
525     let file = sources.add(name, source.clone());
526     parse_grammar(root, &(file, &line_starts)).map_err(|e| Diagnostic::error().with_message(e))
527 }
528 
529 /// Parse a new source file.
530 /// The source file is fully read and added to the compilation database.
531 /// Returns the constructed AST, or a descriptive error message in case
532 /// of syntax error.
parse_file( sources: &mut ast::SourceDatabase, name: String, ) -> Result<ast::Grammar, Diagnostic<ast::FileId>>533 pub fn parse_file(
534     sources: &mut ast::SourceDatabase,
535     name: String,
536 ) -> Result<ast::Grammar, Diagnostic<ast::FileId>> {
537     let source = std::fs::read_to_string(&name).map_err(|e| {
538         Diagnostic::error().with_message(format!("failed to read input file '{}': {}", &name, e))
539     })?;
540     parse_inline(sources, name, source)
541 }
542