use crate::analysis::constant_folding::{ConstantFolder, ReadingConstantFold};
use crate::ast;
use crate::hir::Hir;
use crate::hir_lowering::derivatives::DerivativeMap;
use crate::hir_lowering::error::{Error, Type, Warning};
use crate::hir_lowering::expression_semantic::{ConstantSchematicAnalysis, SchematicAnalysis};
use crate::ir::mir::{ExpressionId, Mir, Parameter, ParameterType};
use crate::ir::*;
use crate::mir::Attribute;
use crate::mir::*;
use crate::SourceMap;
pub mod control_flow;
pub mod derivatives;
pub mod error;
mod expression_semantic;
#[cfg(test)]
pub mod test;
pub struct HirToMirFold<'lt> {
pub errors: Vec<Error>,
pub warnings: Vec<Warning>,
hir: &'lt Hir,
mir: Mir,
variable_to_differentiate: DerivativeMap,
}
impl<'lt> HirToMirFold<'lt> {
pub fn new(hir: &'lt mut Hir) -> Self {
Self {
errors: Vec::with_capacity(32),
warnings: Vec::with_capacity(32),
mir: Mir::initalize(hir),
hir: &*hir,
variable_to_differentiate: DerivativeMap::with_capacity_and_hasher(
64,
Default::default(),
),
}
}
fn fold(mut self) -> (Result<Mir, Vec<Error>>, Vec<Warning>) {
self.mir.natures = self
.hir
.natures
.iter()
.map(|nature| nature.map_with(|old| self.fold_nature(old)))
.collect();
self.mir.parameters = self
.hir
.parameters
.iter()
.map(|param| param.map_with(|old| self.fold_parameter(old)))
.collect();
self.mir.variables = self
.hir
.variables
.iter()
.map(|var| var.map_with(|old| self.fold_variable(old)))
.collect();
self.mir.attributes = self
.hir
.attributes
.iter()
.map(|attr| {
let value = attr
.value
.and_then(|val| ConstantSchematicAnalysis().fold_expression(&mut self, val));
Attribute {
name: attr.name,
value,
}
})
.collect();
self.mir.modules = self
.hir
.modules
.iter()
.map(|module| {
module.map_with(|old| Module {
name: old.name,
port_list: old.port_list.clone(),
analog_cfg: self.fold_block_into_cfg(old.analog.clone()),
})
})
.collect();
(
if self.errors.is_empty() {
Ok(self.mir)
} else {
Err(self.errors)
},
self.warnings,
)
}
fn fold_variable(&mut self, variable: &ast::Variable) -> Variable {
let variable_type = match variable.variable_type {
ast::VariableType::REAL => {
let default_value = variable
.default_value
.and_then(|expr| ConstantSchematicAnalysis().fold_real_expression(self, expr));
VariableType::Real(default_value)
}
ast::VariableType::INTEGER => {
let default_value = if let Some(default_value) = variable.default_value {
match ConstantSchematicAnalysis().fold_expression(self, default_value) {
Some(ExpressionId::Integer(expr)) => Some(expr),
Some(ExpressionId::Real(real_expr)) => {
Some(self.mir.integer_expressions.push(Node {
source: self.mir[real_expr].source,
contents: IntegerExpression::RealCast(real_expr),
}))
}
Some(ExpressionId::String(_)) => {
self.errors.push(Error {
error_type: Type::ExpectedNumber,
source: self.hir[default_value].source,
});
None
}
None => None,
}
} else {
None
};
VariableType::Integer(default_value)
}
};
Variable {
name: variable.name,
variable_type,
}
}
fn fold_parameter(&mut self, parameter: &ast::Parameter) -> Parameter {
let parameter_type = match parameter.parameter_type {
ast::ParameterType::String() => todo!("String parameters"),
ast::ParameterType::Numerical {
parameter_type,
ref from_ranges,
ref excluded,
} => match parameter_type {
ast::VariableType::INTEGER => {
let from_ranges = from_ranges
.iter()
.filter_map(|range| {
let start = range.start.try_copy_with(&mut |expr| {
ConstantSchematicAnalysis().fold_integer_expression(self, expr)
});
let end = range.end.try_copy_with(&mut |expr| {
ConstantSchematicAnalysis().fold_integer_expression(self, expr)
});
Some(start?..end?)
})
.collect();
let excluded = excluded
.iter()
.filter_map(|exclude| {
exclude.try_clone_with(|expr| {
ConstantSchematicAnalysis().fold_integer_expression(self, expr)
})
})
.collect();
#[allow(clippy::or_fun_call)]
let default_value = ConstantSchematicAnalysis()
.fold_integer_expression(self, parameter.default_value)
.unwrap_or(IntegerExpressionId::from_usize_unchecked(0));
ParameterType::Integer {
from_ranges,
excluded,
default_value,
}
}
ast::VariableType::REAL => {
let from_ranges = from_ranges
.iter()
.filter_map(|range| {
let start = range.start.try_copy_with(&mut |expr| {
ConstantSchematicAnalysis().fold_real_expression(self, expr)
});
let end = range.end.try_copy_with(&mut |expr| {
ConstantSchematicAnalysis().fold_real_expression(self, expr)
});
Some(start?..end?)
})
.collect();
let excluded = excluded
.iter()
.filter_map(|exclude| {
exclude.try_clone_with(|expr| {
ConstantSchematicAnalysis().fold_real_expression(self, expr)
})
})
.collect();
#[allow(clippy::or_fun_call)]
let default_value = ConstantSchematicAnalysis()
.fold_real_expression(self, parameter.default_value)
.unwrap_or(RealExpressionId::from_usize_unchecked(0));
ParameterType::Real {
from_ranges,
excluded,
default_value,
}
}
},
};
Parameter {
name: parameter.name,
parameter_type,
}
}
pub fn fold_nature(&mut self, nature: &hir::Nature) -> Nature {
let units = ConstantSchematicAnalysis()
.fold_string_expression(self, nature.units)
.and_then(|expr| ReadingConstantFold(&self.mir).string_constant_fold(&mut (), expr))
.unwrap();
let abstol = ConstantSchematicAnalysis()
.fold_real_expression(self, nature.abstol)
.and_then(|expr| ReadingConstantFold(&self.mir).real_constant_fold(&mut (), expr))
.unwrap();
Nature {
name: nature.name,
abstol,
units,
access: nature.access,
idt_nature: nature.idt_nature,
ddt_nature: nature.ddt_nature,
}
}
}
pub type LoweringResults = (std::result::Result<Mir, (Vec<Error>, Hir)>, Vec<Warning>);
impl Hir {
pub fn lower(mut self) -> LoweringResults {
let (res, warnings) = HirToMirFold::new(&mut self).fold();
(res.map_err(|errors| (errors, self)), warnings)
}
pub fn lower_and_print_errors(
mut self,
source_map: &SourceMap,
translate_line: bool,
) -> Option<Mir> {
let (res, warnings) = HirToMirFold::new(&mut self).fold();
for warning in warnings {
warning.print(source_map, &self, translate_line)
}
res.map_err(|errors| {
errors
.into_iter()
.for_each(|error| error.print(source_map, &self, translate_line))
})
.ok()
}
}