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

Commit 39e2ad94 authored by Henri Chataing's avatar Henri Chataing Committed by Automerger Merge Worker
Browse files

Merge "PDL: Import pdl-parser sources" am: 5251d18a am: be23cad4 am: b8284f11 am: e084c4f6

parents b249e0c8 e084c4f6
Loading
Loading
Loading
Loading

tools/pdl/Android.bp

0 → 100644
+17 −0
Original line number Diff line number Diff line

rust_binary_host {
    name: "pdl",
    srcs: [
        "src/main.rs",
    ],
    rustlibs: [
        "libpest",
        "libserde",
        "libserde_json",
        "libstructopt",
        "libcodespan_reporting",
    ],
    proc_macros: [
        "libpest_derive",
    ],
}

tools/pdl/src/ast.rs

0 → 100644
+301 −0
Original line number Diff line number Diff line
use codespan_reporting::diagnostic;
use codespan_reporting::files;
use serde::Serialize;
use std::fmt;
use std::ops;

/// File identfiier.
/// References a source file in the source database.
pub type FileId = usize;

/// Source database.
/// Stores the source file contents for reference.
pub type SourceDatabase = files::SimpleFiles<String, String>;

#[derive(Debug, Copy, Clone, Serialize, PartialEq, Eq, PartialOrd, Ord)]
pub struct SourceLocation {
    pub offset: usize,
    pub line: usize,
    pub column: usize,
}

#[derive(Debug, Clone, Serialize)]
pub struct SourceRange {
    pub file: FileId,
    pub start: SourceLocation,
    pub end: SourceLocation,
}

