From bbd3224a4b029372fbba4a3b56ff65c64b055537 Mon Sep 17 00:00:00 2001 From: James Goppert Date: Sun, 12 Jan 2025 04:59:20 -0500 Subject: [PATCH] Add parser support for extends, while, connect. Signed-off-by: James Goppert --- src/s0_lexer/tokens.rs | 2 +- src/s1_parser/ast.rs | 103 +++++++++++++-- src/s1_parser/modelica.lalrpop | 226 +++++++++++++++++++++++++-------- src/s2_analyzer/flattener.rs | 111 ++++++++++------ test/models/simple_circuit.mo | 2 +- 5 files changed, 338 insertions(+), 106 deletions(-) diff --git a/src/s0_lexer/tokens.rs b/src/s0_lexer/tokens.rs index 40eebf1..f681885 100644 --- a/src/s0_lexer/tokens.rs +++ b/src/s0_lexer/tokens.rs @@ -177,7 +177,7 @@ pub enum Token { #[regex("[_a-zA-Z][_0-9a-zA-Z]*", |lex| lex.slice().to_string())] Identifier(String), - #[regex("\"[ _0-9a-zA-Z]*\"", quoted_string_callback)] + #[regex("\"[\\- _0-9a-zA-Z]*\"", quoted_string_callback)] String(String), #[regex("[1-9][0-9]*", |lex| lex.slice().parse::().unwrap(), priority=3)] diff --git a/src/s1_parser/ast.rs b/src/s1_parser/ast.rs index dc87923..045e841 100644 --- a/src/s1_parser/ast.rs +++ b/src/s1_parser/ast.rs @@ -27,12 +27,32 @@ pub struct ClassPrefixes { pub class_type: ClassType, } -#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] -pub struct ClassSpecifier { - pub name: String, - pub description: Vec, - pub composition: Vec, - pub name_end: String, +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub enum ClassSpecifier { + Long { + name: String, + description: Vec, + composition: Vec, + name_end: String, + }, + Extends { + name: String, + modification: Option>, + description: Vec, + composition: Vec, + name_end: String, + }, +} + +impl Default for ClassSpecifier { + fn default() -> Self { + ClassSpecifier::Long { + name: "".to_string(), + description: Vec::new(), + composition: Vec::new(), + name_end: "".to_string(), + } + } } #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] @@ -59,13 +79,40 @@ pub enum CompositionPart { }, } +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct ComponentClause { + pub type_prefix: TypePrefix, + pub type_specifier: TypeSpecifier, + pub array_subscripts: Option>, + pub components: Vec, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct ElementFlags { + pub replaceable: bool, + pub redeclare: bool, + pub final_: bool, + pub inner: bool, + pub outer: bool, +} + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum Element { + ImportClause { + alias: String, + name: Name, + description: Description, + }, ComponentClause { - type_prefix: TypePrefix, + flags: ElementFlags, + clause: ComponentClause, + }, + ClassDefinition { + flags: ElementFlags, + def: ClassDefinition, + }, + ExtendsClause { type_specifier: TypeSpecifier, - array_subscripts: Option>, - components: Vec, }, } @@ -102,20 +149,30 @@ pub enum Statement { Assignment { comp: ComponentReference, rhs: Expression, + description: Description, }, If { if_cond: Expression, if_stmts: Vec, else_if_blocks: Vec, else_stmts: Vec, + description: Description, }, For { indices: Vec, stmts: Vec, + description: Description, }, While { cond: Expression, stmts: Vec, + description: Description, + }, + Break { + description: Description, + }, + Return { + description: Description, }, } @@ -136,16 +193,24 @@ pub enum Equation { Simple { lhs: Expression, rhs: Expression, + description: Description, }, If { if_cond: Expression, if_eqs: Vec, else_if_blocks: Vec, else_eqs: Vec, + description: Description, }, For { indices: Vec, eqs: Vec, + description: Description, + }, + Connect { + lhs: ComponentReference, + rhs: ComponentReference, + description: Description, }, } @@ -288,15 +353,27 @@ pub enum Expression { }, } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct Description { pub strings: Vec, pub annotation: Vec, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct Modification { - pub expression: Expression, +pub enum ModExpr { + Break, + Expression { expr: Expression }, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub enum Modification { + Expression { + expr: ModExpr, + }, + Class { + args: Vec, + expr: Option, + }, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -366,7 +443,7 @@ pub enum Subscript { #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] pub enum ClassType { #[default] - Unknown, + Class, Model, Record, OperatorRecord, diff --git a/src/s1_parser/modelica.lalrpop b/src/s1_parser/modelica.lalrpop index f357794..2675253 100644 --- a/src/s1_parser/modelica.lalrpop +++ b/src/s1_parser/modelica.lalrpop @@ -204,6 +204,7 @@ pub ClassPrefixes: ast::ClassPrefixes = { } pub ClassType: ast::ClassType = { + "class" => ast::ClassType::Class, "model" => ast::ClassType::Model, "record" => ast::ClassType::Record, "operator" "record" => ast::ClassType::OperatorRecord, @@ -227,21 +228,38 @@ pub ClassSpecifier: ast::ClassSpecifier = { => spec, } +pub IDENT: String = { + => ident, +} + //✅ long-class-specifier : //✅ IDENT description-string composition end IDENT -//🟥 | extends IDENT [ class-modification ] description-string composition end IDENT +//✅ | extends IDENT [ class-modification ] description-string composition end IDENT pub LongClassSpecifier: ast::ClassSpecifier = { - + "end" - => { - ast::ClassSpecifier { + => { + ast::ClassSpecifier::Long { name, description: description.unwrap_or(Vec::new()), composition, name_end, } + }, + "extends" + + + + "end" => { + ast::ClassSpecifier::Extends { + name, + modification, + description, + composition, + name_end, + } } } @@ -320,37 +338,106 @@ pub ElementList: Vec = { > => elements } -//🟨 element : -//🟥 import-clause -//🟥 | extends-clause -//🟨 | [ redeclare ] [ final ] [ inner ] [ outer ] ( -//🟥 class-definition -//🟥 | component-clause -//🟥 | replaceable ( -//🟥 class-definition +//✅ element : +//✅ import-clause +//✅ | extends-clause +//✅ | [ redeclare ] [ final ] [ inner ] [ outer ] ( +//✅ class-definition +//✅ | component-clause +//✅ | replaceable ( +//✅ class-definition //✅ | component-clause) //🟥 [ constraining-clause description ]) +pub ElementFlags : ast::ElementFlags = { + + + + + => { + ast::ElementFlags { + redeclare: redeclare.is_some(), + final_: final_.is_some(), + inner: inner.is_some(), + outer: outer.is_some(), + replaceable: replaceable.is_some(), + } + } +} pub Element : ast::Element = { - => elem + => { + ast::Element::ComponentClause { + flags, + clause, + } + }, + => { + ast::Element::ClassDefinition { + flags, + def, + } + }, + => extends, } -//🟥 import-clause : -//🟥 import -//🟥 ( IDENT "=" name -//🟥 | name [ ".*" | "." ( "*" | "{" import-list "}" ) ] -//🟥 ) -//🟥 description +//✅ import-clause : +//✅ import +//✅ ( IDENT "=" name +//🟥 | name [ ".*" | "." ( "*" | "{" import-list "}" ) ]) +//✅ description + +pub ImportClause : ast::Element = { + // qualified import + "import" => { + ast::Element::ImportClause { + alias: "".to_string(), + name, + description, + } + }, + // unqualified import + // "import" ".*" => { + // ast::Element::ImportClause { + // alias: None, + // name, + // } + // }, + // renaming qualified import + // "import" "=" => { + // ast::Element::ImportClause { + // alias: None, + // name, + // } + // }, + // multiple definition import + // "import" "." "{" SeparatedListMinOne "}"=> { + // ast::Element::ImportClause { + // alias: None, + // name, + // } + // } +} -//🟥 import-list : -//🟥 IDENT { "," IDENT } +//✅ import-list : +//✅ IDENT { "," IDENT } +// Note: flattened into import-clause // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // A.2.3 Extends // ✅: Implemented, 🟥: Not-Implemented, 🟨: Partial -//🟥 extends-clause : -//🟥 extends type-specifier [ class-or-inheritance-modification ] [ annotation-clause ] +//✅ extends-clause : +//✅ extends type-specifier +//🟥 [ class-or-inheritance-modification ] +//🟥 [ annotation-clause ] +pub ExtendsClause: ast::Element = { + "extends" + => { + ast::Element::ExtendsClause { + type_specifier, + } + } +} //🟥 constraining-clause : //🟥 constrainedby type-specifier [ class-modification ] @@ -370,12 +457,12 @@ pub Element : ast::Element = { //✅ component-clause : //✅ type-prefix type-specifier [ array-subscripts ] component-list -pub ComponentClause: ast::Element = { +pub ComponentClause: ast::ComponentClause = { => { - ast::Element::ComponentClause { + ast::ComponentClause { type_prefix, type_specifier, array_subscripts, @@ -441,7 +528,7 @@ pub ConditionAttribute: ast::Expression = { //✅ declaration : //✅ IDENT [ array-subscripts ] [ modification ] pub Declaration: ast::Declaration = { - + => { ast::Declaration { @@ -457,18 +544,28 @@ pub Declaration: ast::Declaration = { // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // ✅: Implemented, 🟥: Not-Implemented, 🟨: Partial -//🟨 modification : -//🟥 class-modification [ "=" modification-expression ] -//🟨 | "=" modification-expression +//✅ modification : +//✅ class-modification [ "=" modification-expression ] +//✅ | "=" modification-expression pub Modification: ast::Modification = { - "=" => ast::Modification { - expression - } + => ast::Modification::Expression { + expr, + }, } -//🟥 modification-expression : -//🟥 expression -//🟥 | break +//✅ modification-expression : +//✅ expression +//✅ | break +pub ModExpr: ast::ModExpr = { + => ast::ModExpr::Expression { + expr + }, + "break" => ast::ModExpr::Break {} +} //✅ class-modification : //✅ "(" [ argument-list ] ")" @@ -568,41 +665,47 @@ pub AlgorithmSection: ast::CompositionPart = { //✅ ( simple-expression "=" expression //✅ | if-equation //✅ | for-equation -//🟥 | connect-equation +//✅ | connect-equation //🟥 | when-equation //🟥 | component-reference function-call-args ) //🟥 description pub Equation: ast::Equation = { - "=" => { + "=" => { ast::Equation::Simple { lhs, - rhs + rhs, + description, } }, => eq, => eq, + => eq, } //✅ statement : //✅ ( component-reference ( ":=" expression | function-call-args ) //🟥 | "(" output-expression-list ")" ":=" component-reference function-call-args -//🟥 | break -//🟥 | return +//✅ | break +//✅ | return //✅ | if-statement //✅ | for-statement -//🟥 | while-statement +//✅ | while-statement //🟥 | when-statement ) -//🟥 description +//✅ description pub Statement: ast::Statement = { - ":=" => { + ":=" => { ast::Statement::Assignment{ comp, - rhs + rhs, + description, } }, => stmt, => stmt, + => stmt, + "break" => ast::Statement::Break { description }, + "return" => ast::Statement::Return { description }, } //✅ if-equation : @@ -621,12 +724,13 @@ pub IfEquation: ast::Equation = { > - "end" "if" => { + "end" "if" => { ast::Equation::If { if_cond, if_eqs, else_if_blocks, else_eqs: else_eqs.unwrap_or(Vec::new()), + description, } } } @@ -661,11 +765,12 @@ pub IfStatement: ast::Statement = { > - "end" "if" => { + "end" "if" => { ast::Statement::If { if_cond, if_stmts, else_if_blocks, else_stmts: else_stmts.unwrap_or(Vec::new()), + description, } } } @@ -692,11 +797,12 @@ pub ElseStatementBlock: Vec = { pub ForEquation: ast::Equation = { "for" "loop" > - "end" "for" + "end" "for" => { ast::Equation::For { indices, eqs, + description, } } } @@ -708,11 +814,12 @@ pub ForEquation: ast::Equation = { pub ForStatement: ast::Statement = { "for" "loop" > - "end" "for" + "end" "for" => { ast::Statement::For { indices, stmts, + description, } } } @@ -726,7 +833,7 @@ pub ForIndices: Vec = { //✅ for-index : //✅ IDENT [ in expression ] pub ForIndex: ast::ForIndex = { - )?> => { + )?> => { ast::ForIndex { ident, in_expr, @@ -746,6 +853,7 @@ pub WhileStatement: ast::Statement = { ast::Statement::While { cond, stmts, + description: ast::Description::default(), } } } @@ -766,8 +874,20 @@ pub WhileStatement: ast::Statement = { //🟥 } //🟥 end when -//🟥 connect-equation : -//🟥 connect "(" component-reference "," component-reference ")" +//✅ connect-equation : +//✅ connect "(" component-reference "," component-reference ")" +pub ConnectEquation: ast::Equation = { + "connect" "(" + "," + ")" + => { + ast::Equation::Connect { + lhs, + rhs, + description, + } + } +} // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // A.2.7 Expressions @@ -1038,7 +1158,7 @@ pub TypeSpecifier: ast::TypeSpecifier = { //✅ name : //✅ IDENT { "." IDENT } pub Name: ast::Name = { - )*> => { + )*> => { let mut v = vec![first]; v.extend(remaining); ast::Name { @@ -1059,7 +1179,7 @@ pub ComponentReference: ast::ComponentReference = { }, } pub RefPart: ast::RefPart = { - => { + => { ast::RefPart { name, array_subscripts: array_subscripts.unwrap_or(Vec::new()), diff --git a/src/s2_analyzer/flattener.rs b/src/s2_analyzer/flattener.rs index 322a67e..5080059 100644 --- a/src/s2_analyzer/flattener.rs +++ b/src/s2_analyzer/flattener.rs @@ -1,5 +1,6 @@ use crate::s1_parser::ast::{ - self as parse_ast, Causality, Element, Expression, Statement, Subscript, Variability, + self as parse_ast, Causality, Element, Expression, ModExpr, Modification, Statement, Subscript, + Variability, }; use crate::s2_analyzer::ast; use ndarray::{ArrayBase, ArrayD, IxDyn, OwnedRepr}; @@ -50,7 +51,17 @@ pub fn evaluate( Ok(ArrayD::from_shape_vec(shape, values).unwrap()) } Expression::Ref { comp } => match &class.components[&compref_to_string(comp)].start { - Some(m) => Ok(evaluate(class, &m.expression)?), + Some(m) => match m { + Modification::Expression { expr } => match expr { + ModExpr::Expression { expr } => Ok(evaluate(class, expr)?), + ModExpr::Break => { + todo!("{:?}", m); + } + }, + Modification::Class { .. } => { + todo!("{:?}", m); + } + }, None => { panic!("no start value defined for {:?}", comp); } @@ -105,7 +116,19 @@ pub fn evaluate_expressions( ) { for (name, comp) in &class.components { if let Some(m) = &comp.start { - start_vals.insert(name.clone(), evaluate(class, &m.expression).unwrap()); + match m { + Modification::Expression { expr } => match expr { + ModExpr::Expression { expr: e } => { + start_vals.insert(name.clone(), evaluate(class, e).unwrap()); + } + ModExpr::Break => { + todo!("{:?}", m); + } + }, + Modification::Class { .. } => { + todo!("{:?}", m); + } + } } } } @@ -123,14 +146,26 @@ pub fn set_start_expressions( pub fn flatten_class(class: &parse_ast::ClassDefinition, def: &mut ast::Def) { let mut fclass = ast::Class { - name: class.class_specifier.name.clone(), class_type: class.class_prefixes.class_type.clone(), - description: class.class_specifier.description.clone(), ..Default::default() }; - for composition_part in &class.class_specifier.composition { - flatten_composition_part(composition_part, &mut fclass) + match &class.class_specifier { + parse_ast::ClassSpecifier::Long { + name, + description, + composition, + .. + } => { + fclass.name = name.clone(); + fclass.description = description.clone(); + for composition_part in composition.iter() { + flatten_composition_part(composition_part, &mut fclass) + } + } + parse_ast::ClassSpecifier::Extends { .. } => { + todo!("{:?}", class.class_specifier); + } } def.classes.insert(fclass.name.to_string(), fclass.clone()); @@ -165,21 +200,16 @@ pub fn flatten_composition_part(composition: &parse_ast::CompositionPart, class: } pub fn flatten_element(elem: &Element, class: &mut ast::Class) { - match &elem { - &Element::ComponentClause { - type_prefix, - type_specifier: _, - array_subscripts, - components, - } => { - for comp in components.iter() { + match elem { + Element::ComponentClause { flags: _, clause } => { + for comp in clause.components.iter() { // determine array subscripts let comp_sub = match &comp.declaration.array_subscripts { Some(sub) => { // already has array subscripts sub.clone() } - None => match array_subscripts { + None => match &clause.array_subscripts { Some(clause_sub) => { // take array subscripts from clause clause_sub.clone() @@ -202,11 +232,11 @@ pub fn flatten_element(elem: &Element, class: &mut ast::Class) { .components .insert(flat_comp.name.clone(), flat_comp.clone()); - match type_prefix.variability { + match clause.type_prefix.variability { Variability::Constant => { class.c.insert(flat_comp.name.to_string()); } - Variability::Continuous => match type_prefix.causality { + Variability::Continuous => match clause.type_prefix.causality { Causality::Input => { class.u.insert(flat_comp.name.to_string()); } @@ -226,6 +256,15 @@ pub fn flatten_element(elem: &Element, class: &mut ast::Class) { } } } + Element::ClassDefinition { .. } => { + todo!("{:?}", elem); + } + Element::ImportClause { .. } => { + todo!("{:?}", elem); + } + Element::ExtendsClause { .. } => { + todo!("{:?}", elem); + } } } @@ -242,20 +281,18 @@ pub fn compref_to_string(comp: &parse_ast::ComponentReference) -> String { pub fn flatten_equation(eq: &parse_ast::Equation, class: &mut ast::Class) { match eq { - parse_ast::Equation::Simple { lhs, rhs } => { + parse_ast::Equation::Simple { lhs, rhs, .. } => { class.algebraic.push(eq.clone()); flatten_expression(lhs, class); flatten_expression(rhs, class); } - parse_ast::Equation::If { - if_cond: _, - if_eqs: _, - else_if_blocks: _, - else_eqs: _, - } => { + parse_ast::Equation::If { .. } => { todo!("{:?}", eq); } - parse_ast::Equation::For { indices: _, eqs: _ } => { + parse_ast::Equation::For { .. } => { + todo!("{:?}", eq); + } + parse_ast::Equation::Connect { .. } => { todo!("{:?}", eq); } } @@ -304,24 +341,22 @@ pub fn flatten_expression(expr: &Expression, class: &mut ast::Class) { pub fn flatten_statement(stmt: &parse_ast::Statement, class: &mut ast::Class) { match &stmt { - Statement::Assignment { comp: _, rhs: _ } => { + Statement::Assignment { .. } => { class.algorithm.push(stmt.clone()); } - Statement::If { - if_cond: _, - if_stmts: _, - else_if_blocks: _, - else_stmts: _, - } => { + Statement::If { .. } => { todo!("{:?}", stmt); } - parse_ast::Statement::For { - indices: _, - stmts: _, - } => { + parse_ast::Statement::For { .. } => { + todo!("{:?}", stmt); + } + parse_ast::Statement::While { .. } => { + todo!("{:?}", stmt); + } + parse_ast::Statement::Break { .. } => { todo!("{:?}", stmt); } - parse_ast::Statement::While { cond: _, stmts: _ } => { + parse_ast::Statement::Return { .. } => { todo!("{:?}", stmt); } } diff --git a/test/models/simple_circuit.mo b/test/models/simple_circuit.mo index 9527b48..beed676 100644 --- a/test/models/simple_circuit.mo +++ b/test/models/simple_circuit.mo @@ -46,7 +46,7 @@ equation end Ground; class VsourceAC "Sin-wave voltage source" - extends TwoPin; + extends TwoPin; parameter Real VA = 220 "Amplitude"; parameter Real f = 50 "Frequency"; constant Real PI = 3.14159;