Skip to content

Commit de29204

Browse files
hyperpolymathclaude
andcommitted
chore: fix, Rust, lint/fmt, issues
Batch Justfile audit: standardised naming (lowercase→Justfile), fixed parse errors, removed useless build-riscv from non-Rust repos, added missing assail recipe, and fixed code quality issues. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 0be6c08 commit de29204

9 files changed

Lines changed: 203 additions & 83 deletions

File tree

src/abi/mod.rs

Lines changed: 90 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,12 @@ impl Clock {
4747

4848
impl fmt::Display for Clock {
4949
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50-
write!(f, "{}ms ({:.1}Hz)", self.base_period_ms, self.frequency_hz())
50+
write!(
51+
f,
52+
"{}ms ({:.1}Hz)",
53+
self.base_period_ms,
54+
self.frequency_hz()
55+
)
5156
}
5257
}
5358

@@ -152,7 +157,10 @@ impl std::str::FromStr for SignalType {
152157
"int" | "int32" | "integer" => Ok(Self::Int),
153158
"float" | "f32" => Ok(Self::Float),
154159
"real" | "double" | "f64" => Ok(Self::Real),
155-
other => Err(format!("Unknown signal type: '{}'. Expected bool, int, float, or real.", other)),
160+
other => Err(format!(
161+
"Unknown signal type: '{}'. Expected bool, int, float, or real.",
162+
other
163+
)),
156164
}
157165
}
158166
}
@@ -261,23 +269,37 @@ impl LustreNode {
261269
errors.push("Node name must not be empty".to_string());
262270
}
263271