#[derive(Debug, Serialize)]
#[serde(tag = "kind", rename = "comment")]
pub struct Comment {
    pub loc: SourceRange,
    pub text: String,
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum EndiannessValue {
    LittleEndian,
    BigEndian,
}

#[derive(Debug, Serialize)]
#[serde(tag = "kind", rename = "endianness_declaration")]
pub struct Endianness {
    pub loc: SourceRange,
    pub value: EndiannessValue,
}

#[derive(Debug, Serialize)]
#[serde(tag = "kind")]
pub enum Expr {
    #[serde(rename = "identifier")]
    Identifier { loc: SourceRange, name: String },
    #[serde(rename = "integer")]
    Integer { loc: SourceRange, value: usize },
    #[serde(rename = "unary_expr")]
    Unary { loc: SourceRange, op: String, operand: Box<Expr> },
    #[serde(rename = "binary_expr")]
    Binary { loc: SourceRange, op: String, operands: Box<(Expr, Expr)> },
}

#[derive(Debug, Serialize)]
#[serde(tag = "kind", rename = "tag")]
pub struct Tag {
    pub id: String,
    pub loc: SourceRange,
    pub value: usize,
}

#[derive(Debug, Serialize)]
#[serde(tag = "kind", rename = "constraint")]
pub struct Constraint {
    pub id: String,
    pub loc: SourceRange,
    pub value: Expr,
}

#[derive(Debug, Serialize)]
#[serde(tag = "kind")]
pub enum Field {
    #[serde(rename = "checksum_field")]
    Checksum { loc: SourceRange, field_id: String },
    #[serde(rename = "padding_field")]
    Padding { loc: SourceRange, width: usize },
    #[serde(rename = "size_field")]
    Size { loc: SourceRange, field_id: String, width: usize },
    #[serde(rename = "count_field")]
    Count { loc: SourceRange, field_id: String, width: usize },
    #[serde(rename = "body_field")]
    Body { loc: SourceRange },
    #[serde(rename = "payload_field")]
    Payload { loc: SourceRange, size_modifier: Option<String> },
    #[serde(rename = "fixed_field")]
    Fixed {
        loc: SourceRange,
        width: Option<usize>,
        value: Option<usize>,
        enum_id: Option<String>,
        tag_id: Option<String>,
    },
    #[serde(rename = "reserved_field")]
    Reserved { loc: SourceRange, width: usize },
    #[serde(rename = "array_field")]
    Array {
        loc: SourceRange,
        id: String,
        width: Option<usize>,
        type_id: Option<String>,
        size_modifier: Option<String>,
        size: Option<usize>,
    },
    #[serde(rename = "scalar_field")]
    Scalar { loc: SourceRange, id: String, width: usize },
    #[serde(rename = "typedef_field")]
    Typedef { loc: SourceRange, id: String, type_id: String },
    #[serde(rename = "group_field")]
    Group { loc: SourceRange, group_id: String, constraints: Vec<Constraint> },
}

#[derive(Debug, Serialize)]
#[serde(tag = "kind", rename = "test_case")]
pub struct TestCase {
    pub loc: SourceRange,
    pub input: String,
}

#[derive(Debug, Serialize)]
#[serde(tag = "kind")]
pub enum Decl {
    #[serde(rename = "checksum_declaration")]
    Checksum { id: String, loc: SourceRange, function: String, width: usize },
    #[serde(rename = "custom_field_declaration")]
    CustomField { id: String, loc: SourceRange, width: Option<usize>, function: String },
    #[serde(rename = "enum_declaration")]
    Enum { id: String, loc: SourceRange, tags: Vec<Tag>, width: usize },
    #[serde(rename = "packet_declaration")]
    Packet {
        id: String,
        loc: SourceRange,
        constraints: Vec<Constraint>,
        fields: Vec<Field>,
        parent_id: Option<String>,
    },
    #[serde(rename = "struct_declaration")]
    Struct {
        id: String,
        loc: SourceRange,
        constraints: Vec<Constraint>,
        fields: Vec<Field>,
        parent_id: Option<String>,
    },
    #[serde(rename = "group_declaration")]
    Group { id: String, loc: SourceRange, fields: Vec<Field> },
    #[serde(rename = "test_declaration")]
    Test { loc: SourceRange, type_id: String, test_cases: Vec<TestCase> },
}

#[derive(Debug, Serialize)]
pub struct Grammar {
    pub version: String,
    pub file: FileId,
    pub comments: Vec<Comment>,
    pub endianness: Option<Endianness>,
    pub declarations: Vec<Decl>,
}

/// Implemented for all AST elements.
pub trait Located<'d> {
    fn loc(&'d self) -> &'d SourceRange;
}

/// Implemented for named AST elements.
pub trait Named<'d> {
    fn id(&'d self) -> Option<&'d String>;
}

impl SourceLocation {
    pub fn new(offset: usize, line_starts: &[usize]) -> SourceLocation {
        for (line, start) in line_starts.iter().enumerate() {
            if *start <= offset {
                return SourceLocation { offset, line, column: offset - start };
            }
        }
        unreachable!()
    }
}

impl SourceRange {
    pub fn primary(&self) -> diagnostic::Label<FileId> {
        diagnostic::Label::primary(self.file, self.start.offset..self.end.offset)
    }
    pub fn secondary(&self) -> diagnostic::Label<FileId> {
        diagnostic::Label::secondary(self.file, self.start.offset..self.end.offset)
    }
}

impl fmt::Display for SourceRange {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if self.start.line == self.end.line {
            write!(f, "{}:{}-{}", self.start.line, self.start.column, self.end.column)
        } else {
            write!(
                f,
                "{}:{}-{}:{}",
                self.start.line, self.start.column, self.end.line, self.end.column
            )
        }
    }
}

impl ops::Add<SourceRange> for SourceRange {
    type Output = SourceRange;

    fn add(self, rhs: SourceRange) -> SourceRange {
        assert!(self.file == rhs.file);
        SourceRange {
            file: self.file,
            start: self.start.min(rhs.start),
            end: self.end.max(rhs.end),
        }
    }
}

