Loading tools/pdl/src/analyzer.rs +154 −3 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ use std::collections::HashMap; use crate::ast::*; use crate::parser::ast as parser_ast; use crate::utils; pub mod ast { use serde::Serialize; Loading @@ -25,7 +26,7 @@ pub mod ast { Unknown, } #[derive(Debug, Serialize, Default)] #[derive(Debug, Serialize, Default, Clone, PartialEq)] pub struct Annotation; #[derive(Default, Debug, Clone)] Loading Loading @@ -1205,8 +1206,67 @@ fn compute_field_sizes(file: &parser_ast::File) -> ast::File { } /// Inline group fields and remove group declarations. fn inline_groups(_file: &mut ast::File) -> Result<(), Diagnostics> { // TODO fn inline_groups(file: &mut ast::File) -> Result<(), Diagnostics> { fn inline_fields<'a>( fields: impl Iterator<Item = &'a ast::Field>, groups: &HashMap<String, ast::Decl>, constraints: &HashMap<String, Constraint>, ) -> Vec<ast::Field> { fields .flat_map(|field| match &field.desc { FieldDesc::Group { group_id, constraints: group_constraints } => { let mut constraints = constraints.clone(); constraints.extend( group_constraints .iter() .map(|constraint| (constraint.id.clone(), constraint.clone())), ); inline_fields(groups.get(group_id).unwrap().fields(), groups, &constraints) } FieldDesc::Scalar { id, width } if constraints.contains_key(id) => { vec![ast::Field { desc: FieldDesc::FixedScalar { width: *width, value: constraints.get(id).unwrap().value.unwrap(), }, loc: field.loc, annot: field.annot.clone(), }] } FieldDesc::Typedef { id, type_id, .. } if constraints.contains_key(id) => { vec![ast::Field { desc: FieldDesc::FixedEnum { enum_id: type_id.clone(), tag_id: constraints .get(id) .and_then(|constraint| constraint.tag_id.clone()) .unwrap(), }, loc: field.loc, annot: field.annot.clone(), }] } _ => vec![field.clone()], }) .collect() } let groups = utils::drain_filter(&mut file.declarations, |decl| { matches!(&decl.desc, DeclDesc::Group { .. }) }) .into_iter() .map(|decl| (decl.id().unwrap().to_owned(), decl)) .collect::<HashMap<String, _>>(); for decl in file.declarations.iter_mut() { match &mut decl.desc { DeclDesc::Packet { fields, .. } | DeclDesc::Struct { fields, .. } => { *fields = inline_fields(fields.iter(), &groups, &HashMap::new()) } _ => (), } } Ok(()) } Loading Loading @@ -2052,4 +2112,95 @@ mod test { "# ); } fn desugar(text: &str) -> analyzer::ast::File { let mut db = SourceDatabase::new(); let file = parse_inline(&mut db, "stdin".to_owned(), text.to_owned()).expect("parsing failure"); analyzer::analyze(&file).expect("analyzer failure") } #[test] fn test_inline_groups() { assert_eq!( desugar( r#" little_endian_packets enum E : 8 { X=0, Y=1 } group G { a: 8, b: E, } packet A { G { } } "# ), desugar( r#" little_endian_packets enum E : 8 { X=0, Y=1 } packet A { a: 8, b: E, } "# ) ); assert_eq!( desugar( r#" little_endian_packets enum E : 8 { X=0, Y=1 } group G { a: 8, b: E, } packet A { G { a=1, b=X } } "# ), desugar( r#" little_endian_packets enum E : 8 { X=0, Y=1 } packet A { _fixed_ = 1: 8, _fixed_ = X: E, } "# ) ); assert_eq!( desugar( r#" little_endian_packets enum E : 8 { X=0, Y=1 } group G1 { a: 8, } group G2 { G1 { a=1 }, b: E, } packet A { G2 { b=X } } "# ), desugar( r#" little_endian_packets enum E : 8 { X=0, Y=1 } packet A { _fixed_ = 1: 8, _fixed_ = X: E, } "# ) ); } } tools/pdl/src/ast.rs +60 −3 Original line number Diff line number Diff line Loading @@ -64,7 +64,7 @@ pub struct Tag { pub value: usize, } #[derive(Debug, Serialize, Clone, PartialEq, Eq)] #[derive(Debug, Serialize, Clone)] #[serde(tag = "kind", rename = "constraint")] pub struct Constraint { pub id: String, Loading Loading @@ -112,7 +112,7 @@ pub enum FieldDesc { Group { group_id: String, constraints: Vec<Constraint> }, } #[derive(Debug, Serialize, PartialEq, Eq)] #[derive(Debug, Serialize, Clone)] pub struct Field<A: Annotation> { pub loc: SourceRange, #[serde(skip_serializing)] Loading @@ -128,7 +128,7 @@ pub struct TestCase { pub input: String, } #[derive(Debug, Serialize)] #[derive(Debug, Serialize, PartialEq, Eq)] #[serde(tag = "kind")] pub enum DeclDesc<A: Annotation> { #[serde(rename = "checksum_declaration")] Loading Loading @@ -235,6 +235,47 @@ impl ops::Add<SourceRange> for SourceRange { } } impl Eq for Endianness {} impl PartialEq for Endianness { fn eq(&self, other: &Self) -> bool { // Implement structual equality, leave out loc. self.value == other.value } } impl Eq for Tag {} impl PartialEq for Tag { fn eq(&self, other: &Self) -> bool { // Implement structual equality, leave out loc. self.id == other.id && self.value == other.value } } impl Eq for Constraint {} impl PartialEq for Constraint { fn eq(&self, other: &Self) -> bool { // Implement structual equality, leave out loc. self.id == other.id && self.value == other.value && self.tag_id == other.tag_id } } impl Eq for TestCase {} impl PartialEq for TestCase { fn eq(&self, other: &Self) -> bool { // Implement structual equality, leave out loc. self.input == other.input } } impl<A: Annotation + std::cmp::PartialEq> Eq for File<A> {} impl<A: Annotation + std::cmp::PartialEq> PartialEq for File<A> { fn eq(&self, other: &Self) -> bool { // Implement structual equality, leave out comments and PDL // version information. self.endianness == other.endianness && self.declarations == other.declarations } } impl<A: Annotation> File<A> { pub fn new(file: FileId) -> File<A> { File { Loading @@ -259,6 +300,14 @@ impl<A: Annotation> File<A> { } } impl<A: Annotation + std::cmp::PartialEq> Eq for Decl<A> {} impl<A: Annotation + std::cmp::PartialEq> PartialEq for Decl<A> { fn eq(&self, other: &Self) -> bool { // Implement structual equality, leave out loc and annot. self.desc == other.desc } } impl<A: Annotation> Decl<A> { pub fn new(loc: SourceRange, desc: DeclDesc<A>) -> Decl<A> { Decl { loc, annot: Default::default(), desc } Loading Loading @@ -382,6 +431,14 @@ impl<A: Annotation> Decl<A> { } } impl<A: Annotation> Eq for Field<A> {} impl<A: Annotation> PartialEq for Field<A> { fn eq(&self, other: &Self) -> bool { // Implement structual equality, leave out loc and annot. self.desc == other.desc } } impl<A: Annotation> Field<A> { pub fn annotate<B: Annotation>(&self, annot: B::FieldAnnotation) -> Field<B> { Field { loc: self.loc, annot, desc: self.desc.clone() } Loading tools/pdl/src/lint.rs +0 −7 Original line number Diff line number Diff line Loading @@ -45,13 +45,6 @@ pub struct PacketScope<'d> { pub all_constraints: HashMap<String, &'d Constraint>, } impl std::cmp::Eq for &parser::ast::Decl {} impl<'d> std::cmp::PartialEq for &'d parser::ast::Decl { fn eq(&self, other: &Self) -> bool { std::ptr::eq(*self, *other) } } impl<'d> std::hash::Hash for &'d parser::ast::Decl { fn hash<H: std::hash::Hasher>(&self, state: &mut H) { std::ptr::hash(*self, state); Loading tools/pdl/src/main.rs +1 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ mod lint; mod parser; #[cfg(test)] mod test_utils; mod utils; #[derive(Copy, Clone, Debug, Eq, PartialEq)] enum OutputFormat { Loading tools/pdl/src/parser.rs +1 −1 Original line number Diff line number Diff line Loading @@ -77,7 +77,7 @@ array_field = { identifier ~ ":" ~ (integer|identifier) ~ } scalar_field = { identifier ~ ":" ~ integer } typedef_field = { identifier ~ ":" ~ identifier } group_field = { identifier ~ ("{" ~ constraint_list ~ "}")? } group_field = { identifier ~ ("{" ~ constraint_list? ~ "}")? } field = _{ checksum_field | Loading Loading
tools/pdl/src/analyzer.rs +154 −3 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ use std::collections::HashMap; use crate::ast::*; use crate::parser::ast as parser_ast; use crate::utils; pub mod ast { use serde::Serialize; Loading @@ -25,7 +26,7 @@ pub mod ast { Unknown, } #[derive(Debug, Serialize, Default)] #[derive(Debug, Serialize, Default, Clone, PartialEq)] pub struct Annotation; #[derive(Default, Debug, Clone)] Loading Loading @@ -1205,8 +1206,67 @@ fn compute_field_sizes(file: &parser_ast::File) -> ast::File { } /// Inline group fields and remove group declarations. fn inline_groups(_file: &mut ast::File) -> Result<(), Diagnostics> { // TODO fn inline_groups(file: &mut ast::File) -> Result<(), Diagnostics> { fn inline_fields<'a>( fields: impl Iterator<Item = &'a ast::Field>, groups: &HashMap<String, ast::Decl>, constraints: &HashMap<String, Constraint>, ) -> Vec<ast::Field> { fields .flat_map(|field| match &field.desc { FieldDesc::Group { group_id, constraints: group_constraints } => { let mut constraints = constraints.clone(); constraints.extend( group_constraints .iter() .map(|constraint| (constraint.id.clone(), constraint.clone())), ); inline_fields(groups.get(group_id).unwrap().fields(), groups, &constraints) } FieldDesc::Scalar { id, width } if constraints.contains_key(id) => { vec![ast::Field { desc: FieldDesc::FixedScalar { width: *width, value: constraints.get(id).unwrap().value.unwrap(), }, loc: field.loc, annot: field.annot.clone(), }] } FieldDesc::Typedef { id, type_id, .. } if constraints.contains_key(id) => { vec![ast::Field { desc: FieldDesc::FixedEnum { enum_id: type_id.clone(), tag_id: constraints .get(id) .and_then(|constraint| constraint.tag_id.clone()) .unwrap(), }, loc: field.loc, annot: field.annot.clone(), }] } _ => vec![field.clone()], }) .collect() } let groups = utils::drain_filter(&mut file.declarations, |decl| { matches!(&decl.desc, DeclDesc::Group { .. }) }) .into_iter() .map(|decl| (decl.id().unwrap().to_owned(), decl)) .collect::<HashMap<String, _>>(); for decl in file.declarations.iter_mut() { match &mut decl.desc { DeclDesc::Packet { fields, .. } | DeclDesc::Struct { fields, .. } => { *fields = inline_fields(fields.iter(), &groups, &HashMap::new()) } _ => (), } } Ok(()) } Loading Loading @@ -2052,4 +2112,95 @@ mod test { "# ); } fn desugar(text: &str) -> analyzer::ast::File { let mut db = SourceDatabase::new(); let file = parse_inline(&mut db, "stdin".to_owned(), text.to_owned()).expect("parsing failure"); analyzer::analyze(&file).expect("analyzer failure") } #[test] fn test_inline_groups() { assert_eq!( desugar( r#" little_endian_packets enum E : 8 { X=0, Y=1 } group G { a: 8, b: E, } packet A { G { } } "# ), desugar( r#" little_endian_packets enum E : 8 { X=0, Y=1 } packet A { a: 8, b: E, } "# ) ); assert_eq!( desugar( r#" little_endian_packets enum E : 8 { X=0, Y=1 } group G { a: 8, b: E, } packet A { G { a=1, b=X } } "# ), desugar( r#" little_endian_packets enum E : 8 { X=0, Y=1 } packet A { _fixed_ = 1: 8, _fixed_ = X: E, } "# ) ); assert_eq!( desugar( r#" little_endian_packets enum E : 8 { X=0, Y=1 } group G1 { a: 8, } group G2 { G1 { a=1 }, b: E, } packet A { G2 { b=X } } "# ), desugar( r#" little_endian_packets enum E : 8 { X=0, Y=1 } packet A { _fixed_ = 1: 8, _fixed_ = X: E, } "# ) ); } }
tools/pdl/src/ast.rs +60 −3 Original line number Diff line number Diff line Loading @@ -64,7 +64,7 @@ pub struct Tag { pub value: usize, } #[derive(Debug, Serialize, Clone, PartialEq, Eq)] #[derive(Debug, Serialize, Clone)] #[serde(tag = "kind", rename = "constraint")] pub struct Constraint { pub id: String, Loading Loading @@ -112,7 +112,7 @@ pub enum FieldDesc { Group { group_id: String, constraints: Vec<Constraint> }, } #[derive(Debug, Serialize, PartialEq, Eq)] #[derive(Debug, Serialize, Clone)] pub struct Field<A: Annotation> { pub loc: SourceRange, #[serde(skip_serializing)] Loading @@ -128,7 +128,7 @@ pub struct TestCase { pub input: String, } #[derive(Debug, Serialize)] #[derive(Debug, Serialize, PartialEq, Eq)] #[serde(tag = "kind")] pub enum DeclDesc<A: Annotation> { #[serde(rename = "checksum_declaration")] Loading Loading @@ -235,6 +235,47 @@ impl ops::Add<SourceRange> for SourceRange { } } impl Eq for Endianness {} impl PartialEq for Endianness { fn eq(&self, other: &Self) -> bool { // Implement structual equality, leave out loc. self.value == other.value } } impl Eq for Tag {} impl PartialEq for Tag { fn eq(&self, other: &Self) -> bool { // Implement structual equality, leave out loc. self.id == other.id && self.value == other.value } } impl Eq for Constraint {} impl PartialEq for Constraint { fn eq(&self, other: &Self) -> bool { // Implement structual equality, leave out loc. self.id == other.id && self.value == other.value && self.tag_id == other.tag_id } } impl Eq for TestCase {} impl PartialEq for TestCase { fn eq(&self, other: &Self) -> bool { // Implement structual equality, leave out loc. self.input == other.input } } impl<A: Annotation + std::cmp::PartialEq> Eq for File<A> {} impl<A: Annotation + std::cmp::PartialEq> PartialEq for File<A> { fn eq(&self, other: &Self) -> bool { // Implement structual equality, leave out comments and PDL // version information. self.endianness == other.endianness && self.declarations == other.declarations } } impl<A: Annotation> File<A> { pub fn new(file: FileId) -> File<A> { File { Loading @@ -259,6 +300,14 @@ impl<A: Annotation> File<A> { } } impl<A: Annotation + std::cmp::PartialEq> Eq for Decl<A> {} impl<A: Annotation + std::cmp::PartialEq> PartialEq for Decl<A> { fn eq(&self, other: &Self) -> bool { // Implement structual equality, leave out loc and annot. self.desc == other.desc } } impl<A: Annotation> Decl<A> { pub fn new(loc: SourceRange, desc: DeclDesc<A>) -> Decl<A> { Decl { loc, annot: Default::default(), desc } Loading Loading @@ -382,6 +431,14 @@ impl<A: Annotation> Decl<A> { } } impl<A: Annotation> Eq for Field<A> {} impl<A: Annotation> PartialEq for Field<A> { fn eq(&self, other: &Self) -> bool { // Implement structual equality, leave out loc and annot. self.desc == other.desc } } impl<A: Annotation> Field<A> { pub fn annotate<B: Annotation>(&self, annot: B::FieldAnnotation) -> Field<B> { Field { loc: self.loc, annot, desc: self.desc.clone() } Loading
tools/pdl/src/lint.rs +0 −7 Original line number Diff line number Diff line Loading @@ -45,13 +45,6 @@ pub struct PacketScope<'d> { pub all_constraints: HashMap<String, &'d Constraint>, } impl std::cmp::Eq for &parser::ast::Decl {} impl<'d> std::cmp::PartialEq for &'d parser::ast::Decl { fn eq(&self, other: &Self) -> bool { std::ptr::eq(*self, *other) } } impl<'d> std::hash::Hash for &'d parser::ast::Decl { fn hash<H: std::hash::Hasher>(&self, state: &mut H) { std::ptr::hash(*self, state); Loading
tools/pdl/src/main.rs +1 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ mod lint; mod parser; #[cfg(test)] mod test_utils; mod utils; #[derive(Copy, Clone, Debug, Eq, PartialEq)] enum OutputFormat { Loading
tools/pdl/src/parser.rs +1 −1 Original line number Diff line number Diff line Loading @@ -77,7 +77,7 @@ array_field = { identifier ~ ":" ~ (integer|identifier) ~ } scalar_field = { identifier ~ ":" ~ integer } typedef_field = { identifier ~ ":" ~ identifier } group_field = { identifier ~ ("{" ~ constraint_list ~ "}")? } group_field = { identifier ~ ("{" ~ constraint_list? ~ "}")? } field = _{ checksum_field | Loading