Skip to content

Commit

Permalink
WIP migrate annot -> key
Browse files Browse the repository at this point in the history
  • Loading branch information
hchataing committed Mar 26, 2024
1 parent c847947 commit cb27c21
Show file tree
Hide file tree
Showing 14 changed files with 510 additions and 637 deletions.
635 changes: 281 additions & 354 deletions pdl-compiler/src/analyzer.rs

Large diffs are not rendered by default.

115 changes: 34 additions & 81 deletions pdl-compiler/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,6 @@ pub struct SourceRange {
pub end: SourceLocation,
}

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

#[derive(Debug, Serialize, Clone)]
#[serde(tag = "kind", rename = "comment")]
pub struct Comment {
Expand Down Expand Up @@ -154,10 +149,12 @@ pub enum FieldDesc {
}

#[derive(Debug, Serialize, Clone)]
pub struct Field<A: Annotation> {
pub struct Field {
pub loc: SourceRange,
/// Unique identifier used to refer to the AST node in
/// compilation environments.
#[serde(skip_serializing)]
pub annot: A::FieldAnnotation,
pub key: usize,
#[serde(flatten)]
pub desc: FieldDesc,
pub cond: Option<Constraint>,
Expand All @@ -172,7 +169,7 @@ pub struct TestCase {

#[derive(Debug, Serialize, Clone, PartialEq, Eq)]
#[serde(tag = "kind")]
pub enum DeclDesc<A: Annotation> {
pub enum DeclDesc {
#[serde(rename = "checksum_declaration")]
Checksum { id: String, function: String, width: usize },
#[serde(rename = "custom_field_declaration")]
Expand All @@ -183,38 +180,42 @@ pub enum DeclDesc<A: Annotation> {
Packet {
id: String,
constraints: Vec<Constraint>,
fields: Vec<Field<A>>,
fields: Vec<Field>,
parent_id: Option<String>,
},
#[serde(rename = "struct_declaration")]
Struct {
id: String,
constraints: Vec<Constraint>,
fields: Vec<Field<A>>,
fields: Vec<Field>,
parent_id: Option<String>,
},
#[serde(rename = "group_declaration")]
Group { id: String, fields: Vec<Field<A>> },
Group { id: String, fields: Vec<Field> },
#[serde(rename = "test_declaration")]
Test { type_id: String, test_cases: Vec<TestCase> },
}

#[derive(Debug, Serialize, Clone)]
pub struct Decl<A: Annotation> {
pub struct Decl {
pub loc: SourceRange,
/// Unique identifier used to refer to the AST node in
/// compilation environments.
#[serde(skip_serializing)]
pub annot: A::DeclAnnotation,
pub key: usize,
#[serde(flatten)]
pub desc: DeclDesc<A>,
pub desc: DeclDesc,
}

#[derive(Debug, Serialize, Clone)]
pub struct File<A: Annotation> {
pub struct File {
pub version: String,
pub file: FileId,
pub comments: Vec<Comment>,
pub endianness: Endianness,
pub declarations: Vec<Decl<A>>,
pub declarations: Vec<Decl>,
#[serde(skip_serializing)]
pub max_key: usize,
}

impl SourceLocation {
Expand Down Expand Up @@ -350,17 +351,17 @@ impl PartialEq for TestCase {
}
}

impl<A: Annotation + PartialEq> Eq for File<A> {}
impl<A: Annotation + PartialEq> PartialEq for File<A> {
impl Eq for File {}
impl PartialEq for File {
fn eq(&self, other: &Self) -> bool {
// Implement structural 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> {
impl File {
pub fn new(file: FileId) -> File {
File {
version: "1,0".to_owned(),
comments: vec![],
Expand All @@ -372,71 +373,27 @@ impl<A: Annotation> File<A> {
},
declarations: vec![],
file,
max_key: 0,
}
}

/// 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>> {
pub fn iter_children<'d>(&'d self, decl: &'d Decl) -> impl Iterator<Item = &'d Decl> {
self.declarations.iter().filter(|other_decl| other_decl.parent_id() == decl.id())
}
}

impl<A: Annotation + PartialEq> Eq for Decl<A> {}
impl<A: Annotation + PartialEq> PartialEq for Decl<A> {
impl Eq for Decl {}
impl PartialEq for Decl {
fn eq(&self, other: &Self) -> bool {
// Implement structural equality, leave out loc and annot.
// Implement structural equality, leave out loc and key.
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 }
}

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

impl Decl {
pub fn id(&self) -> Option<&str> {
match &self.desc {
DeclDesc::Test { .. } => None,
Expand Down Expand Up @@ -467,7 +424,7 @@ impl<A: Annotation> Decl<A> {
}
}

pub fn fields(&self) -> std::slice::Iter<'_, Field<A>> {
pub fn fields(&self) -> std::slice::Iter<'_, Field> {
match &self.desc {
DeclDesc::Packet { fields, .. }
| DeclDesc::Struct { fields, .. }
Expand All @@ -478,14 +435,14 @@ impl<A: Annotation> Decl<A> {

/// Return the reference to the payload or body field in a declaration,
/// if present.
pub fn payload(&self) -> Option<&Field<A>> {
pub fn payload(&self) -> Option<&Field> {
self.fields()
.find(|field| matches!(&field.desc, FieldDesc::Payload { .. } | FieldDesc::Body { .. }))
}

/// Return the reference to the payload or body size field in a declaration,
/// if present.
pub fn payload_size(&self) -> Option<&Field<A>> {
pub fn payload_size(&self) -> Option<&Field> {
self.fields().find(|field| match &field.desc {
FieldDesc::Size { field_id, .. } => field_id == "_payload_" || field_id == "_body_",
_ => false,
Expand All @@ -494,7 +451,7 @@ impl<A: Annotation> Decl<A> {

/// Return the reference to the array size or count field in a declaration,
/// if present.
pub fn array_size(&self, id: &str) -> Option<&Field<A>> {
pub fn array_size(&self, id: &str) -> Option<&Field> {
self.fields().find(|field| match &field.desc {
FieldDesc::Size { field_id, .. } | FieldDesc::Count { field_id, .. } => field_id == id,
_ => false,
Expand All @@ -514,19 +471,15 @@ impl<A: Annotation> Decl<A> {
}
}

impl<A: Annotation> Eq for Field<A> {}
impl<A: Annotation> PartialEq for Field<A> {
impl Eq for Field {}
impl PartialEq for Field {
fn eq(&self, other: &Self) -> bool {
// Implement structural 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, cond: self.cond.clone(), desc: self.desc.clone() }
}

impl Field {
pub fn id(&self) -> Option<&str> {
match &self.desc {
FieldDesc::Checksum { .. }
Expand Down
16 changes: 4 additions & 12 deletions pdl-compiler/src/backends/intermediate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
use std::collections::{btree_map::Entry, BTreeMap, HashMap};

use crate::ast;
use crate::parser;

pub struct Schema<'a> {
pub packets_and_structs: HashMap<&'a str, PacketOrStruct<'a>>,
Expand Down Expand Up @@ -98,7 +97,7 @@ pub enum ComputedOffset<'a> {
Alias(ComputedOffsetId<'a>),
}

pub fn generate(file: &parser::ast::File) -> Result<Schema, String> {
pub fn generate(file: &ast::File) -> Result<Schema, String> {
let mut schema = Schema { packets_and_structs: HashMap::new(), enums: HashMap::new() };
match file.endianness.value {
ast::EndiannessValue::LittleEndian => {}
Expand All @@ -112,7 +111,7 @@ pub fn generate(file: &parser::ast::File) -> Result<Schema, String> {
Ok(schema)
}

fn process_decl<'a>(schema: &mut Schema<'a>, decl: &'a parser::ast::Decl) {
fn process_decl<'a>(schema: &mut Schema<'a>, decl: &'a ast::Decl) {
match &decl.desc {
ast::DeclDesc::Enum { id, tags, width, .. } => process_enum(schema, id, tags, *width),
ast::DeclDesc::Packet { id, fields, .. } | ast::DeclDesc::Struct { id, fields, .. } => {
Expand All @@ -135,18 +134,11 @@ fn process_enum<'a>(schema: &mut Schema<'a>, id: &'a str, tags: &'a [ast::Tag],
);
}

fn process_packet_or_struct<'a>(
schema: &mut Schema<'a>,
id: &'a str,
fields: &'a [parser::ast::Field],
) {
fn process_packet_or_struct<'a>(schema: &mut Schema<'a>, id: &'a str, fields: &'a [ast::Field]) {
schema.packets_and_structs.insert(id, compute_getters(schema, fields));
}

fn compute_getters<'a>(
schema: &Schema<'a>,
fields: &'a [parser::ast::Field],
) -> PacketOrStruct<'a> {
fn compute_getters<'a>(schema: &Schema<'a>, fields: &'a [ast::Field]) -> PacketOrStruct<'a> {
let mut prev_pos_id = None;
let mut curr_pos_id = ComputedOffsetId::HeaderStart;
let mut computed_values = BTreeMap::new();
Expand Down
4 changes: 2 additions & 2 deletions pdl-compiler/src/backends/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@

//! Json compiler backend.
use crate::parser;
use crate::ast;

/// Turn the AST into a JSON representation.
pub fn generate(file: &parser::ast::File) -> Result<String, String> {
pub fn generate(file: &ast::File) -> Result<String, String> {
serde_json::to_string_pretty(&file)
.map_err(|err| format!("could not JSON serialize grammar: {err}"))
}
Loading

0 comments on commit cb27c21

Please sign in to comment.