use crate::ir;
use crate::ir::ast::{Equation, Expression, TerminalType};
use indexmap::IndexMap;
use super::connections::make_comp_ref;
pub(super) fn is_simple_literal(expr: &Expression) -> bool {
match expr {
Expression::Empty => true,
Expression::Terminal { terminal_type, .. } => {
matches!(
terminal_type,
TerminalType::UnsignedInteger
| TerminalType::UnsignedReal
| TerminalType::Bool
| TerminalType::String
)
}
Expression::Unary { op, rhs } => {
matches!(op, ir::ast::OpUnary::Minus(_) | ir::ast::OpUnary::Plus(_))
&& is_simple_literal(rhs)
}
_ => false,
}
}
pub(super) fn try_evaluate_modification(
expr: &Expression,
components: &IndexMap<String, ir::ast::Component>,
) -> Option<Expression> {
match expr {
Expression::Terminal { .. } => Some(expr.clone()),
Expression::Unary { op, rhs } => {
if matches!(op, ir::ast::OpUnary::Minus(_) | ir::ast::OpUnary::Plus(_))
&& let Some(evaluated) = try_evaluate_modification(rhs, components)
{
return Some(Expression::Unary {
op: op.clone(),
rhs: Box::new(evaluated),
});
}
None
}
Expression::ComponentReference(comp_ref) => {
if comp_ref.parts.iter().all(|p| p.subs.is_none()) {
let name = comp_ref
.parts
.iter()
.map(|p| p.ident.text.as_str())
.collect::<Vec<_>>()
.join(".");
if let Some(comp) = components.get(&name) {
if is_simple_literal(&comp.start) {
return Some(comp.start.clone());
}
}
}
None
}
_ => None,
}
}
pub(super) fn make_binding_eq(lhs: &str, rhs: Expression) -> Equation {
Equation::Simple {
lhs: Expression::ComponentReference(make_comp_ref(lhs)),
rhs,
}
}
pub(super) fn is_operator_record_type(class: &ir::ast::ClassDefinition, type_name: &str) -> bool {
if type_name == "Complex" {
return true;
}
if class.components.len() == 2
&& class.components.contains_key("re")
&& class.components.contains_key("im")
{
if let (Some(re), Some(im)) = (class.components.get("re"), class.components.get("im")) {
let re_type = re.type_name.to_string();
let im_type = im.type_name.to_string();
if re_type == "Real" && im_type == "Real" {
return true;
}
}
}
false
}