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

Commit 007a5f2e authored by Henri Chataing's avatar Henri Chataing Committed by Gerrit Code Review
Browse files

Merge "pdl: Refactor analyzer"

parents 727d001a 81ff283a
Loading
Loading
Loading
Loading
+1972 −0

File added.

Preview size limit exceeded, changes collapsed.

+115 −6
Original line number Diff line number Diff line
@@ -31,11 +31,11 @@ pub struct SourceRange {
}

pub trait Annotation: fmt::Debug + Serialize {
    type FieldAnnotation: Default + fmt::Debug;
    type FieldAnnotation: Default + fmt::Debug + Clone;
    type DeclAnnotation: Default + fmt::Debug;
}

#[derive(Debug, Serialize)]
#[derive(Debug, Serialize, Clone)]
#[serde(tag = "kind", rename = "comment")]
pub struct Comment {
    pub loc: SourceRange,
@@ -56,7 +56,7 @@ pub struct Endianness {
    pub value: EndiannessValue,
}

#[derive(Debug, Serialize)]
#[derive(Debug, Serialize, Clone)]
#[serde(tag = "kind", rename = "tag")]
pub struct Tag {
    pub id: String,
@@ -121,7 +121,7 @@ pub struct Field<A: Annotation> {
    pub desc: FieldDesc,
}

#[derive(Debug, Serialize)]
#[derive(Debug, Serialize, Clone)]
#[serde(tag = "kind", rename = "test_case")]
pub struct TestCase {
    pub loc: SourceRange,
@@ -250,9 +250,61 @@ impl<A: Annotation> File<A> {
            file,
        }
    }

    /// Iterate over the children of the selected declaration.
    /// /!\ This method is unsafe to use if the file contains cyclic
    /// declarations, use with caution.
    pub fn iter_children<'d>(&'d self, decl: &'d Decl<A>) -> impl Iterator<Item = &'d Decl<A>> {
        self.declarations.iter().filter(|other_decl| other_decl.parent_id() == decl.id())
    }
}

impl<A: Annotation> Decl<A> {
    pub fn new(loc: SourceRange, desc: DeclDesc<A>) -> Decl<A> {
        Decl { loc, annot: Default::default(), desc }
    }

    pub fn annotate<F, B: Annotation>(
        &self,
        annot: B::DeclAnnotation,
        annotate_fields: F,
    ) -> Decl<B>
    where
        F: FnOnce(&[Field<A>]) -> Vec<Field<B>>,
    {
        let desc = match &self.desc {
            DeclDesc::Checksum { id, function, width } => {
                DeclDesc::Checksum { id: id.clone(), function: function.clone(), width: *width }
            }
            DeclDesc::CustomField { id, width, function } => {
                DeclDesc::CustomField { id: id.clone(), width: *width, function: function.clone() }
            }
            DeclDesc::Enum { id, tags, width } => {
                DeclDesc::Enum { id: id.clone(), tags: tags.clone(), width: *width }
            }

            DeclDesc::Test { type_id, test_cases } => {
                DeclDesc::Test { type_id: type_id.clone(), test_cases: test_cases.clone() }
            }
            DeclDesc::Packet { id, constraints, parent_id, fields } => DeclDesc::Packet {
                id: id.clone(),
                constraints: constraints.clone(),
                parent_id: parent_id.clone(),
                fields: annotate_fields(fields),
            },
            DeclDesc::Struct { id, constraints, parent_id, fields } => DeclDesc::Struct {
                id: id.clone(),
                constraints: constraints.clone(),
                parent_id: parent_id.clone(),
                fields: annotate_fields(fields),
            },
            DeclDesc::Group { id, fields } => {
                DeclDesc::Group { id: id.clone(), fields: annotate_fields(fields) }
            }
        };
        Decl { loc: self.loc, desc, annot }
    }

    pub fn id(&self) -> Option<&str> {
        match &self.desc {
            DeclDesc::Test { .. } => None,
@@ -265,6 +317,24 @@ impl<A: Annotation> Decl<A> {
        }
    }

    pub fn parent_id(&self) -> Option<&str> {
        match &self.desc {
            DeclDesc::Packet { parent_id, .. } | DeclDesc::Struct { parent_id, .. } => {
                parent_id.as_deref()
            }
            _ => None,
        }
    }

    pub fn constraints(&self) -> std::slice::Iter<'_, Constraint> {
        match &self.desc {
            DeclDesc::Packet { constraints, .. } | DeclDesc::Struct { constraints, .. } => {
                constraints.iter()
            }
            _ => [].iter(),
        }
    }

    /// Determine the size of a declaration type in bits, if possible.
    ///
    /// If the type is dynamically sized (e.g. contains an array or
@@ -290,12 +360,33 @@ impl<A: Annotation> Decl<A> {
        }
    }

    pub fn new(loc: SourceRange, desc: DeclDesc<A>) -> Decl<A> {
        Decl { loc, annot: Default::default(), desc }
    pub fn fields(&self) -> std::slice::Iter<'_, Field<A>> {
        match &self.desc {
            DeclDesc::Packet { fields, .. }
            | DeclDesc::Struct { fields, .. }
            | DeclDesc::Group { fields, .. } => fields.iter(),
            _ => [].iter(),
        }
    }

