Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions pdl-compiler/scripts/generate_cxx_backend_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,12 +352,6 @@ def run(input: argparse.FileType, output: argparse.FileType, test_vectors: argpa
'Packet_Checksum_Field_FromEnd',
'Struct_Checksum_Field_FromStart',
'Struct_Checksum_Field_FromEnd',
'PartialParent5',
'PartialParent12',
'Packet_Array_Field_VariableElementSize_ConstantSize',
'Packet_Array_Field_VariableElementSize_VariableSize',
'Packet_Array_Field_VariableElementSize_VariableCount',
'Packet_Array_Field_VariableElementSize_UnknownSize',
]

output.write(
Expand Down
103 changes: 89 additions & 14 deletions pdl-compiler/src/backends/cxx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -890,15 +890,21 @@ impl<'a> FieldParser<'a> {
let out = self.parse_array_element(field, "element_span".to_string());
self.append(format!(" output->{id}_[n] = {out};"));
self.append("}".to_string());
self.append(format!("span.skip(output->{id}_element_size_ * output->{id}_count_);"));
self.append(format!(
"span.skip(output->{id}_element_size_ * output->{id}_count_);"
));
}

(ElementSize::Dynamic, ArraySize::DynamicSize) => {
self.check_size(&format!("output->{id}_size_"));
self.append(format!("if ((output->{id}_size_ % output->{id}_element_size_) != 0) {{"));
self.append(format!(
"if ((output->{id}_size_ % output->{id}_element_size_) != 0) {{"
));
self.append(" return false;".to_string());
self.append("}".to_string());
self.append(format!("auto {id}_count_ = output->{id}_size_ / output->{id}_element_size_;"));
self.append(format!(
"auto {id}_count_ = output->{id}_size_ / output->{id}_element_size_;"
));
self.append(format!("for (size_t n = 0; n < {id}_count_; n++) {{"));
self.append(format!(" auto element_span = span.subrange(n * output->{id}_element_size_, output->{id}_element_size_);"));
let out = self.parse_array_element(field, "element_span".to_string());
Expand All @@ -911,7 +917,9 @@ impl<'a> FieldParser<'a> {
self.append(format!("if ((span.size() % output->{id}_element_size_) != 0) {{"));
self.append(" return false;".to_string());
self.append("}".to_string());
self.append(format!("auto {id}_count_ = span.size() / output->{id}_element_size_;"));
self.append(format!(
"auto {id}_count_ = span.size() / output->{id}_element_size_;"
));
self.append(format!("for (size_t n = 0; n < {id}_count_; n++) {{"));
self.append(format!(" auto element_span = span.subrange(n * output->{id}_element_size_, output->{id}_element_size_);"));
let out = self.parse_array_element(field, "element_span".to_string());
Expand Down Expand Up @@ -1491,12 +1499,23 @@ impl<'a> FieldSerializer<'a> {
self.values.push((format!("{}.size()", get_field_expr(f)), shift));
}
ast::FieldDesc::ElementSize { field_id, .. } => {
let f = self
.scope
.iter_fields(decl)
.find(|f| f.id() == Some(field_id))
.expect("Field not found");
let array_expr = get_field_expr(f);
let field_name = if field_id == "_payload_" || field_id == "_body_" {
"payload"
} else {
field_id
};
self.append(&format!("size_t {field_name}_element_size = 0; // TODO"));
let element_size = analyzer::element_size(self.scope, self.schema, decl, f);
let size_expr = match element_size {
analyzer::ElementSize::Static(size) => format!("{}", size),
_ => format!("{array_expr}.empty() ? 0 : {array_expr}[0].GetSize()"),
};
Comment thread
hchataing marked this conversation as resolved.
self.append(&format!("size_t {field_name}_element_size = {size_expr};"));
self.values.push((format!("{}_element_size", field_name), shift));
}
ast::FieldDesc::Flag { .. } => {
Expand Down Expand Up @@ -1727,12 +1746,25 @@ fn generate_packet_view(
format!("std::vector<{}>", element_type)
};

let is_dynamic_element_size = matches!(
analyzer::element_size(scope, schema, decl, field),
analyzer::ElementSize::Dynamic
);
let mut accessor_code = Vec::new();
accessor_code.push(format!("pdl::packet::slice span = {}_;", id));
if let Some(s) = size {
accessor_code.push(format!("{} elements;", array_type));
accessor_code.push(format!("for (int n = 0; n < {}; n++) {{", s));
if let Some(tid) = type_id {
if is_dynamic_element_size {
let tid = type_id.as_deref().unwrap();
accessor_code.push(format!(
" auto element_span = span.subrange(0, {}_element_size_);",
id
));
accessor_code
.push(format!(" {}::Parse(element_span, &elements[n]);", tid));
accessor_code.push(format!(" span.skip({}_element_size_);", id));
} else if let Some(tid) = type_id {
let td = scope.typedef.get(tid).unwrap();
match &td.desc {
ast::DeclDesc::Enum { width, .. } => {
Expand Down Expand Up @@ -1773,7 +1805,23 @@ fn generate_packet_view(
}
}

if let Some(tid) = type_id {
if is_dynamic_element_size {
let tid = type_id.as_deref().unwrap();
accessor_code.push(format!("while ({}) {{", count_limit));
accessor_code.push(format!(
" auto element_span = span.subrange(0, {}_element_size_);",
id
));
accessor_code.push(format!(" {} element;", tid));
accessor_code.push(format!(
" if (!{}::Parse(element_span, &element)) break;",
tid
));
accessor_code
.push(" elements.emplace_back(std::move(element));".to_string());
accessor_code.push(format!(" span.skip({}_element_size_);", id));
accessor_code.push("}".to_string());
} else if let Some(tid) = type_id {
let td = scope.typedef.get(tid).unwrap();
match &td.desc {
ast::DeclDesc::Enum { width, .. } => {
Expand Down Expand Up @@ -2508,7 +2556,7 @@ mod test {
use crate::{analyzer, ast, parser};

#[test]
fn test_canonical() {
fn test_canonical_le() {
let mut db = ast::SourceDatabase::new();
let input_file = "tests/canonical/le_test_file.pdl";
let file = parser::parse_file(&mut db, input_file).unwrap();
Expand All @@ -2532,14 +2580,41 @@ mod test {
"Struct_Custom_Field_VariableSize_".to_string(),
"Struct_Checksum_Field_FromStart_".to_string(),
"Struct_Checksum_Field_FromEnd_".to_string(),
"PartialParent5".to_string(),
"PartialChild5_A".to_string(),
"PartialChild5_B".to_string(),
"PartialParent12".to_string(),
"PartialChild12_A".to_string(),
"PartialChild12_B".to_string(),
],
);
assert_snapshot_eq("tests/generated/cxx/le_backend.h", &actual_code);
}

#[test]
fn test_canonical_be() {
let mut db = ast::SourceDatabase::new();
let input_file = "tests/canonical/le_test_file.pdl";
let source = std::fs::read_to_string(input_file).unwrap();
let source = source.replace("little_endian_packets", "big_endian_packets");
let file =
parser::parse_inline(&mut db, "tests/canonical/be_test_file.pdl", source).unwrap();
let file = analyzer::analyze(&file).unwrap();
let actual_code = generate(
&db,
&file,
Some("be_backend"),
&[],
&[],
&[
"Packet_Custom_Field_ConstantSize".to_string(),
"Packet_Custom_Field_VariableSize".to_string(),
"Packet_Checksum_Field_FromStart".to_string(),
"Packet_Checksum_Field_FromEnd".to_string(),
"Struct_Custom_Field_ConstantSize".to_string(),
"Struct_Custom_Field_VariableSize".to_string(),
"Struct_Checksum_Field_FromStart".to_string(),
"Struct_Checksum_Field_FromEnd".to_string(),
"Struct_Custom_Field_ConstantSize_".to_string(),
"Struct_Custom_Field_VariableSize_".to_string(),
"Struct_Checksum_Field_FromStart_".to_string(),
"Struct_Checksum_Field_FromEnd_".to_string(),
],
);
assert_snapshot_eq("tests/generated/cxx/be_backend.h", &actual_code);
}
}
Loading
Loading