1use std::fmt::Display;
4
5use anyhow::{Result, anyhow};
6
7use crate::utils::FipsValue;
8
9use super::*;
10
11#[derive(Debug, Clone)]
15pub enum SubstitutionValue {
16 I64(i64),
18 F64(f64),
20 Usize(usize)
22}
23
24impl Into<FipsValue> for SubstitutionValue {
26 fn into(self) -> FipsValue {
27 match self {
28 Self::I64(value) => FipsValue::Int64(value),
29 Self::F64(value) => FipsValue::Double(value),
30 Self::Usize(value) => FipsValue::Int64(value as i64),
31 }
32 }
33}
34
35impl Display for SubstitutionValue {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 match self {
38 SubstitutionValue::I64(v) => write!(f, "i64 ({})", v),
39 SubstitutionValue::F64(v) => write!(f, "f64 ({})", v),
40 SubstitutionValue::Usize(v) => write!(f, "usize ({})", v),
41 }
42 }
43}
44
45pub trait ConstantSubstitution {
46 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()>;
47}
48
49impl ConstantSubstitution for CompileTimeConstant<i64> {
52 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
53 match self {
54 CompileTimeConstant::Identifier(ident_name) if ident_name == name => {
55 if let SubstitutionValue::I64(value) = value {
56 self.substitute(*value);
57 Ok(())
58 }
59 else {
60 Err(anyhow!("Invalid type for substitution: expected i64, but got {}", value))
61 }
62 }
63 _ => Ok(())
65 }
66 }
67}
68
69impl ConstantSubstitution for CompileTimeConstant<f64> {
70 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
71 match self {
72 CompileTimeConstant::Identifier(ident_name) if ident_name == name => {
73 if let SubstitutionValue::F64(value) = value {
74 self.substitute(*value);
75 Ok(())
76 }
77 else {
78 Err(anyhow!("Invalid type for substitution: expected f64, but got {}", value))
79 }
80 }
81 _ => Ok(())
82 }
83 }
84}
85
86impl ConstantSubstitution for CompileTimeConstant<usize> {
87 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
88 match self {
89 CompileTimeConstant::Identifier(ident_name) if ident_name == name => {
90 if let SubstitutionValue::Usize(value) = value {
91 self.substitute(*value);
92 Ok(())
93 }
94 else {
95 Err(anyhow!("Invalid type for substitution: expected usize, but got {}", value))
96 }
97 }
98 _ => Ok(())
99 }
100 }
101}
102
103impl ConstantSubstitution for FipsType {
132 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
133 match self {
135 FipsType::Double | FipsType::Int64 => Ok(()),
136 FipsType::Array {typ, length} => {
137 typ.substitute_constant(name, value)?;
138 length.substitute_constant(name, value)
139 }
140 }
141 }
142}
143
144impl ConstantSubstitution for Statement {
145 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
146 match self {
147 Statement::Let(statement) => statement.substitute_constant(name, value),
148 Statement::Assign(statement) => statement.substitute_constant(name, value),
149 Statement::Update(_) => Ok(()),
150 Statement::Call(_) => Ok(())
151 }
152 }
153}
154
155impl ConstantSubstitution for LetStatement {
156 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
157 if self.name == name {
159 return Err(anyhow!("Cannot shadow compile-time constant {} with local binding", name));
160 }
161 self.initial.substitute_constant(name, value)
162 }
163}
164
165impl ConstantSubstitution for AssignStatement {
166 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
167 if self.assignee == name {
169 return Err(anyhow!("Cannot assign to compile-time constant {}", name));
170 }
171 if let Some(index) = self.index.as_mut() {
173 index.substitute_constant(name, value)?;
174 }
175 self.value.substitute_constant(name, value)
176 }
177}
178
179impl ConstantSubstitution for Expression {
180 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
181 match self {
182 Expression::Atom(_) => Ok(()),
185 Expression::BinaryOperation(binop) => binop.substitute_constant(name, value),
186 Expression::FunctionCall(call) => call.substitute_constant(name, value),
187 Expression::Block(block) => block.substitute_constant(name, value),
188 Expression::Indexing(indexing) => indexing.substitute_constant(name, value),
189 Expression::AdHocArray(adhocarray) => adhocarray.substitute_constant(name, value),
190 }
191 }
192}
193
194impl ConstantSubstitution for BinaryOperation {
195 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
196 self.lhs.substitute_constant(name, value)?;
197 self.rhs.substitute_constant(name, value)
198 }
199}
200
201impl ConstantSubstitution for FunctionCall {
202 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
203 for parameter in &mut self.parameters {
204 parameter.substitute_constant(name, value)?;
205 }
206 Ok(())
207 }
208}
209
210impl ConstantSubstitution for BlockExpression {
211 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
212 for statement in &mut self.statements {
213 statement.substitute_constant(name, value)?;
214 }
215 self.expression.substitute_constant(name, value)
216 }
217}
218
219impl ConstantSubstitution for AtIndex {
220 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
221 self.index.substitute_constant(name, value)
222 }
223}
224
225impl ConstantSubstitution for AdHocArrayExpression {
226 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
227 for element in &mut self.elements {
228 element.substitute_constant(name, value)?;
229 }
230 Ok(())
231 }
232}
233
234impl ConstantSubstitution for Particle {
237 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
238 for member in &mut self.members {
240 member.substitute_constant(name, value)?;
241 }
242 Ok(())
243 }
244}
245
246impl ConstantSubstitution for ParticleMember {
247 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
248 self.typ.substitute_constant(name, value)
250 }
251}
252
253impl ConstantSubstitution for Simulation {
256 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
257 for block in &mut self.blocks {
259 block.substitute_constant(name, value)?;
260 }
261 Ok(())
262 }
263}
264
265impl ConstantSubstitution for SimulationBlock {
266 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
267 match self {
268 SimulationBlock::Once(block) => block.substitute_constant(name, value),
269 SimulationBlock::Step(block) => block.substitute_constant(name, value)
270 }
271 }
272}
273
274impl ConstantSubstitution for OnceBlock {
275 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
276 self.step.substitute_constant(name, value)?;
277 for subblock in &mut self.subblocks {
278 subblock.substitute_constant(name, value)?;
279 }
280 Ok(())
281 }
282}
283
284impl ConstantSubstitution for StepBlock {
285 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
286 self.step_range.substitute_constant(name, value)?;
287 for subblock in &mut self.subblocks {
288 subblock.substitute_constant(name, value)?;
289 }
290 Ok(())
291 }
292}
293
294impl ConstantSubstitution for StepRange {
295 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
296 self.start.substitute_constant(name, value)?;
297 self.end.substitute_constant(name, value)?;
298 self.step.substitute_constant(name, value)
299 }
300}
301
302impl ConstantSubstitution for SimulationSubBlock {
303 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
304 for statement in &mut self.statements {
305 statement.substitute_constant(name, value)?;
306 }
307 Ok(())
308 }
309}
310
311impl ConstantSubstitution for ExternFunctionDecl {
314 fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
315 for parameter_type in &mut self.parameter_types {
316 parameter_type.substitute_constant(name, value)?;
317 }
318 self.return_type.substitute_constant(name, value)
319 }
320}