264-
if !self.name.chars().next().map_or(false, |c| c.is_ascii_alphabetic() || c == '_') {
265-
errors.push(format!("Node name '{}' must start with a letter or underscore", self.name));
272+
if !self
273+
.name
274+
.chars()
275+
.next()
276+
.is_some_and(|c| c.is_ascii_alphabetic() || c == '_')
277+
{
278+
errors.push(format!(
279+
"Node name '{}' must start with a letter or underscore",
280+
self.name
281+
));
266282
}
267283

268284
if self.inputs.is_empty() {
269285
errors.push(format!("Node '{}' must have at least one input", self.name));
270286
}
271287

272288
if self.outputs.is_empty() {
273-
errors.push(format!("Node '{}' must have at least one output", self.name));
289+
errors.push(format!(
290+
"Node '{}' must have at least one output",
291+
self.name
292+
));
274293
}
275294

276295
// Check for duplicate signal names across inputs and outputs.
277296
let mut seen = std::collections::HashSet::new();
278297
for sig in self.inputs.iter().chain(self.outputs.iter()) {
279298
if !seen.insert(&sig.name) {
280-
errors.push(format!("Duplicate signal name '{}' in node '{}'", sig.name, self.name));
299+
errors.push(format!(
300+
"Duplicate signal name '{}' in node '{}'",
301+
sig.name, self.name
302+
));
281303
}
282304
}
283305

@@ -406,7 +428,12 @@ impl EmbeddedTarget {
406428
/// Return recommended compiler optimisation flags for this target.
407429
pub fn compiler_flags(&self) -> &'static [&'static str] {
408430
match self {
409-
Self::ArmCortexM => &["-mcpu=cortex-m4", "-mthumb", "-mfloat-abi=hard", "-mfpu=fpv4-sp-d16"],
431+
Self::ArmCortexM => &[
432+
"-mcpu=cortex-m4",
433+
"-mthumb",
434+
"-mfloat-abi=hard",
435+
"-mfpu=fpv4-sp-d16",
436+
],
410437
Self::RiscV => &["-march=rv32imac", "-mabi=ilp32"],
411438
Self::X86 => &["-march=native", "-O2"],
412439
}
@@ -456,7 +483,12 @@ pub struct Wcet {
456483

457484
impl Wcet {
458485
/// Create a new WCET result.
459-
pub fn new(node_name: impl Into<String>, estimated_us: u64, deadline_us: u64, analysis_performed: bool) -> Self {
486+
pub fn new(
487+
node_name: impl Into<String>,
488+
estimated_us: u64,
489+
deadline_us: u64,
490+
analysis_performed: bool,
491+
) -> Self {
460492
Self {
461493
node_name: node_name.into(),
462494
estimated_us,
@@ -496,7 +528,11 @@ impl Wcet {
496528

497529
impl fmt::Display for Wcet {
498530
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
499-
let status = if self.meets_deadline() { "OK" } else { "VIOLATION" };
531+
let status = if self.meets_deadline() {
532+
"OK"
533+
} else {
534+
"VIOLATION"
535+
};
500536
write!(
501537
f,
502538
"WCET({}) = {}us / {}us deadline [{}] (utilisation: {:.1}%)",
@@ -561,16 +597,34 @@ mod tests {
561597

562598
#[test]
563599
fn test_safety_standard_parsing() {
564-
assert_eq!("DO-178C".parse::<SafetyStandard>().unwrap(), SafetyStandard::Do178c);
565-
assert_eq!("IEC-61508".parse::<SafetyStandard>().unwrap(), SafetyStandard::Iec61508);
566-
assert_eq!("ISO-26262".parse::<SafetyStandard>().unwrap(), SafetyStandard::Iso26262);
600+
assert_eq!(
601+
"DO-178C".parse::<SafetyStandard>().unwrap(),
602+
SafetyStandard::Do178c
603+
);
604+
assert_eq!(
605+
"IEC-61508".parse::<SafetyStandard>().unwrap(),
606+
SafetyStandard::Iec61508
607+
);
608+
assert_eq!(
609+
"ISO-26262".parse::<SafetyStandard>().unwrap(),
610+
SafetyStandard::Iso26262
611+
);
567612
}
568613

569614
#[test]
570615
fn test_embedded_target_parsing() {
571-
assert_eq!("arm-cortex-m".parse::<EmbeddedTarget>().unwrap(), EmbeddedTarget::ArmCortexM);
572-
assert_eq!("riscv".parse::<EmbeddedTarget>().unwrap(), EmbeddedTarget::RiscV);
573-
assert_eq!("x86".parse::<EmbeddedTarget>().unwrap(), EmbeddedTarget::X86);
616+
assert_eq!(
617+
"arm-cortex-m".parse::<EmbeddedTarget>().unwrap(),
618+
EmbeddedTarget::ArmCortexM
619+
);
620+
assert_eq!(
621+
"riscv".parse::<EmbeddedTarget>().unwrap(),
622+
EmbeddedTarget::RiscV
623+
);
624+
assert_eq!(
625+
"x86".parse::<EmbeddedTarget>().unwrap(),
626+
EmbeddedTarget::X86
627+
);
574628
}
575629

576630
#[test]
@@ -589,9 +643,9 @@ mod tests {
589643
fn test_wcet_safety_standard_compliance() {
590644
// 70% utilisation => 30% margin => passes all standards
591645
let w = Wcet::new("ctrl", 700, 1000, true);
592-
assert!(w.satisfies_standard(&SafetyStandard::Iso26262)); // needs 20%
593-
assert!(w.satisfies_standard(&SafetyStandard::Iec61508)); // needs 15%
594-
assert!(w.satisfies_standard(&SafetyStandard::Do178c)); // needs 10%
646+
assert!(w.satisfies_standard(&SafetyStandard::Iso26262)); // needs 20%
647+
assert!(w.satisfies_standard(&SafetyStandard::Iec61508)); // needs 15%
648+
assert!(w.satisfies_standard(&SafetyStandard::Do178c)); // needs 10%
595649

596650
// 95% utilisation => 5% margin => fails all
597651
let w_tight = Wcet::new("ctrl", 950, 1000, true);
@@ -604,15 +658,30 @@ mod tests {
604658
fn test_temporal_operator_display() {
605659
assert_eq!(format!("{}", TemporalOperator::Pre), "pre");
606660
assert_eq!(
607-
format!("{}", TemporalOperator::Fby { init_expr: "0".to_string() }),
661+
format!(
662+
"{}",
663+
TemporalOperator::Fby {
664+
init_expr: "0".to_string()
665+
}
666+
),
608667
"0 fby"
609668
);
610669
assert_eq!(
611-
format!("{}", TemporalOperator::When { clock_signal: "clk_10hz".to_string() }),
670+
format!(
671+
"{}",
672+
TemporalOperator::When {
673+
clock_signal: "clk_10hz".to_string()
674+
}
675+
),
612676
"when clk_10hz"
613677
);
614678
assert_eq!(
615-
format!("{}", TemporalOperator::Merge { clock_signal: "sel".to_string() }),
679+
format!(
680+
"{}",
681+
TemporalOperator::Merge {
682+
clock_signal: "sel".to_string()
683+
}
684+
),
616685
"merge(sel)"
617686
);
618687
}

src/codegen/c_gen.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ fn generate_header(node: &ParsedNode, manifest: &Manifest) -> String {
7070
node.clock.base_period_ms,
7171
node.clock.frequency_hz(),
7272
));
73-
buf.push_str(&format!("typedef struct {{\n"));
73+
buf.push_str("typedef struct {\n");
7474

7575
// One state field per output (for fby previous value).
7676
for output in &node.outputs {
@@ -84,7 +84,9 @@ fn generate_header(node: &ParsedNode, manifest: &Manifest) -> String {
8484

8585
// Tick counter for multi-rate scheduling.
8686
if node.is_multi_rate {
87-
buf.push_str(" uint32_t tick_count; /**< Base-clock tick counter for rate division */\n");
87+
buf.push_str(
88+
" uint32_t tick_count; /**< Base-clock tick counter for rate division */\n",
89+
);
8890
}
8991

9092
// Initialisation flag.
@@ -93,8 +95,11 @@ fn generate_header(node: &ParsedNode, manifest: &Manifest) -> String {
9395
buf.push_str(&format!("}} {}_state_t;\n\n", node.name));
9496

9597
// Input struct.
96-
buf.push_str(&format!("/**\n * Input signals for node '{}'.\n */\n", node.name));
97-
buf.push_str(&format!("typedef struct {{\n"));
98+
buf.push_str(&format!(
99+
"/**\n * Input signals for node '{}'.\n */\n",
100+
node.name
101+
));
102+
buf.push_str("typedef struct {\n");
98103
for input in &node.inputs {
99104
buf.push_str(&format!(
100105
" {} {}; /**< Input signal '{}' (rate: /{}) */\n",
@@ -107,8 +112,11 @@ fn generate_header(node: &ParsedNode, manifest: &Manifest) -> String {
107112
buf.push_str(&format!("}} {}_input_t;\n\n", node.name));
108113

109114
// Output struct.
110-
buf.push_str(&format!("/**\n * Output signals for node '{}'.\n */\n", node.name));
111-
buf.push_str(&format!("typedef struct {{\n"));
115+
buf.push_str(&format!(
116+
"/**\n * Output signals for node '{}'.\n */\n",
117+
node.name
118+
));
119+
buf.push_str("typedef struct {\n");
112120
for output in &node.outputs {
113121
buf.push_str(&format!(
114122
" {} {}; /**< Output signal '{}' */\n",

src/codegen/lustre_gen.rs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,7 @@ fn generate_equations(node: &ParsedNode) -> Vec<String> {
196196
));
197197
}
198198
} else {
199-
equations.push(format!(
200-
"{} = {}_prev",
201-
output.name, output.name,
202-
));
199+
equations.push(format!("{} = {}_prev", output.name, output.name,));
203200
}
204201
}
205202
} else {
@@ -284,7 +281,10 @@ mod tests {
284281
#[test]
285282
fn test_lustre_fby_present() {
286283
let lus = generate_lustre_node(&simple_node());
287-
assert!(lus.contains("fby"), "Expected fby operator in generated Lustre");
284+
assert!(
285+
lus.contains("fby"),
286+
"Expected fby operator in generated Lustre"
287+
);
288288
}
289289

290290
#[test]
@@ -306,9 +306,18 @@ mod tests {
306306
is_multi_rate: true,
307307
};
308308
let lus = generate_lustre_node(&node);
309-
assert!(lus.contains("when"), "Expected 'when' operator for multi-rate");
310-
assert!(lus.contains("merge"), "Expected 'merge' operator for multi-rate");
311-
assert!(lus.contains("slow_sampled"), "Expected sampled local for sub-rate input");
309+
assert!(
310+
lus.contains("when"),
311+
"Expected 'when' operator for multi-rate"
312+
);
313+
assert!(
314+
lus.contains("merge"),
315+
"Expected 'merge' operator for multi-rate"
316+
);
317+
assert!(
318+
lus.contains("slow_sampled"),
319+
"Expected sampled local for sub-rate input"
320+
);
312321
}
313322

314323
#[test]
@@ -335,6 +344,9 @@ mod tests {
335344
is_multi_rate: false,
336345
};
337346
let lus = generate_lustre_node(&node);
338-
assert!(lus.contains("false fby"), "Expected 'false fby' for bool init");
347+
assert!(
348+
lus.contains("false fby"),
349+
"Expected 'false fby' for bool init"
350+
);
339351
}
340352
}

src/codegen/mod.rs

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ pub fn generate_all(manifest: &Manifest, output_dir: &str) -> Result<()> {
3333
fs::create_dir_all(out).context("Failed to create output directory")?;
3434

3535
// Stage 1: Parse and validate node definitions from the manifest.
36-
let parsed_nodes = parser::parse_nodes(manifest)
37-
.context("Failed to parse node definitions")?;
36+
let parsed_nodes = parser::parse_nodes(manifest).context("Failed to parse node definitions")?;
3837

3938
// Stage 2: Generate Lustre (.lus) files.
4039
for node in &parsed_nodes {
@@ -69,10 +68,7 @@ pub fn generate_all(manifest: &Manifest, output_dir: &str) -> Result<()> {
6968
/// Generate a WCET analysis report for all nodes.
7069
/// This is a static estimation based on node complexity; a real tool chain
7170
/// would integrate with aiT, Bound-T, or OTAWA for precise analysis.
72-
fn generate_wcet_report(
73-
nodes: &[parser::ParsedNode],
74-
manifest: &Manifest,
75-
) -> String {
71+
fn generate_wcet_report(nodes: &[parser::ParsedNode], manifest: &Manifest) -> String {
7672
use crate::abi::{SafetyStandard, Wcet};
7773

7874
let standard: SafetyStandard = manifest
@@ -91,10 +87,7 @@ fn generate_wcet_report(
9187
"Target: {} ({})\n",
9288
manifest.target.platform, manifest.target.safety_standard
9389
));
94-
report.push_str(&format!(
95-
"Deadline: {}us\n\n",
96-
manifest.timing.deadline_us
97-
));
90+
report.push_str(&format!("Deadline: {}us\n\n", manifest.timing.deadline_us));
9891

9992
let mut all_pass = true;
10093
for node in nodes {
@@ -108,12 +101,7 @@ fn generate_wcet_report(
108101
+ (node.outputs.len() as u64 * 15)
109102
+ (node.operator_count as u64 * 20);
110103

111-
let wcet = Wcet::new(
112-
&node.name,
113-
estimated_us,
114-
manifest.timing.deadline_us,
115-
true,
116-
);
104+
let wcet = Wcet::new(&node.name, estimated_us, manifest.timing.deadline_us, true);
117105

118106
let compliant = wcet.satisfies_standard(&standard);
119107
if !compliant {
@@ -124,7 +112,11 @@ fn generate_wcet_report(
124112
report.push_str(&format!(
125113
" {} compliant: {}\n\n",
126114
standard.display_name(),
127-
if compliant { "YES" } else { "NO — margin insufficient" }
115+
if compliant {
116+
"YES"
117+
} else {
118+
"NO — margin insufficient"
119+
}
128120
));
129121
}
130122

src/codegen/parser.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@ pub fn parse_nodes(manifest: &Manifest) -> Result<Vec<ParsedNode>> {
5151
let mut parsed = Vec::with_capacity(manifest.nodes.len());
5252
for (i, node_cfg) in manifest.nodes.iter().enumerate() {
5353
let ctx = format!("nodes[{}] ('{}')", i, node_cfg.name);
54-
let pn = parse_single_node(node_cfg)
55-
.with_context(|| format!("Failed to parse {}", ctx))?;
54+
let pn = parse_single_node(node_cfg).with_context(|| format!("Failed to parse {}", ctx))?;
5655
parsed.push(pn);
5756
}
5857
Ok(parsed)
@@ -162,10 +161,7 @@ mod tests {
162161

163162
#[test]
164163
fn test_parse_multi_rate_node() {
165-
let m = minimal_manifest(
166-
vec!["fast:real", "slow:real@10"],
167-
vec!["out:real"],
168-
);
164+
let m = minimal_manifest(vec!["fast:real", "slow:real@10"], vec!["out:real"]);
169165
let nodes = parse_nodes(&m).unwrap();
170166
assert!(nodes[0].is_multi_rate);
171167
assert_eq!(nodes[0].inputs[1].rate, 10);

0 commit comments

Comments
 (0)