Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 567ec68e authored by Martin Geisler's avatar Martin Geisler Committed by Automerger Merge Worker
Browse files

Merge changes Idd122436,If8d10f95 am: feba28e9 am: 0eee5e07 am: d6b1647a

parents 7f269728 d6b1647a
Loading
Loading
Loading
Loading
+30 −54
Original line number Original line Diff line number Diff line
@@ -8,9 +8,8 @@
// Remove this when we use Rust 1.63 or later.
// Remove this when we use Rust 1.63 or later.
#![allow(clippy::format_push_string)]
#![allow(clippy::format_push_string)]


use crate::ast;
use crate::{ast, lint};
use quote::{format_ident, quote};
use quote::{format_ident, quote};
use std::collections::HashMap;
use std::path::Path;
use std::path::Path;
use syn::parse_quote;
use syn::parse_quote;


@@ -50,9 +49,8 @@ pub fn mask_bits(n: usize) -> syn::LitInt {


/// Generate code for an `ast::Decl::Packet` enum value.
/// Generate code for an `ast::Decl::Packet` enum value.
fn generate_packet_decl(
fn generate_packet_decl(
    scope: &lint::Scope<'_>,
    file: &ast::File,
    file: &ast::File,
    packets: &HashMap<&str, &ast::Decl>,
    child_ids: &[&str],
    id: &str,
    id: &str,
    fields: &[Field],
    fields: &[Field],
    parent_id: &Option<String>,
    parent_id: &Option<String>,
@@ -60,7 +58,14 @@ fn generate_packet_decl(
    // TODO(mgeisler): use the convert_case crate to convert between
    // TODO(mgeisler): use the convert_case crate to convert between
    // `FooBar` and `foo_bar` in the code below.
    // `FooBar` and `foo_bar` in the code below.
    let mut code = String::new();
    let mut code = String::new();

    let child_ids = scope
        .typedef
        .values()
        .filter_map(|p| match p {
            ast::Decl::Packet { id, parent_id, .. } if parent_id.as_deref() == Some(id) => Some(id),
            _ => None,
        })
        .collect::<Vec<_>>();
    let has_children = !child_ids.is_empty();
    let has_children = !child_ids.is_empty();
    let child_idents = child_ids.iter().map(|id| format_ident!("{id}")).collect::<Vec<_>>();
    let child_idents = child_ids.iter().map(|id| format_ident!("{id}")).collect::<Vec<_>>();


@@ -111,7 +116,7 @@ fn generate_packet_decl(
        }
        }
    });
    });


    let parent = parent_id.as_ref().map(|parent_id| match packets.get(parent_id.as_str()) {
    let parent = parent_id.as_ref().map(|parent_id| match scope.typedef.get(parent_id.as_str()) {
        Some(ast::Decl::Packet { id, .. }) => {
        Some(ast::Decl::Packet { id, .. }) => {
            let parent_ident = format_ident!("{}", id.to_lowercase());
            let parent_ident = format_ident!("{}", id.to_lowercase());
            let parent_data = format_ident!("{id}Data");
            let parent_data = format_ident!("{id}Data");
@@ -268,24 +273,11 @@ fn generate_packet_decl(
    code
    code
}
}


fn generate_decl(
fn generate_decl(scope: &lint::Scope<'_>, file: &ast::File, decl: &ast::Decl) -> String {
    file: &ast::File,
    packets: &HashMap<&str, &ast::Decl>,
    children: &HashMap<&str, Vec<&str>>,
    decl: &ast::Decl,
) -> String {
    let empty: Vec<&str> = vec![];
    match decl {
    match decl {
        ast::Decl::Packet { id, fields, parent_id, .. } => {
        ast::Decl::Packet { id, fields, parent_id, .. } => {
            let fields = fields.iter().map(Field::from).collect::<Vec<_>>();
            let fields = fields.iter().map(Field::from).collect::<Vec<_>>();
            generate_packet_decl(
            generate_packet_decl(scope, file, id, &fields, parent_id)
                file,
                packets,
                children.get(id.as_str()).unwrap_or(&empty),
                id,
                &fields,
                parent_id,
            )
        }
        }
        _ => todo!("unsupported Decl::{:?}", decl),
        _ => todo!("unsupported Decl::{:?}", decl),
    }
    }
@@ -296,25 +288,14 @@ fn generate_decl(
/// The code is not formatted, pipe it through `rustfmt` to get
/// The code is not formatted, pipe it through `rustfmt` to get
/// readable source code.
/// readable source code.
pub fn generate(sources: &ast::SourceDatabase, file: &ast::File) -> String {
pub fn generate(sources: &ast::SourceDatabase, file: &ast::File) -> String {
    let source = sources.get(file.file).expect("could not read source");

    let mut children = HashMap::new();
    let mut packets = HashMap::new();
    for decl in &file.declarations {
        if let ast::Decl::Packet { id, parent_id, .. } = decl {
            packets.insert(id.as_str(), decl);
            if let Some(parent_id) = parent_id {
                children.entry(parent_id.as_str()).or_insert_with(Vec::new).push(id.as_str());
            }
        }
    }

    let mut code = String::new();
    let mut code = String::new();


    let source = sources.get(file.file).expect("could not read source");
    code.push_str(&preamble::generate(Path::new(source.name())));
    code.push_str(&preamble::generate(Path::new(source.name())));


    let scope = lint::Scope::new(file).unwrap();
    for decl in &file.declarations {
    for decl in &file.declarations {
        code.push_str(&generate_decl(file, &packets, &children, decl));
        code.push_str(&generate_decl(&scope, file, decl));
        code.push_str("\n\n");
        code.push_str("\n\n");
    }
    }


@@ -346,10 +327,9 @@ mod tests {
              packet Foo {}
              packet Foo {}
            "#,
            "#,
        );
        );
        let packets = HashMap::new();
        let scope = lint::Scope::new(&file).unwrap();
        let children = HashMap::new();
        let decl = &file.declarations[0];
        let decl = &file.declarations[0];
        let actual_code = generate_decl(&file, &packets, &children, decl);
        let actual_code = generate_decl(&scope, &file, decl);
        assert_snapshot_eq("tests/generated/packet_decl_empty.rs", &rustfmt(&actual_code));
        assert_snapshot_eq("tests/generated/packet_decl_empty.rs", &rustfmt(&actual_code));
    }
    }


@@ -366,10 +346,9 @@ mod tests {
              }
              }
            "#,
            "#,
        );
        );
        let packets = HashMap::new();
        let scope = lint::Scope::new(&file).unwrap();
        let children = HashMap::new();
        let decl = &file.declarations[0];
        let decl = &file.declarations[0];
        let actual_code = generate_decl(&file, &packets, &children, decl);
        let actual_code = generate_decl(&scope, &file, decl);
        assert_snapshot_eq(
        assert_snapshot_eq(
            "tests/generated/packet_decl_simple_little_endian.rs",
            "tests/generated/packet_decl_simple_little_endian.rs",
            &rustfmt(&actual_code),
            &rustfmt(&actual_code),
@@ -389,10 +368,9 @@ mod tests {
              }
              }
            "#,
            "#,
        );
        );
        let packets = HashMap::new();
        let scope = lint::Scope::new(&file).unwrap();
        let children = HashMap::new();
        let decl = &file.declarations[0];
        let decl = &file.declarations[0];
        let actual_code = generate_decl(&file, &packets, &children, decl);
        let actual_code = generate_decl(&scope, &file, decl);
        assert_snapshot_eq(
        assert_snapshot_eq(
            "tests/generated/packet_decl_simple_big_endian.rs",
            "tests/generated/packet_decl_simple_big_endian.rs",
            &rustfmt(&actual_code),
            &rustfmt(&actual_code),
@@ -401,7 +379,7 @@ mod tests {


    #[test]
    #[test]
    fn test_generate_packet_decl_complex_little_endian() {
    fn test_generate_packet_decl_complex_little_endian() {
        let grammar = parse_str(
        let file = parse_str(
            r#"
            r#"
              little_endian_packets
              little_endian_packets


@@ -415,10 +393,9 @@ mod tests {
              }
              }
            "#,
            "#,
        );
        );
        let packets = HashMap::new();
        let scope = lint::Scope::new(&file).unwrap();
        let children = HashMap::new();
        let decl = &file.declarations[0];
        let decl = &grammar.declarations[0];
        let actual_code = generate_decl(&scope, &file, decl);
        let actual_code = generate_decl(&grammar, &packets, &children, decl);
        assert_snapshot_eq(
        assert_snapshot_eq(
            "tests/generated/packet_decl_complex_little_endian.rs",
            "tests/generated/packet_decl_complex_little_endian.rs",
            &rustfmt(&actual_code),
            &rustfmt(&actual_code),
@@ -427,7 +404,7 @@ mod tests {


    #[test]
    #[test]
    fn test_generate_packet_decl_complex_big_endian() {
    fn test_generate_packet_decl_complex_big_endian() {
        let grammar = parse_str(
        let file = parse_str(
            r#"
            r#"
              big_endian_packets
              big_endian_packets


@@ -441,10 +418,9 @@ mod tests {
              }
              }
            "#,
            "#,
        );
        );
        let packets = HashMap::new();
        let scope = lint::Scope::new(&file).unwrap();
        let children = HashMap::new();
        let decl = &file.declarations[0];
        let decl = &grammar.declarations[0];
        let actual_code = generate_decl(&scope, &file, decl);
        let actual_code = generate_decl(&grammar, &packets, &children, decl);
        assert_snapshot_eq(
        assert_snapshot_eq(
            "tests/generated/packet_decl_complex_big_endian.rs",
            "tests/generated/packet_decl_complex_big_endian.rs",
            &rustfmt(&actual_code),
            &rustfmt(&actual_code),
+1 −5
Original line number Original line Diff line number Diff line
@@ -16,10 +16,6 @@ impl ScalarField {
        ScalarField { id: String::from(id), width }
        ScalarField { id: String::from(id), width }
    }
    }


    fn get_width(&self) -> usize {
        self.width
    }

    fn get_ident(&self) -> proc_macro2::Ident {
    fn get_ident(&self) -> proc_macro2::Ident {
        format_ident!("{}", self.id)
        format_ident!("{}", self.id)
    }
    }
@@ -141,7 +137,7 @@ impl From<&ast::Field> for Field {
impl Field {
impl Field {
    pub fn get_width(&self) -> usize {
    pub fn get_width(&self) -> usize {
        match self {
        match self {
            Field::Scalar(field) => field.get_width(),
            Field::Scalar(field) => field.width,
        }
        }
    }
    }


+26 −14
Original line number Original line Diff line number Diff line
@@ -8,6 +8,7 @@ use std::ptr;
use crate::ast::*;
use crate::ast::*;


/// Aggregate linter diagnostics.
/// Aggregate linter diagnostics.
#[derive(Debug)]
pub struct LintDiagnostics {
pub struct LintDiagnostics {
    pub diagnostics: Vec<Diagnostic<FileId>>,
    pub diagnostics: Vec<Diagnostic<FileId>>,
}
}
@@ -23,20 +24,22 @@ pub trait Lintable {
/// Each field but the last in the chain is a typedef field of a group.
/// Each field but the last in the chain is a typedef field of a group.
/// The last field can also be a typedef field of a group if the chain is
/// The last field can also be a typedef field of a group if the chain is
/// not fully expanded.
/// not fully expanded.
#[derive(Clone)]
#[derive(Debug, Clone)]
struct FieldPath<'d>(Vec<&'d Field>);
struct FieldPath<'d>(Vec<&'d Field>);


/// Gather information about the full AST.
/// Gather information about the full AST.
struct Scope<'d> {
#[derive(Debug)]
pub struct Scope<'d> {
    // Collection of Group, Packet, Enum, Struct, Checksum, and CustomField declarations.
    // Collection of Group, Packet, Enum, Struct, Checksum, and CustomField declarations.
    typedef: HashMap<String, &'d Decl>,
    pub typedef: HashMap<String, &'d Decl>,


    // Collection of Packet, Struct, and Group scope declarations.
    // Collection of Packet, Struct, and Group scope declarations.
    scopes: HashMap<&'d Decl, PacketScope<'d>>,
    pub scopes: HashMap<&'d Decl, PacketScope<'d>>,
}
}


/// Gather information about a Packet, Struct, or Group declaration.
/// Gather information about a Packet, Struct, or Group declaration.
struct PacketScope<'d> {
#[derive(Debug)]
pub struct PacketScope<'d> {
    // Checksum starts, indexed by the checksum field id.
    // Checksum starts, indexed by the checksum field id.
    checksums: HashMap<String, FieldPath<'d>>,
    checksums: HashMap<String, FieldPath<'d>>,


@@ -462,6 +465,23 @@ fn lint_constraint(
}
}


impl<'d> Scope<'d> {
impl<'d> Scope<'d> {
    pub fn new(file: &File) -> Result<Scope<'_>, LintDiagnostics> {
        let mut lint_diagnostics = LintDiagnostics::new();
        let scope = file.scope(&mut lint_diagnostics);

        if !lint_diagnostics.diagnostics.is_empty() {
            return Err(lint_diagnostics);
        }
        for decl in &file.declarations {
            decl.lint(&scope, &mut lint_diagnostics)
        }
        if !lint_diagnostics.diagnostics.is_empty() {
            return Err(lint_diagnostics);
        }

        Ok(scope)
    }

    // Sort Packet, Struct, and Group declarations by reverse topological
    // Sort Packet, Struct, and Group declarations by reverse topological
    // orde, and inline Group fields.
    // orde, and inline Group fields.
    // Raises errors and warnings for:
    // Raises errors and warnings for:
@@ -1288,15 +1308,7 @@ impl File {


impl Lintable for File {
impl Lintable for File {
    fn lint(&self) -> LintDiagnostics {
    fn lint(&self) -> LintDiagnostics {
        let mut result = LintDiagnostics::new();
        Scope::new(self).err().unwrap_or_else(LintDiagnostics::new)
        let scope = self.scope(&mut result);
        if !result.diagnostics.is_empty() {
            return result;
        }
        for decl in &self.declarations {
            decl.lint(&scope, &mut result)
        }
        result
    }
    }
}
}