use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use std::{fmt::Debug, fmt::Display};
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Location {
pub start_line: u32,
pub start_column: u32,
pub end_line: u32,
pub end_column: u32,
pub start: u32,
pub end: u32,
pub file_name: String,
}
#[derive(Default, Clone, PartialEq, Serialize, Deserialize)]
pub struct Token {
pub text: String,
pub location: Location,
pub token_number: u32,
pub token_type: u16,
}
impl Debug for Token {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.text)
}
}
#[derive(Default, Clone, PartialEq, Serialize, Deserialize)]
pub struct Name {
pub name: Vec<Token>,
}
impl Display for Name {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let mut s = Vec::new();
for n in &self.name {
s.push(n.text.clone());
}
write!(f, "{}", s.join("."))
}
}
impl Debug for Name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut s = Vec::new();
for n in &self.name {
s.push(n.text.clone());
}
write!(f, "{:?}", s.join("."))
}
}
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
pub struct StoredDefinition {
pub class_list: IndexMap<String, ClassDefinition>,
pub within: Option<Name>,
}
#[derive(Default, Clone, PartialEq, Serialize, Deserialize)]
pub struct Component {
pub name: String,
pub name_token: Token,
pub type_name: Name,
pub variability: Variability,
pub causality: Causality,
pub connection: Connection,
pub description: Vec<Token>,
pub start: Expression,
pub start_is_modification: bool,
pub start_has_each: bool,
pub shape: Vec<usize>,
pub shape_expr: Vec<Subscript>,
pub shape_is_modification: bool,
pub annotation: Vec<Expression>,
pub modifications: IndexMap<String, Expression>,
pub location: Location,
pub condition: Option<Expression>,
pub inner: bool,
pub outer: bool,
pub final_attributes: std::collections::HashSet<String>,
pub is_protected: bool,
}
impl Debug for Component {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut builder = f.debug_struct("Component");
builder
.field("name", &self.name)
.field("type_name", &self.type_name);
if self.variability != Variability::Empty {
builder.field("variability", &self.variability);
}
if self.causality != Causality::Empty {
builder.field("causality", &self.causality);
}
if self.connection != Connection::Empty {
builder.field("connection", &self.connection);
}
if !self.description.is_empty() {
builder.field("description", &self.description);
}
if !self.shape.is_empty() {
builder.field("shape", &self.shape);
}
if !self.shape_expr.is_empty() {
builder.field("shape_expr", &self.shape_expr);
}
if !self.annotation.is_empty() {
builder.field("annotation", &self.annotation);
}
if !self.modifications.is_empty() {
builder.field("modifications", &self.modifications);
}
if self.condition.is_some() {
builder.field("condition", &self.condition);
}
if self.inner {
builder.field("inner", &self.inner);
}
if self.outer {
builder.field("outer", &self.outer);
}
if !self.final_attributes.is_empty() {
builder.field("final_attributes", &self.final_attributes);
}
if self.is_protected {
builder.field("is_protected", &self.is_protected);
}
builder.finish()
}
}
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
pub struct EnumLiteral {
pub ident: Token,
pub description: Vec<Token>,
}
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
pub enum ClassType {
#[default]
Model,
Class,
Block,
Connector,
Record,
Type,
Package,
Function,
Operator,
}
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
pub struct ClassDefinition {
pub name: Token,
pub class_type: ClassType,
pub class_type_token: Token,
pub encapsulated: bool,
pub partial: bool,
pub causality: Causality,
pub description: Vec<Token>,
pub location: Location,
pub extends: Vec<Extend>,
pub imports: Vec<Import>,
pub classes: IndexMap<String, ClassDefinition>,
pub components: IndexMap<String, Component>,
pub equations: Vec<Equation>,
pub initial_equations: Vec<Equation>,
pub algorithms: Vec<Vec<Statement>>,
pub initial_algorithms: Vec<Vec<Statement>>,
pub equation_keyword: Option<Token>,
pub initial_equation_keyword: Option<Token>,
pub algorithm_keyword: Option<Token>,
pub initial_algorithm_keyword: Option<Token>,
pub end_name_token: Option<Token>,
pub enum_literals: Vec<EnumLiteral>,
pub annotation: Vec<Expression>,
}
impl ClassDefinition {
pub fn iter_components(&self) -> impl Iterator<Item = (&str, &Component)> {
self.components
.iter()
.map(|(name, comp)| (name.as_str(), comp))
}
pub fn iter_classes(&self) -> impl Iterator<Item = (&str, &ClassDefinition)> {
self.classes
.iter()
.map(|(name, class)| (name.as_str(), class))
}
pub fn iter_all_equations(&self) -> impl Iterator<Item = &Equation> {
self.equations.iter().chain(self.initial_equations.iter())
}
pub fn iter_all_statements(&self) -> impl Iterator<Item = &Statement> {
self.algorithms
.iter()
.flatten()
.chain(self.initial_algorithms.iter().flatten())
}
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Extend {
pub comp: Name,
pub location: Location,
pub modifications: Vec<Expression>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Import {
Qualified { path: Name, location: Location },
Renamed {
alias: Token,
path: Name,
location: Location,
},
Unqualified { path: Name, location: Location },
Selective {
path: Name,
names: Vec<Token>,
location: Location,
},
}
impl Import {
pub fn base_path(&self) -> &Name {
match self {
Import::Qualified { path, .. } => path,
Import::Renamed { path, .. } => path,
Import::Unqualified { path, .. } => path,
Import::Selective { path, .. } => path,
}
}
pub fn location(&self) -> &Location {
match self {
Import::Qualified { location, .. } => location,
Import::Renamed { location, .. } => location,
Import::Unqualified { location, .. } => location,
Import::Selective { location, .. } => location,
}
}
}
#[derive(Default, Clone, PartialEq, Serialize, Deserialize)]
pub struct ComponentRefPart {
pub ident: Token,
pub subs: Option<Vec<Subscript>>,
}
impl Debug for ComponentRefPart {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}
impl Display for ComponentRefPart {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.ident.text)?;
if let Some(subs) = &self.subs {
write!(f, "[")?;
for (i, sub) in subs.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", sub)?;
}
write!(f, "]")?;
}
Ok(())
}
}
#[derive(Default, Clone, PartialEq, Serialize, Deserialize)]
pub struct ComponentReference {
pub local: bool,
pub parts: Vec<ComponentRefPart>,
}
impl Display for ComponentReference {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for (i, part) in self.parts.iter().enumerate() {
if i > 0 {
write!(f, ".")?;
}
write!(f, "{}", part)?;
}
Ok(())
}
}
impl Debug for ComponentReference {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}
impl ComponentReference {
pub fn get_location(&self) -> Option<&Location> {
self.parts.first().map(|part| &part.ident.location)
}
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct EquationBlock {
pub cond: Expression,
pub eqs: Vec<Equation>,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StatementBlock {
pub cond: Expression,
pub stmts: Vec<Statement>,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ForIndex {
pub ident: Token,
pub range: Expression,
}
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
pub enum Equation {
#[default]
Empty,
Simple {
lhs: Expression,
rhs: Expression,
},
Connect {
lhs: ComponentReference,
rhs: ComponentReference,
},
For {
indices: Vec<ForIndex>,
equations: Vec<Equation>,
},
When(Vec<EquationBlock>),
If {
cond_blocks: Vec<EquationBlock>,
else_block: Option<Vec<Equation>>,
},
FunctionCall {
comp: ComponentReference,
args: Vec<Expression>,
},
}
impl Equation {
pub fn get_location(&self) -> Option<&Location> {
match self {
Equation::Empty => None,
Equation::Simple { lhs, .. } => lhs.get_location(),
Equation::Connect { lhs, .. } => lhs.get_location(),
Equation::For { indices, .. } => indices.first().map(|i| &i.ident.location),
Equation::When(blocks) => blocks.first().and_then(|b| b.cond.get_location()),
Equation::If { cond_blocks, .. } => {
cond_blocks.first().and_then(|b| b.cond.get_location())
}
Equation::FunctionCall { comp, .. } => comp.get_location(),
}
}
}
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
pub enum OpBinary {
#[default]
Empty,
Add(Token),
Sub(Token),
Mul(Token),
Div(Token),
Eq(Token),
Neq(Token),
Lt(Token),
Le(Token),
Gt(Token),
Ge(Token),
And(Token),
Or(Token),
Exp(Token),
AddElem(Token),
SubElem(Token),
MulElem(Token),
DivElem(Token),
Assign(Token),
}
impl Display for OpBinary {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
OpBinary::Empty => write!(f, ""),
OpBinary::Add(_) => write!(f, "+"),
OpBinary::Sub(_) => write!(f, "-"),
OpBinary::Mul(_) => write!(f, "*"),
OpBinary::Div(_) => write!(f, "/"),
OpBinary::Eq(_) => write!(f, "=="),
OpBinary::Neq(_) => write!(f, "<>"),
OpBinary::Lt(_) => write!(f, "<"),
OpBinary::Le(_) => write!(f, "<="),
OpBinary::Gt(_) => write!(f, ">"),
OpBinary::Ge(_) => write!(f, ">="),
OpBinary::And(_) => write!(f, "and"),
OpBinary::Or(_) => write!(f, "or"),
OpBinary::Exp(_) => write!(f, "^"),
OpBinary::AddElem(_) => write!(f, ".+"),
OpBinary::SubElem(_) => write!(f, ".-"),
OpBinary::MulElem(_) => write!(f, ".*"),
OpBinary::DivElem(_) => write!(f, "./"),
OpBinary::Assign(_) => write!(f, "="),
}
}
}
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
pub enum OpUnary {
#[default]
Empty,
Minus(Token),
Plus(Token),
DotMinus(Token),
DotPlus(Token),
Not(Token),
}
impl Display for OpUnary {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
OpUnary::Empty => write!(f, ""),
OpUnary::Minus(_) => write!(f, "-"),
OpUnary::Plus(_) => write!(f, "+"),
OpUnary::DotMinus(_) => write!(f, ".-"),
OpUnary::DotPlus(_) => write!(f, ".+"),
OpUnary::Not(_) => write!(f, "not "),
}
}
}
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
pub enum TerminalType {
#[default]
Empty,
UnsignedReal,
UnsignedInteger,
String,
Bool,
End,
}
#[derive(Default, Clone, PartialEq, Serialize, Deserialize)]
pub enum Expression {
#[default]
Empty,
Range {
start: Box<Expression>,
step: Option<Box<Expression>>,
end: Box<Expression>,
},
Unary {
op: OpUnary,
rhs: Box<Expression>,
},
Binary {
op: OpBinary,
lhs: Box<Expression>,
rhs: Box<Expression>,
},
Terminal {
terminal_type: TerminalType,
token: Token,
},
ComponentReference(ComponentReference),
FunctionCall {
comp: ComponentReference,
args: Vec<Expression>,
},
Array {
elements: Vec<Expression>,
is_matrix: bool,
},
Tuple {
elements: Vec<Expression>,
},
If {
branches: Vec<(Expression, Expression)>,
else_branch: Box<Expression>,
},
Parenthesized {
inner: Box<Expression>,
},
ArrayComprehension {
expr: Box<Expression>,
indices: Vec<ForIndex>,
},
}
impl Debug for Expression {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expression::Empty => write!(f, "Empty"),
Expression::Range { start, step, end } => f
.debug_struct("Range")
.field("start", start)
.field("step", step)
.field("end", end)
.finish(),
Expression::ComponentReference(comp) => write!(f, "{:?}", comp),
Expression::FunctionCall { comp, args } => f
.debug_struct("FunctionCall")
.field("comp", comp)
.field("args", args)
.finish(),
Expression::Binary { op, lhs, rhs } => f
.debug_struct(&format!("{:?}", op))
.field("lhs", lhs)
.field("rhs", rhs)
.finish(),
Expression::Unary { op, rhs } => f
.debug_struct(&format!("{:?}", op))
.field("rhs", rhs)
.finish(),
Expression::Terminal {
terminal_type,
token,
} => write!(f, "{:?}({:?})", terminal_type, token),
Expression::Array { elements, .. } => f.debug_list().entries(elements.iter()).finish(),
Expression::Tuple { elements } => {
write!(f, "(")?;
for (i, e) in elements.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{:?}", e)?;
}
write!(f, ")")
}
Expression::If {
branches,
else_branch,
} => {
write!(f, "if ")?;
for (i, (cond, expr)) in branches.iter().enumerate() {
if i > 0 {
write!(f, " elseif ")?;
}
write!(f, "{:?} then {:?}", cond, expr)?;
}
write!(f, " else {:?}", else_branch)
}
Expression::Parenthesized { inner } => {
write!(f, "({:?})", inner)
}
Expression::ArrayComprehension { expr, indices } => {
write!(f, "{{{{ {:?} for {:?} }}}}", expr, indices)
}
}
}
}
impl Expression {
pub fn get_location(&self) -> Option<&Location> {
match self {
Expression::Empty => None,
Expression::Range { start, .. } => start.get_location(),
Expression::Unary { rhs, .. } => rhs.get_location(),
Expression::Binary { lhs, .. } => lhs.get_location(),
Expression::Terminal { token, .. } => Some(&token.location),
Expression::ComponentReference(comp) => {
comp.parts.first().map(|part| &part.ident.location)
}
Expression::FunctionCall { comp, .. } => {
comp.parts.first().map(|part| &part.ident.location)
}
Expression::Array { elements, .. } => elements.first().and_then(|e| e.get_location()),
Expression::Tuple { elements } => elements.first().and_then(|e| e.get_location()),
Expression::If { branches, .. } => {
branches.first().and_then(|(cond, _)| cond.get_location())
}
Expression::Parenthesized { inner } => inner.get_location(),
Expression::ArrayComprehension { expr, .. } => expr.get_location(),
}
}
}
impl std::fmt::Display for Expression {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expression::Empty => write!(f, ""),
Expression::Range { start, step, end } => {
if let Some(s) = step {
write!(f, "{}:{}:{}", start, s, end)
} else {
write!(f, "{}:{}", start, end)
}
}
Expression::Unary { op, rhs } => {
let op_str = match op {
OpUnary::Minus(_) => "-",
OpUnary::Plus(_) => "+",
OpUnary::DotMinus(_) => ".-",
OpUnary::DotPlus(_) => ".+",
OpUnary::Not(_) => "not ",
OpUnary::Empty => "",
};
write!(f, "{}{}", op_str, rhs)
}
Expression::Binary { op, lhs, rhs } => {
let op_str = match op {
OpBinary::Add(_) => "+",
OpBinary::Sub(_) => "-",
OpBinary::Mul(_) => "*",
OpBinary::Div(_) => "/",
OpBinary::Eq(_) => "==",
OpBinary::Neq(_) => "<>",
OpBinary::Lt(_) => "<",
OpBinary::Le(_) => "<=",
OpBinary::Gt(_) => ">",
OpBinary::Ge(_) => ">=",
OpBinary::And(_) => "and",
OpBinary::Or(_) => "or",
OpBinary::Exp(_) => "^",
OpBinary::AddElem(_) => ".+",
OpBinary::SubElem(_) => ".-",
OpBinary::MulElem(_) => ".*",
OpBinary::DivElem(_) => "./",
OpBinary::Assign(_) => "=",
OpBinary::Empty => "?",
};
write!(f, "{} {} {}", lhs, op_str, rhs)
}
Expression::Terminal {
terminal_type,
token,
} => match terminal_type {
TerminalType::String => write!(f, "\"{}\"", token.text),
TerminalType::Bool => write!(f, "{}", token.text),
_ => write!(f, "{}", token.text),
},
Expression::ComponentReference(comp) => write!(f, "{}", comp),
Expression::FunctionCall { comp, args } => {
write!(f, "{}(", comp)?;
for (i, arg) in args.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", arg)?;
}
write!(f, ")")
}
Expression::Array { elements, .. } => {
write!(f, "{{")?;
for (i, e) in elements.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", e)?;
}
write!(f, "}}")
}
Expression::Tuple { elements } => {
write!(f, "(")?;
for (i, e) in elements.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", e)?;
}
write!(f, ")")
}
Expression::If {
branches,
else_branch,
} => {
write!(f, "if ")?;
for (i, (cond, expr)) in branches.iter().enumerate() {
if i > 0 {
write!(f, " elseif ")?;
}
write!(f, "{} then {}", cond, expr)?;
}
write!(f, " else {}", else_branch)
}
Expression::Parenthesized { inner } => write!(f, "({})", inner),
Expression::ArrayComprehension { expr, indices } => {
write!(f, "{{ {} for ", expr)?;
for (i, idx) in indices.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{} in {}", idx.ident.text, idx.range)?;
}
write!(f, " }}")
}
}
}
}
impl std::fmt::Display for Equation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Equation::Empty => write!(f, ""),
Equation::Simple { lhs, rhs } => write!(f, "{} = {}", lhs, rhs),
Equation::Connect { lhs, rhs } => write!(f, "connect({}, {})", lhs, rhs),
Equation::For { indices, equations } => {
write!(f, "for ")?;
for (i, idx) in indices.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{} in {}", idx.ident.text, idx.range)?;
}
writeln!(f, " loop")?;
for eq in equations {
writeln!(f, " {};", eq)?;
}
write!(f, "end for")
}
Equation::When(blocks) => {
for (i, block) in blocks.iter().enumerate() {
if i == 0 {
write!(f, "when {} then", block.cond)?;
} else {
write!(f, " elsewhen {} then", block.cond)?;
}
for eq in &block.eqs {
write!(f, " {};", eq)?;
}
}
write!(f, " end when")
}
Equation::If {
cond_blocks,
else_block,
} => {
for (i, block) in cond_blocks.iter().enumerate() {
if i == 0 {
write!(f, "if {} then", block.cond)?;
} else {
write!(f, " elseif {} then", block.cond)?;
}
for eq in &block.eqs {
write!(f, " {};", eq)?;
}
}
if let Some(else_eqs) = else_block {
write!(f, " else")?;
for eq in else_eqs {
write!(f, " {};", eq)?;
}
}
write!(f, " end if")
}
Equation::FunctionCall { comp, args } => {
write!(f, "{}(", comp)?;
for (i, arg) in args.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", arg)?;
}
write!(f, ")")
}
}
}
}
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
pub enum Statement {
#[default]
Empty,
Assignment {
comp: ComponentReference,
value: Expression,
},
Return {
token: Token,
},
Break {
token: Token,
},
For {
indices: Vec<ForIndex>,
equations: Vec<Statement>,
},
While(StatementBlock),
If {
cond_blocks: Vec<StatementBlock>,
else_block: Option<Vec<Statement>>,
},
When(Vec<StatementBlock>),
FunctionCall {
comp: ComponentReference,
args: Vec<Expression>,
outputs: Vec<Expression>,
},
}
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
pub enum Subscript {
#[default]
Empty,
Expression(Expression),
Range {
token: Token,
},
}
impl Display for Subscript {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Subscript::Empty => write!(f, ""),
Subscript::Expression(expr) => write!(f, "{}", expr),
Subscript::Range { .. } => write!(f, ":"),
}
}
}
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
pub enum Variability {
#[default]
Empty,
Constant(Token),
Discrete(Token),
Parameter(Token),
}
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
pub enum Connection {
#[default]
Empty,
Flow(Token),
Stream(Token),
}
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
pub enum Causality {
#[default]
Empty,
Input(Token),
Output(Token),
}