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