use std::fmt::Display;
use anyhow::{Result, anyhow};
use crate::utils::FipsValue;
use super::*;
#[derive(Debug, Clone)]
pub enum SubstitutionValue {
I64(i64),
F64(f64),
Usize(usize)
}
impl Into<FipsValue> for SubstitutionValue {
fn into(self) -> FipsValue {
match self {
Self::I64(value) => FipsValue::Int64(value),
Self::F64(value) => FipsValue::Double(value),
Self::Usize(value) => FipsValue::Int64(value as i64),
}
}
}
impl Display for SubstitutionValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SubstitutionValue::I64(v) => write!(f, "i64 ({})", v),
SubstitutionValue::F64(v) => write!(f, "f64 ({})", v),
SubstitutionValue::Usize(v) => write!(f, "usize ({})", v),
}
}
}
pub trait ConstantSubstitution {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()>;
}
impl ConstantSubstitution for CompileTimeConstant<i64> {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
match self {
CompileTimeConstant::Identifier(ident_name) if ident_name == name => {
if let SubstitutionValue::I64(value) = value {
self.substitute(*value);
Ok(())
}
else {
Err(anyhow!("Invalid type for substitution: expected i64, but got {}", value))
}
}
_ => Ok(())
}
}
}
impl ConstantSubstitution for CompileTimeConstant<f64> {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
match self {
CompileTimeConstant::Identifier(ident_name) if ident_name == name => {
if let SubstitutionValue::F64(value) = value {
self.substitute(*value);
Ok(())
}
else {
Err(anyhow!("Invalid type for substitution: expected f64, but got {}", value))
}
}
_ => Ok(())
}
}
}
impl ConstantSubstitution for CompileTimeConstant<usize> {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
match self {
CompileTimeConstant::Identifier(ident_name) if ident_name == name => {
if let SubstitutionValue::Usize(value) = value {
self.substitute(*value);
Ok(())
}
else {
Err(anyhow!("Invalid type for substitution: expected usize, but got {}", value))
}
}
_ => Ok(())
}
}
}
impl ConstantSubstitution for FipsType {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
match self {
FipsType::Double | FipsType::Int64 => Ok(()),
FipsType::Array {typ, length} => {
typ.substitute_constant(name, value)?;
length.substitute_constant(name, value)
}
}
}
}
impl ConstantSubstitution for Statement {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
match self {
Statement::Let(statement) => statement.substitute_constant(name, value),
Statement::Assign(statement) => statement.substitute_constant(name, value),
Statement::Update(_) => Ok(()),
Statement::Call(_) => Ok(())
}
}
}
impl ConstantSubstitution for LetStatement {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
if self.name == name {
return Err(anyhow!("Cannot shadow compile-time constant {} with local binding", name));
}
self.initial.substitute_constant(name, value)
}
}
impl ConstantSubstitution for AssignStatement {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
if self.assignee == name {
return Err(anyhow!("Cannot assign to compile-time constant {}", name));
}
if let Some(index) = self.index.as_mut() {
index.substitute_constant(name, value)?;
}
self.value.substitute_constant(name, value)
}
}
impl ConstantSubstitution for Expression {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
match self {
Expression::Atom(_) => Ok(()),
Expression::BinaryOperation(binop) => binop.substitute_constant(name, value),
Expression::FunctionCall(call) => call.substitute_constant(name, value),
Expression::Block(block) => block.substitute_constant(name, value),
Expression::Indexing(indexing) => indexing.substitute_constant(name, value),
Expression::AdHocArray(adhocarray) => adhocarray.substitute_constant(name, value),
}
}
}
impl ConstantSubstitution for BinaryOperation {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
self.lhs.substitute_constant(name, value)?;
self.rhs.substitute_constant(name, value)
}
}
impl ConstantSubstitution for FunctionCall {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
for parameter in &mut self.parameters {
parameter.substitute_constant(name, value)?;
}
Ok(())
}
}
impl ConstantSubstitution for BlockExpression {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
for statement in &mut self.statements {
statement.substitute_constant(name, value)?;
}
self.expression.substitute_constant(name, value)
}
}
impl ConstantSubstitution for AtIndex {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
self.index.substitute_constant(name, value)
}
}
impl ConstantSubstitution for AdHocArrayExpression {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
for element in &mut self.elements {
element.substitute_constant(name, value)?;
}
Ok(())
}
}
impl ConstantSubstitution for Particle {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
for member in &mut self.members {
member.substitute_constant(name, value)?;
}
Ok(())
}
}
impl ConstantSubstitution for ParticleMember {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
self.typ.substitute_constant(name, value)
}
}
impl ConstantSubstitution for Simulation {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
for block in &mut self.blocks {
block.substitute_constant(name, value)?;
}
Ok(())
}
}
impl ConstantSubstitution for SimulationBlock {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
match self {
SimulationBlock::Once(block) => block.substitute_constant(name, value),
SimulationBlock::Step(block) => block.substitute_constant(name, value)
}
}
}
impl ConstantSubstitution for OnceBlock {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
self.step.substitute_constant(name, value)?;
for subblock in &mut self.subblocks {
subblock.substitute_constant(name, value)?;
}
Ok(())
}
}
impl ConstantSubstitution for StepBlock {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
self.step_range.substitute_constant(name, value)?;
for subblock in &mut self.subblocks {
subblock.substitute_constant(name, value)?;
}
Ok(())
}
}
impl ConstantSubstitution for StepRange {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
self.start.substitute_constant(name, value)?;
self.end.substitute_constant(name, value)?;
self.step.substitute_constant(name, value)
}
}
impl ConstantSubstitution for SimulationSubBlock {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
for statement in &mut self.statements {
statement.substitute_constant(name, value)?;
}
Ok(())
}
}
impl ConstantSubstitution for ExternFunctionDecl {
fn substitute_constant(&mut self, name: &str, value: &SubstitutionValue) -> Result<()> {
for parameter_type in &mut self.parameter_types {
parameter_type.substitute_constant(name, value)?;
}
self.return_type.substitute_constant(name, value)
}
}