flux_verify_api/compiler/
mod.rs1pub mod generic;
2pub mod parser;
3pub mod sonar;
4pub mod thermal;
5
6use crate::engine::vm::Bytecode;
7
8#[derive(Debug, Clone)]
10pub struct ConstraintProblem {
11 pub domain: String,
12 pub variables: Vec<Variable>,
13 pub constraints: Vec<Constraint>,
14 pub assertion: Assertion,
15}
16
17#[derive(Debug, Clone)]
18pub struct Variable {
19 pub name: String,
20 pub value: f64,
21 pub desc: String,
22}
23
24#[derive(Debug, Clone)]
25pub enum Constraint {
26 SoundVelocity { depth_m: f64, temp_c: f64, salinity_ppt: f64 },
27 Absorption { frequency_khz: f64, depth_m: f64, temp_c: f64, salinity_ppt: f64 },
28 TransmissionLoss { range_m: f64, frequency_khz: f64, depth_m: f64, temp_c: f64, salinity_ppt: f64 },
29 ThermalBound { temp_c: f64, min_safe: f64, max_safe: f64 },
30 GenericCompare { left: f64, operator: String, right: f64, desc: String },
31 GenericBound { value: f64, min: f64, max: f64, desc: String },
32 GenericRangeCheck { value: f64, min: f64, max: f64, desc: String },
33}
34
35#[derive(Debug, Clone)]
36pub struct Assertion {
37 pub assertion_type: String, pub expected: f64,
39 pub actual_expr: String, }
41
42pub fn parse_claim(claim: &str, domain: &str) -> Result<ConstraintProblem, String> {
44 match domain {
45 "sonar" => sonar::parse(claim),
46 "thermal" => thermal::parse(claim),
47 "generic" => generic::parse(claim),
48 _ => Err(format!("Unknown domain: '{}'. Use sonar, thermal, or generic.", domain)),
49 }
50}
51
52pub fn compile(problem: &ConstraintProblem) -> Vec<Bytecode> {
54 let mut bytecodes = Vec::new();
55
56 for var in &problem.variables {
58 bytecodes.push(Bytecode::Load {
59 name: var.name.clone(),
60 value: var.value,
61 desc: var.desc.clone(),
62 });
63 }
64
65 for constraint in &problem.constraints {
67 match constraint {
68 Constraint::SoundVelocity { depth_m, temp_c, salinity_ppt } => {
69 bytecodes.push(Bytecode::SonarSvp {
70 depth_m: *depth_m,
71 temp_c: *temp_c,
72 salinity_ppt: *salinity_ppt,
73 });
74 }
75 Constraint::Absorption { frequency_khz, depth_m, temp_c, salinity_ppt } => {
76 bytecodes.push(Bytecode::SonarAbsorption {
77 frequency_khz: *frequency_khz,
78 depth_m: *depth_m,
79 temp_c: *temp_c,
80 salinity_ppt: *salinity_ppt,
81 });
82 }
83 Constraint::TransmissionLoss { range_m, frequency_khz, depth_m, temp_c, salinity_ppt } => {
84 bytecodes.push(Bytecode::SonarTl {
85 range_m: *range_m,
86 frequency_khz: *frequency_khz,
87 depth_m: *depth_m,
88 temp_c: *temp_c,
89 salinity_ppt: *salinity_ppt,
90 });
91 }
92 Constraint::ThermalBound { temp_c, min_safe, max_safe } => {
93 bytecodes.push(Bytecode::ThermalBound {
94 temp_c: *temp_c,
95 min_safe: *min_safe,
96 max_safe: *max_safe,
97 });
98 }
99 Constraint::GenericCompare { left, operator, right, desc } => {
100 bytecodes.push(Bytecode::GenericCompare {
101 left: *left,
102 operator: operator.clone(),
103 right: *right,
104 desc: desc.clone(),
105 });
106 }
107 Constraint::GenericBound { value, min, max, desc } => {
108 bytecodes.push(Bytecode::GenericBound {
109 value: *value,
110 min: *min,
111 max: *max,
112 desc: desc.clone(),
113 });
114 }
115 Constraint::GenericRangeCheck { value, min, max, desc } => {
116 bytecodes.push(Bytecode::GenericRangeCheck {
117 value: *value,
118 min: *min,
119 max: *max,
120 desc: desc.clone(),
121 });
122 }
123 }
124 }
125
126 bytecodes.push(Bytecode::Assert {
128 assertion_type: problem.assertion.assertion_type.clone(),
129 expected: problem.assertion.expected,
130 desc: problem.assertion.actual_expr.clone(),
131 });
132
133 bytecodes
134}