    pub fn kind(&self) -> &str {
        match &self.desc {
            DeclDesc::Checksum { .. } => "checksum",
            DeclDesc::CustomField { .. } => "custom field",
            DeclDesc::Enum { .. } => "enum",
            DeclDesc::Packet { .. } => "packet",
            DeclDesc::Struct { .. } => "struct",
            DeclDesc::Group { .. } => "group",
            DeclDesc::Test { .. } => "test",
        }
    }
}

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() }
    }

    pub fn id(&self) -> Option<&str> {
        match &self.desc {
            FieldDesc::Checksum { .. }
@@ -370,6 +461,24 @@ impl<A: Annotation> Field<A> {
            _ => None,
        }
    }

    pub fn kind(&self) -> &str {
        match &self.desc {
            FieldDesc::Checksum { .. } => "payload",
            FieldDesc::Padding { .. } => "padding",
            FieldDesc::Size { .. } => "size",
            FieldDesc::Count { .. } => "count",
            FieldDesc::ElementSize { .. } => "elementsize",
            FieldDesc::Body { .. } => "body",
            FieldDesc::Payload { .. } => "payload",
            FieldDesc::FixedScalar { .. } | FieldDesc::FixedEnum { .. } => "fixed",
            FieldDesc::Reserved { .. } => "reserved",
            FieldDesc::Group { .. } => "group",
            FieldDesc::Array { .. } => "array",
            FieldDesc::Scalar { .. } => "scalar",
            FieldDesc::Typedef { .. } => "typedef",
        }
    }
}

#[cfg(test)]
+1 −44
Original line number Diff line number Diff line
@@ -11,7 +11,7 @@ pub mod ast {
    use serde::Serialize;

    // Field and declaration size information.
    #[derive(Default, Debug)]
    #[derive(Default, Debug, Clone)]
    #[allow(unused)]
    pub enum Size {
        // Constant size in bits.
@@ -682,26 +682,6 @@ impl<'d> Scope<'d> {
    }
}

impl parser::ast::Field {
    fn kind(&self) -> &str {
        match &self.desc {
            FieldDesc::Checksum { .. } => "payload",
            FieldDesc::Padding { .. } => "padding",
            FieldDesc::Size { .. } => "size",
            FieldDesc::Count { .. } => "count",
            FieldDesc::ElementSize { .. } => "elementsize",
            FieldDesc::Body { .. } => "body",
            FieldDesc::Payload { .. } => "payload",
            FieldDesc::FixedScalar { .. } | FieldDesc::FixedEnum { .. } => "fixed",
            FieldDesc::Reserved { .. } => "reserved",
            FieldDesc::Group { .. } => "group",
            FieldDesc::Array { .. } => "array",
            FieldDesc::Scalar { .. } => "scalar",
            FieldDesc::Typedef { .. } => "typedef",
        }
    }
}

// Helper for linting an enum declaration.
fn lint_enum(tags: &[Tag], width: usize, result: &mut LintDiagnostics) {
    let mut local_scope = HashMap::new();
@@ -1211,17 +1191,6 @@ fn lint_struct(
}

impl parser::ast::Decl {
    fn constraints(&self) -> impl Iterator<Item = &Constraint> {
        match &self.desc {
            DeclDesc::Packet { constraints, .. } | DeclDesc::Struct { constraints, .. } => {
                Some(constraints.iter())
            }
            _ => None,
        }
        .into_iter()
        .flatten()
    }

    fn scope<'d>(&'d self, result: &mut LintDiagnostics) -> Option<PacketScope<'d>> {
        match &self.desc {
            DeclDesc::Packet { fields, .. }
@@ -1264,18 +1233,6 @@ impl parser::ast::Decl {
            DeclDesc::Test { .. } => (),
        }
    }

    fn kind(&self) -> &str {
        match &self.desc {
            DeclDesc::Checksum { .. } => "checksum",
            DeclDesc::CustomField { .. } => "custom field",
            DeclDesc::Enum { .. } => "enum",
            DeclDesc::Packet { .. } => "packet",
            DeclDesc::Struct { .. } => "struct",
            DeclDesc::Group { .. } => "group",
            DeclDesc::Test { .. } => "test",
        }
    }
}

impl parser::ast::File {
+16 −9
Original line number Diff line number Diff line
//! PDL parser and linter.
//! PDL parser and analyzer.

use clap::Parser;
use codespan_reporting::term::{self, termcolor};

mod analyzer;
mod ast;
mod backends;
mod lint;
@@ -10,8 +11,6 @@ mod parser;
#[cfg(test)]
mod test_utils;

use crate::lint::Lintable;

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum OutputFormat {
    JSON,
@@ -62,12 +61,19 @@ fn main() -> std::process::ExitCode {
    let mut sources = ast::SourceDatabase::new();
    match parser::parse_file(&mut sources, opt.input_file) {
        Ok(file) => {
            let lint = file.lint();
            if !lint.diagnostics.is_empty() {
                lint.print(&sources, termcolor::ColorChoice::Always)
                    .expect("Could not print lint diagnostics");
            let _analyzed_file = match analyzer::analyze(&file) {
                Ok(file) => file,
                Err(diagnostics) => {
                    diagnostics
                        .emit(
                            &sources,
                            &mut termcolor::StandardStream::stderr(termcolor::ColorChoice::Always)
                                .lock(),
                        )
                        .expect("Could not print analyzer diagnostics");
                    return std::process::ExitCode::FAILURE;
                }
            };

            match opt.output_format {
                OutputFormat::JSON => {
@@ -89,6 +95,7 @@ fn main() -> std::process::ExitCode {
            }
            std::process::ExitCode::SUCCESS
        }

        Err(err) => {
            let writer = termcolor::StandardStream::stderr(termcolor::ColorChoice::Always);
            let config = term::Config::default();
+1 −1
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@ use std::iter::{Filter, Peekable};
pub mod ast {
    use serde::Serialize;

    #[derive(Debug, Serialize, PartialEq, Eq)]
    #[derive(Debug, Serialize, Default, PartialEq, Eq)]
    pub struct Annotation;

    impl crate::ast::Annotation for Annotation {