impl Grammar {
    pub fn new(file: FileId) -> Grammar {
        Grammar {
            version: "1,0".to_owned(),
            comments: vec![],
            endianness: None,
            declarations: vec![],
            file,
        }
    }
}

impl<'d> Located<'d> for Field {
    fn loc(&'d self) -> &'d SourceRange {
        match self {
            Field::Checksum { loc, .. }
            | Field::Padding { loc, .. }
            | Field::Size { loc, .. }
            | Field::Count { loc, .. }
            | Field::Body { loc, .. }
            | Field::Payload { loc, .. }
            | Field::Fixed { loc, .. }
            | Field::Reserved { loc, .. }
            | Field::Array { loc, .. }
            | Field::Scalar { loc, .. }
            | Field::Typedef { loc, .. }
            | Field::Group { loc, .. } => loc,
        }
    }
}

impl<'d> Located<'d> for Decl {
    fn loc(&'d self) -> &'d SourceRange {
        match self {
            Decl::Checksum { loc, .. }
            | Decl::CustomField { loc, .. }
            | Decl::Enum { loc, .. }
            | Decl::Packet { loc, .. }
            | Decl::Struct { loc, .. }
            | Decl::Group { loc, .. }
            | Decl::Test { loc, .. } => loc,
        }
    }
}

impl<'d> Named<'d> for Field {
    fn id(&'d self) -> Option<&'d String> {
        match self {
            Field::Checksum { .. }
            | Field::Padding { .. }
            | Field::Size { .. }
            | Field::Count { .. }
            | Field::Body { .. }
            | Field::Payload { .. }
            | Field::Fixed { .. }
            | Field::Reserved { .. }
            | Field::Group { .. } => None,
            Field::Array { id, .. } | Field::Scalar { id, .. } | Field::Typedef { id, .. } => {
                Some(id)
            }
        }
    }
}

impl<'d> Named<'d> for Decl {
    fn id(&'d self) -> Option<&'d String> {
        match self {
            Decl::Test { .. } => None,
            Decl::Checksum { id, .. }
            | Decl::CustomField { id, .. }
            | Decl::Enum { id, .. }
            | Decl::Packet { id, .. }
            | Decl::Struct { id, .. }
            | Decl::Group { id, .. } => Some(id),
        }
    }
}

tools/pdl/src/lint.rs

0 → 100644
+1265 −0

File added.

Preview size limit exceeded, changes collapsed.

tools/pdl/src/main.rs

0 → 100644
+51 −0
Original line number Diff line number Diff line
//! PDL parser and linter.

extern crate codespan_reporting;
extern crate pest;
#[macro_use]
extern crate pest_derive;
extern crate serde;
extern crate serde_json;
extern crate structopt;

use codespan_reporting::term;
use codespan_reporting::term::termcolor;
use structopt::StructOpt;

mod ast;
mod lint;
mod parser;

use crate::lint::Lintable;

#[derive(Debug, StructOpt)]
#[structopt(name = "pdl-parser", about = "Packet Description Language parser tool.")]
struct Opt {
    #[structopt(short, long = "--version", help = "Print tool version and exit.")]
    version: bool,

    #[structopt(name = "FILE", help = "Input file.")]
    input_file: String,
}

fn main() {
    let opt = Opt::from_args();

    if opt.version {
        println!("Packet Description Language parser version 1.0");
        return;
    }

    let mut sources = ast::SourceDatabase::new();
    match parser::parse_file(&mut sources, opt.input_file) {
        Ok(grammar) => {
            let _ = grammar.lint().print(&sources, termcolor::ColorChoice::Always);
            println!("{}", serde_json::to_string_pretty(&grammar).unwrap())
        }
        Err(err) => {
            let writer = termcolor::StandardStream::stderr(termcolor::ColorChoice::Always);
            let config = term::Config::default();
            _ = term::emit(&mut writer.lock(), &config, &sources, &err);
        }
    }
}
+530 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading