use indexmap::IndexMap;
use std::fmt;
use crate::ir::ast::{Component, Equation, Expression, Statement};
use serde::{Deserialize, Serialize};
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Dae {
pub model_name: String, pub rumoca_version: String, pub git_version: String, pub model_hash: String, pub template_hash: String, pub t: Component, pub p: IndexMap<String, Component>, pub cp: IndexMap<String, Component>, pub x: IndexMap<String, Component>, pub y: IndexMap<String, Component>, pub u: IndexMap<String, Component>, pub pre_z: IndexMap<String, Component>, pub pre_x: IndexMap<String, Component>, pub pre_m: IndexMap<String, Component>, pub z: IndexMap<String, Component>, pub m: IndexMap<String, Component>, pub c: IndexMap<String, Component>, pub fx: Vec<Equation>, pub fx_init: Vec<Equation>, pub fz: Vec<Equation>, pub fm: Vec<Equation>, pub fr: IndexMap<String, Statement>, pub fc: IndexMap<String, Expression>, }
impl Dae {
pub fn to_dae_ir_json(&self) -> Result<String, serde_json::Error> {
serde_json::to_string_pretty(self)
}
pub fn to_pretty_string(&self) -> String {
format!("{}", self)
}
}
impl fmt::Display for Dae {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "=== {} ===", self.model_name)?;
if !self.rumoca_version.is_empty() {
writeln!(f, "rumoca: {}", self.rumoca_version)?;
}
writeln!(f)?;
if !self.p.is_empty() {
writeln!(f, "Parameters:")?;
for (name, comp) in &self.p {
write!(f, " {}: {}", name, comp.type_name)?;
format_shape(f, &comp.shape)?;
format_start(f, &comp.start)?;
writeln!(f)?;
}
writeln!(f)?;
}
if !self.cp.is_empty() {
writeln!(f, "Constants:")?;
for (name, comp) in &self.cp {
write!(f, " {}: {}", name, comp.type_name)?;
format_shape(f, &comp.shape)?;
format_start(f, &comp.start)?;
writeln!(f)?;
}
writeln!(f)?;
}
if !self.u.is_empty() {
writeln!(f, "Inputs:")?;
for (name, comp) in &self.u {
write!(f, " {}: {}", name, comp.type_name)?;
format_shape(f, &comp.shape)?;
format_start(f, &comp.start)?;
writeln!(f)?;
}
writeln!(f)?;
}
if !self.x.is_empty() {
writeln!(f, "States (x):")?;
for (name, comp) in &self.x {
write!(f, " {}: {}", name, comp.type_name)?;
format_shape(f, &comp.shape)?;
format_start(f, &comp.start)?;
writeln!(f)?;
}
writeln!(f)?;
}
if !self.y.is_empty() {
writeln!(f, "Algebraics (y):")?;
for (name, comp) in &self.y {
write!(f, " {}: {}", name, comp.type_name)?;
format_shape(f, &comp.shape)?;
format_start(f, &comp.start)?;
writeln!(f)?;
}
writeln!(f)?;
}
if !self.z.is_empty() {
writeln!(f, "Discrete Real (z):")?;
for (name, comp) in &self.z {
write!(f, " {}: {}", name, comp.type_name)?;
format_shape(f, &comp.shape)?;
format_start(f, &comp.start)?;
writeln!(f)?;
}
writeln!(f)?;
}
if !self.m.is_empty() {
writeln!(f, "Discrete (m):")?;
for (name, comp) in &self.m {
write!(f, " {}: {}", name, comp.type_name)?;
format_shape(f, &comp.shape)?;
format_start(f, &comp.start)?;
writeln!(f)?;
}
writeln!(f)?;
}
if !self.c.is_empty() {
writeln!(f, "Conditions (c):")?;
for (name, comp) in &self.c {
write!(f, " {}: {}", name, comp.type_name)?;
format_shape(f, &comp.shape)?;
format_start(f, &comp.start)?;
writeln!(f)?;
}
writeln!(f)?;
}
if !self.fx.is_empty() {
writeln!(f, "Equations (fx):")?;
for eq in &self.fx {
writeln!(f, " {};", eq)?;
}
writeln!(f)?;
}
if !self.fx_init.is_empty() {
writeln!(f, "Initial Equations (fx_init):")?;
for eq in &self.fx_init {
writeln!(f, " {};", eq)?;
}
writeln!(f)?;
}
if !self.fz.is_empty() {
writeln!(f, "Algebraic Equations (fz):")?;
for eq in &self.fz {
writeln!(f, " {};", eq)?;
}
writeln!(f)?;
}
if !self.fm.is_empty() {
writeln!(f, "Discrete Equations (fm):")?;
for eq in &self.fm {
writeln!(f, " {};", eq)?;
}
writeln!(f)?;
}
if !self.fr.is_empty() {
writeln!(f, "Reset Statements (fr):")?;
for (cond, stmt) in &self.fr {
writeln!(f, " when {}: {}", cond, format_statement(stmt))?;
}
writeln!(f)?;
}
if !self.fc.is_empty() {
writeln!(f, "Condition Updates (fc):")?;
for (cond, expr) in &self.fc {
writeln!(f, " {} := {}", cond, expr)?;
}
writeln!(f)?;
}
writeln!(f, "Summary:")?;
writeln!(f, " States: {}", self.x.len())?;
writeln!(f, " Algebraics: {}", self.y.len())?;
writeln!(
f,
" Equations: {} (continuous) + {} (algebraic)",
self.fx.len(),
self.fz.len()
)?;
Ok(())
}
}
fn format_shape(f: &mut fmt::Formatter<'_>, shape: &[usize]) -> fmt::Result {
if !shape.is_empty() {
write!(
f,
"[{}]",
shape
.iter()
.map(|s| s.to_string())
.collect::<Vec<_>>()
.join(", ")
)?;
}
Ok(())
}
fn format_start(f: &mut fmt::Formatter<'_>, start: &Expression) -> fmt::Result {
if !matches!(start, Expression::Empty) {
write!(f, " = {}", start)?;
}
Ok(())
}
fn format_statement(stmt: &Statement) -> String {
match stmt {
Statement::Assignment { comp, value } => format!("{} := {}", comp, value),
Statement::Return { .. } => "return".to_string(),
Statement::Break { .. } => "break".to_string(),
Statement::For { indices, equations } => {
let idx_str = indices
.iter()
.map(|i| format!("{} in {}", i.ident.text, i.range))
.collect::<Vec<_>>()
.join(", ");
let eqs_str = equations
.iter()
.map(format_statement)
.collect::<Vec<_>>()
.join("; ");
format!("for {} loop {} end for", idx_str, eqs_str)
}
Statement::While(block) => {
format!("while {} loop ... end while", block.cond)
}
Statement::When(blocks) => {
let mut s = String::new();
for (i, block) in blocks.iter().enumerate() {
if i == 0 {
s.push_str(&format!("when {} then ...", block.cond));
} else {
s.push_str(&format!(" elsewhen {} then ...", block.cond));
}
}
s.push_str(" end when");
s
}
Statement::FunctionCall {
comp,
args,
outputs,
} => {
let args_str = args
.iter()
.map(|a| a.to_string())
.collect::<Vec<_>>()
.join(", ");
if outputs.is_empty() {
format!("{}({})", comp, args_str)
} else {
let outputs_str = outputs
.iter()
.map(|o| o.to_string())
.collect::<Vec<_>>()
.join(", ");
format!("({}) := {}({})", outputs_str, comp, args_str)
}
}
Statement::If {
cond_blocks,
else_block,
} => {
let mut s = String::new();
for (i, block) in cond_blocks.iter().enumerate() {
if i == 0 {
s.push_str(&format!("if {} then ...", block.cond));
} else {
s.push_str(&format!(" elseif {} then ...", block.cond));
}
}
if let Some(eb) = else_block
&& !eb.is_empty()
{
s.push_str(" else ...");
}
s.push_str(" end if");
s
}
Statement::Empty => String::new(),
}
}