From dbefa0f0b7c38a4e685dc649705a55df92316735 Mon Sep 17 00:00:00 2001 From: James Goppert Date: Fri, 10 Jan 2025 01:48:26 -0500 Subject: [PATCH] Expand parser support and highlight supported grammar. Signed-off-by: James Goppert --- src/s0_lexer/tokens.rs | 2 +- src/s1_parser/ast.rs | 94 +++- src/s1_parser/modelica.lalrpop | 891 +++++++++++++++++++-------------- src/s2_analyzer/ast.rs | 2 +- src/s2_analyzer/flattener.rs | 188 ++++--- test/models/quadrotor.mo | 40 +- test/templates/casadi_sx.jinja | 80 ++- 7 files changed, 757 insertions(+), 540 deletions(-) diff --git a/src/s0_lexer/tokens.rs b/src/s0_lexer/tokens.rs index 0ec56fd..40eebf1 100644 --- a/src/s0_lexer/tokens.rs +++ b/src/s0_lexer/tokens.rs @@ -178,7 +178,7 @@ pub enum Token { Identifier(String), #[regex("\"[ _0-9a-zA-Z]*\"", quoted_string_callback)] - Description(String), + String(String), #[regex("[1-9][0-9]*", |lex| lex.slice().parse::().unwrap(), priority=3)] UnsignedInteger(i64), diff --git a/src/s1_parser/ast.rs b/src/s1_parser/ast.rs index aeb7234..d63804e 100644 --- a/src/s1_parser/ast.rs +++ b/src/s1_parser/ast.rs @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct StoredDefinition { pub classes: Vec, + pub within: Option, pub model_md5: String, pub rumoca_git_hash: String, } @@ -10,30 +11,45 @@ pub struct StoredDefinition { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[allow(clippy::vec_box)] pub struct ComponentDeclaration { + pub declaration: Declaration, + pub condition_attribute: Option>, + pub description: Description, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[allow(clippy::vec_box)] +pub struct ComponentDeclaration1 { + pub declaration: Declaration, + pub description: Description, +} + +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +pub struct ClassPrefixes { + pub is_partial: bool, + pub class_type: ClassType, +} + +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +pub struct ClassSpecifier { pub name: String, - pub class: String, - pub connection: Connection, - pub variability: Variability, - pub causality: Causality, - pub array_subscripts: Vec, - pub modification: Option, + pub description: Vec, + pub composition: Vec, + pub name_end: String, } #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct ClassDefinition { - pub name: String, - pub description: String, - pub class_type: ClassType, - pub partial: bool, - pub encapsulated: bool, - pub compositions: Vec, + pub is_encapsulated: bool, + pub is_final: bool, + pub class_prefixes: ClassPrefixes, + pub class_specifier: ClassSpecifier, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub enum Composition { +pub enum CompositionPart { ElementList { visibility: Visibility, - elements: Vec, + elements: Vec, }, EquationSection { initial: bool, @@ -45,6 +61,16 @@ pub enum Composition { }, } +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub enum Element { + ComponentClause { + type_prefix: TypePrefix, + type_specifier: TypeSpecifier, + array_subscripts: Option>, + components: Vec, + }, +} + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum Causality { None, @@ -88,12 +114,17 @@ pub enum Statement { } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[allow(clippy::vec_box)] -pub struct ComponentReference { +pub struct RefPart { pub name: String, pub array_subscripts: Vec, } +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct ComponentReference { + pub local: bool, + pub parts: Vec, +} + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum Equation { Der { @@ -242,6 +273,12 @@ pub enum Expression { }, } +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct Description { + pub strings: Vec, + pub annotation: Vec, +} + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Modification { pub expression: Box, @@ -250,18 +287,18 @@ pub struct Modification { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Declaration { pub name: String, - pub array_subscripts: Vec, + pub array_subscripts: Option>, pub modification: Option, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum Argument { - Modificaion { + Modification { name: Name, each: bool, is_final: bool, modification: Option, - description: String, + description: Description, }, Replaceable, Redeclaration, @@ -275,11 +312,23 @@ pub struct TypePrefix { } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct ComponentClause { - pub type_prefix: TypePrefix, +pub struct Component { + pub connection: Connection, + pub variability: Variability, + pub causality: Causality, pub type_specifier: TypeSpecifier, + pub name: String, pub array_subscripts: Vec, - pub components: Vec, + pub modification: Option, + pub condition_attribute: Option>, + pub description: Description, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct ComponentClause1 { + pub type_prefix: TypePrefix, + pub type_specifier: TypeSpecifier, + pub component_declaration1: ComponentDeclaration1, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -328,7 +377,6 @@ mod tests { // class ball let class_ball = ClassDefinition { - name: String::from("Ball"), ..Default::default() }; def.classes.push(class_ball); diff --git a/src/s1_parser/modelica.lalrpop b/src/s1_parser/modelica.lalrpop index 1fbae5f..4b17dab 100644 --- a/src/s1_parser/modelica.lalrpop +++ b/src/s1_parser/modelica.lalrpop @@ -4,8 +4,9 @@ use crate::s1_parser::ast; grammar; +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // LALRPOP macros -// ============================================================================ + CommaSeparatedList: Vec = { ",")*> => match e { None => v, @@ -30,8 +31,9 @@ SemicolonTerminatedList: Vec = { ";")*> => v }; +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // 2.3.3 Modelica Keywords -// ============================================================================ + extern { type Location = usize; type Error = LexicalError; @@ -90,17 +92,16 @@ extern { "return" => Token::KeywordReturn, "stream" => Token::KeywordStream, "then" => Token::KeywordThen, - "boolean" => Token::Boolean, "type" => Token::KeywordType, "when" => Token::KeywordWhen, "while" => Token::KeywordWhile, "within" => Token::KeywordWithin, // other lexical tokens - "identifier" => Token::Identifier(), - "description" => Token::Description(), - "unsigned_integer" => Token::UnsignedInteger(), - "unsigned_real" => Token::UnsignedReal(), + "IDENT" => Token::Identifier(), + "STRING" => Token::String(), + "UNSIGNED-INTEGER" => Token::UnsignedInteger(), + "UNSIGNED-REAL" => Token::UnsignedReal(), "boolean" => Token::Boolean(), "(" => Token::LParen, ")" => Token::RParen, @@ -135,55 +136,74 @@ extern { } } +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // A.2.1 Stored Definition – Within -// ============================================================================ -// stored-definition : -// [ within [ name ] ";" ] -// { [ final ] class-definition ";" } +// ✅: Implemented, 🟥: Not-Implemented, 🟨: Partial + +//✅ stored-definition : +//✅ [ within [ name ] ";" ] +//✅ { [ final ] class-definition ";" } +pub Within: ast::Name = { + "within" ";" => name +} pub StoredDefinition: ast::StoredDefinition = { - => { + + > => { ast::StoredDefinition { classes, + within, rumoca_git_hash: "".to_string(), model_md5: "".to_string(), } } } +pub ClassDefinitionWithFinal: ast::ClassDefinition = { + => { + class.is_final = is_final.is_some(); + class + } +} + +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // A.2.2 Class Definition -// ============================================================================ -// class-definition : -// [ encapsulated ] class-prefixes class-specifier +// ✅: Implemented, 🟥: Not-Implemented, 🟨: Partial + +//✅ class-definition : +//✅ [ encapsulated ] class-prefixes class-specifier pub ClassDefinition: ast::ClassDefinition = { - - - - - "end" "identifier" ";" => { - let mut comp_vec = vec![element_list_first]; - comp_vec.extend(compositions); + + + => { ast::ClassDefinition { - name, - description: description.unwrap_or("".to_string()), + is_final: false, + is_encapsulated: is_encapsulated.is_some(), + class_prefixes, + class_specifier, + } + } +} +//✅ class-prefixes : +//✅ [ partial ] +//✅ ( class +//✅ | model +//✅ | [ operator ] record +//✅ | block +//✅ | [ expandable ] connector +//✅ | type +//✅ | package +//✅ | [ pure | impure ] [ operator ] function +//✅ | operator +//✅ ) +pub ClassPrefixes: ast::ClassPrefixes = { + => { + ast::ClassPrefixes { + is_partial: partial.is_some(), class_type, - partial: partial.is_some(), - encapsulated: encapsulated.is_some(), - compositions: comp_vec, } } } -// class-prefixes : -// [ partial ] -// ( class -// | model -// | [ operator ] record -// | block -// | [ expandable ] connector -// | type -// | package -// | [ pure | impure ] [ operator ] function -// | operator -// ) + pub ClassType: ast::ClassType = { "model" => ast::ClassType::Model, "record" => ast::ClassType::Record, @@ -200,130 +220,175 @@ pub ClassType: ast::ClassType = { "operator" => ast::ClassType::Operator, } -// TODO -// class-specifier : -// long-class-specifier | short-class-specifier | der-class-specifier -// long-class-specifier : -// IDENT description-string composition end IDENT -// | extends IDENT [ class-modification ] description-string composition -// end IDENT -// short-class-specifier : -// IDENT "=" base-prefix type-specifier [ array-subscripts ] -// [ class-modification ] description -// | IDENT "=" enumeration "(" ( [ enum-list ] | ":" ) ")" description -// der-class-specifier : -// IDENT "=" der "(" type-specifier "," IDENT { "," IDENT } ")" description -// base-prefix : -// [ input | output ] -// enum-list : -// enumeration-literal { "," enumeration-literal } -// enumeration-literal : -// IDENT description -// composition : -// element-list -// { public element-list -// | protected element-list -// | equation-section -// | algorithm-section -// } -pub ElementListDefaultPublic: ast::Composition = { - => { - ast::Composition::ElementList { - visibility: ast::Visibility::Public, - elements, +//✅ class-specifier : +//✅ long-class-specifier +//🟥 | short-class-specifier +//🟥 | der-class-specifier +pub ClassSpecifier: ast::ClassSpecifier = { + => spec, +} + +//✅ long-class-specifier : +//✅ IDENT description-string composition end IDENT +//🟥 | extends IDENT [ class-modification ] description-string composition end IDENT +pub LongClassSpecifier: ast::ClassSpecifier = { + + + + "end" + => { + ast::ClassSpecifier { + name, + description: description.unwrap_or(Vec::new()), + composition, + name_end, } } } -pub ElementList: ast::Composition = { - => { - ast::Composition::ElementList { - visibility, - elements, - } +//🟥 short-class-specifier : +//🟥 IDENT "=" base-prefix type-specifier [ array-subscripts ] [ class-modification ] description +//🟥 | IDENT "=" enumeration "(" ( [ enum-list ] | ":" ) ")" description + +//🟥 der-class-specifier : +//🟥 IDENT "=" der "(" type-specifier "," IDENT { "," IDENT } ")" description + +//🟥 base-prefix : +//🟥 [ input | output ] + +//🟥 enum-list : +//🟥 enumeration-literal { "," enumeration-literal } + +//🟥 enumeration-literal : +//🟥 IDENT description + +//✅ composition : +//✅ element-list +//✅ { public element-list +//✅ | protected element-list +//✅ | equation-section +//✅ | algorithm-section +//✅ } +//🟥 [ external [ language-specification ] +//🟥 [ external-function-call ] [ annotation-clause ] ";" +//🟥 ] +//🟥 [ annotation-clause ";" ] +pub Composition: Vec = { + + + => { + let mut v = Vec::new(); + v.push(ast::CompositionPart::ElementList { + visibility: ast::Visibility::Public, + elements: first, + }); + v.extend(remaining); + v } } -pub Composition: ast::Composition = { - => comp, +pub CompositionPart: ast::CompositionPart = { + => comp, => comp, => comp, } +pub ElementListWithVisibility: ast::CompositionPart = { + => { + ast::CompositionPart::ElementList { + visibility, + elements, + } + } +} + pub Visibility: ast::Visibility = { "public" => ast::Visibility::Public, "protected" => ast::Visibility::Protected, } +//✅ language-specification : +//✅ STRING +pub LanguageSpecification: String = { + => string +} +//🟥 external-function-call : +//🟥 [ component-reference "=" ] IDENT "(" [ expression-list ] ")" + +//✅ element-list : +//✅ { element ";" } +pub ElementList: Vec = { + > => elements +} + +//🟨 element : +//🟥 import-clause +//🟥 | extends-clause +//🟨 | [ redeclare ] [ final ] [ inner ] [ outer ] ( +//🟥 class-definition +//🟥 | component-clause +//🟥 | replaceable ( +//🟥 class-definition +//✅ | component-clause) +//🟥 [ constraining-clause description ]) +pub Element : ast::Element = { + => elem +} + +//🟥 import-clause : +//🟥 import +//🟥 ( IDENT "=" name +//🟥 | name [ ".*" | "." ( "*" | "{" import-list "}" ) ] +//🟥 ) +//🟥 description + +//🟥 import-list : +//🟥 IDENT { "," IDENT } + + +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// A.2.3 Extends +// ✅: Implemented, 🟥: Not-Implemented, 🟨: Partial + +//🟥 extends-clause : +//🟥 extends type-specifier [ class-or-inheritance-modification ] [ annotation-clause ] -// [ external [ language-specification ] -// [ external-function-call ] [ annotation-clause ] ";" -// ] -// [ annotation-clause ";" ] -// language-specification : -// STRING -// external-function-call : -// [ component-reference "=" ] -// IDENT "(" [ expression-list ] ")" -// element-list : -// { element ";" } -// element : -// import-clause -// | extends-clause -// | [ redeclare ] -// [ final ] -// [ inner ] [ outer ] -// ( class-definition -// | component-clause -// | replaceable ( class-definition | component-clause ) -// [ constraining-clause description ] -// ) -// import-clause : -// import -// ( IDENT "=" name -// | name [ ".*" | "." ( "*" | "{" import-list "}" ) ] -// ) -// description -// import-list : -// IDENT { "," IDENT } -// - -// A.2.3 Extends (TODO) -// ============================================================================ -// extends-clause : -// extends type-specifier [ class-or-inheritance-modification ] [ annotation-clause ] -// constraining-clause : -// constrainedby type-specifier [ class-modification ] -// class-or-inheritance-modification : -// "(" [ argument-or-inheritance-modification-list ] ")" -// argument-or-inheritance-modification-list : -// ( argument | inheritance-modification ) { "," ( argument | inheritance-modification ) } -// inheritance-modification : -// break ( connect-equation | IDENT ) +//🟥 constraining-clause : +//🟥 constrainedby type-specifier [ class-modification ] +//🟥 class-or-inheritance-modification : +//🟥 "(" [ argument-or-inheritance-modification-list ] ")" +//🟥 argument-or-inheritance-modification-list : +//🟥 ( argument | inheritance-modification ) { "," ( argument | inheritance-modification ) } + +//🟥 inheritance-modification : +//🟥 break ( connect-equation | IDENT ) + +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // A.2.4 Component Clause -// ============================================================================ -// component-clause : -// type-prefix type-specifier [ array-subscripts ] component-list -pub ComponentClause: ast::ComponentClause = { +// ✅: Implemented, 🟥: Not-Implemented, 🟨: Partial + +//✅ component-clause : +//✅ type-prefix type-specifier [ array-subscripts ] component-list +pub ComponentClause: ast::Element = { - - > => { - ast::ComponentClause { + + => { + ast::Element::ComponentClause { type_prefix, type_specifier, array_subscripts, - components + components, } } } -// type-prefix : -// [ flow | stream ] -// [ discrete | parameter | constant ] -// [ input | output ] +//✅ type-prefix : +//✅ [ flow | stream ] +//✅ [ discrete | parameter | constant ] +//✅ [ input | output ] pub TypePrefix: ast::TypePrefix = { @@ -348,89 +413,80 @@ pub Causality: ast::Causality = { "input" => ast::Causality::Input, "output" => ast::Causality::Output, } -// component-list : -// component-declaration { "," component-declaration } +//✅ component-list : +//✅ component-declaration { "," component-declaration } pub ComponentList: Vec = { > => { components } } -// component-declaration : -// declaration [ condition-attribute ] description +//✅ component-declaration : +//✅ declaration [ condition-attribute ] description pub ComponentDeclaration: ast::ComponentDeclaration = { - - - - - - - - ";" + + + => { ast::ComponentDeclaration{ - name, - class, - connection: connection.unwrap_or(ast::Connection::None), - variability: variability.unwrap_or(ast::Variability::Continuous), - causality: causality.unwrap_or(ast::Causality::None), - array_subscripts: array_subscripts.unwrap_or(Vec::new()), - modification, + declaration, + condition_attribute, + description, } } } -// condition-attribute : -// if expression +//✅ condition-attribute : +//✅ if expression pub ConditionAttribute: Box = { "if" => cond } -// declaration : -// IDENT [ array-subscripts ] [ modification ] +//✅ declaration : +//✅ IDENT [ array-subscripts ] [ modification ] pub Declaration: ast::Declaration = { - + => { ast::Declaration { name, - array_subscripts: array_subscripts.unwrap_or(Vec::new()), + array_subscripts, modification, } } } -// A.2.5 Modification (TODO) -// ============================================================================ -// modification : -// class-modification [ "=" modification-expression ] -// | "=" modification-expression -// modification-expression : -// expression -// | break +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// A.2.5 Modification +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// ✅: Implemented, 🟥: Not-Implemented, 🟨: Partial + +//🟨 modification : +//🟥 class-modification [ "=" modification-expression ] +//🟨 | "=" modification-expression pub Modification: ast::Modification = { "=" => ast::Modification { expression } } -// class-modification : -// "(" [ argument-list ] ")" -// argument-list : -// argument { "," argument } - -// argument : -// element-modification-or-replaceable -// | element-redeclaration -// element-modification-or-replaceable : -// [ each ] [ final ] ( element-modification | element-replaceable ) -// element-modification : -// name [ modification ] description-string -// element-redeclaration : -// redeclare [ each ] [ final ] -// ( short-class-definition | component-clause1 | element-replaceable ) -// element-replaceable : -// replaceable ( short-class-definition | component-clause1 ) -// [ constraining-clause ] + +//🟥 modification-expression : +//🟥 expression +//🟥 | break + +//✅ class-modification : +//✅ "(" [ argument-list ] ")" +pub ClassModification: Vec = { + "(" > ")" => args +} + +//✅ argument-list : +//✅ argument { "," argument } +// NOTE: flattend into class-modification above + +//🟨 argument : +//🟨 element-modification-or-replaceable +//🟥 | element-redeclaration pub Argument: ast::Argument = { => { - ast::Argument::Modificaion { + ast::Argument::Modification { name, modification, description, @@ -440,45 +496,83 @@ pub Argument: ast::Argument = { }, } -// component-clause1 : -// type-prefix type-specifier component-declaration1 -// component-declaration1 : -// declaration description -// short-class-definition : -// class-prefixes short-class-specifier +//🟥 element-modification-or-replaceable : +//🟥 [ each ] [ final ] ( element-modification | element-replaceable ) + +//🟨 element-modification : +//🟨 name [ modification ] description-string + +//🟥 element-redeclaration : +//🟥 redeclare [ each ] [ final ] +//🟥 ( short-class-definition | component-clause1 | element-replaceable ) +//🟥 element-replaceable : +//🟥 replaceable ( short-class-definition | component-clause1 ) +//🟥 [ constraining-clause ] + +//✅ component-clause1 : +//✅ type-prefix type-specifier component-declaration1 +pub ComponentClause1: ast::ComponentClause1 = { + + + => { + ast::ComponentClause1 { + type_prefix, + type_specifier, + component_declaration1, + } + } +} + +//✅ component-declaration1 : +//✅ declaration description +pub ComponentDeclaration1: ast::ComponentDeclaration1 = { + + => { + ast::ComponentDeclaration1 { + declaration, + description, + } + } +} + +//🟥 short-class-definition : +//🟥 class-prefixes short-class-specifier + +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // A.2.6 Equations -// ============================================================================ -// equation-section : -// [ initial ] equation { some-equation ";" } -pub EquationSection: ast::Composition = { +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// ✅: Implemented, 🟥: Not-Implemented, 🟨: Partial + +//✅ equation-section : +//✅ [ initial ] equation { some-equation ";" } +pub EquationSection: ast::CompositionPart = { "equation" > => { - ast::Composition::EquationSection { + ast::CompositionPart::EquationSection { initial: initial.is_some(), equations, } } } -// algorithm-section : -// [ initial ] algorithm { statement ";" } -pub AlgorithmSection: ast::Composition = { +//✅ algorithm-section : +//✅ [ initial ] algorithm { statement ";" } +pub AlgorithmSection: ast::CompositionPart = { "algorithm" > => { - ast::Composition::AlgorithmSection { + ast::CompositionPart::AlgorithmSection { initial: initial.is_some(), statements, } } } -// some-equation : -// ( simple-expression "=" expression -// | if-equation -// | for-equation -// | connect-equation -// | when-equation -// | component-reference function-call-args -// ) -// description +//🟥 some-equation : +//✅ ( simple-expression "=" expression +//✅ | if-equation +//🟥 | for-equation +//🟥 | connect-equation +//🟥 | when-equation +//🟥 | component-reference function-call-args ) +//🟥 description pub Equation: ast::Equation = { "=" => { ast::Equation::Simple { @@ -495,18 +589,16 @@ pub Equation: ast::Equation = { => eq, } -// statement : -// ( component-reference ( ":=" expression | function-call-args ) -// | "(" output-expression-list ")" ":=" -// component-reference function-call-args -// | break -// | return -// | if-statement -// | for-statement -// | while-statement -// | when-statement -// ) -// description +//✅ statement : +//✅ ( component-reference ( ":=" expression | function-call-args ) +//🟥 | "(" output-expression-list ")" ":=" component-reference function-call-args +//🟥 | break +//🟥 | return +//🟥 | if-statement +//🟥 | for-statement +//🟥 | while-statement +//🟥 | when-statement ) +//🟥 description pub Statement: ast::Statement = { ":=" => { @@ -518,16 +610,16 @@ pub Statement: ast::Statement = { => stmt, } -// if-equation : -// if expression then -// { some-equation ";" } -// { elseif expression then -// { some-equation ";" } -// } -// [ else -// { some-equation ";" } -// ] -// end if +//✅ if-equation : +//✅ if expression then +//✅ { some-equation ";" } +//✅ { elseif expression then +//✅ { some-equation ";" } +//✅ } +//✅ [ else +//✅ { some-equation ";" } +//✅ ] +//✅ end if pub IfEquation: ast::Equation = { "if" "then" @@ -559,16 +651,16 @@ pub ElseEquationBlock: Vec = { } } -// if-statement : -// if expression then -// { statement ";" } -// { elseif expression then -// { statement ";" } -// } -// [ else -// { statement ";" } -// ] -// end if +//✅ if-statement : +//✅ if expression then +//✅ { statement ";" } +//✅ { elseif expression then +//✅ { statement ";" } +//✅ } +//✅ [ else +//✅ { statement ";" } +//✅ ] +//✅ end if pub IfStatement: ast::Statement = { "if" "then" > @@ -598,57 +690,54 @@ pub ElseStatementBlock: Vec = { } } -// for-equation : -// for for-indices loop -// { some-equation ";" } -// end for -// for-statement : -// for for-indices loop -// { statement ";" } -// end for -// for-indices : -// for-index { "," for-index } -// for-index : -// IDENT [ in expression ] -// while-statement : -// while expression loop -// { statement ";" } -// end while -// when-equation : -// when expression then -// { some-equation ";" } -// { elsewhen expression then -// { some-equation ";" } -// } -// end when -// when-statement : -// when expression then -// { statement ";" } -// { elsewhen expression then -// { statement ";" } -// } -// end when -// connect-equation : -// connect "(" component-reference "," component-reference ")" - +//🟥 for-equation : +//🟥 for for-indices loop +//🟥 { some-equation ";" } +//🟥 end for +//🟥 for-statement : +//🟥 for for-indices loop +//🟥 { statement ";" } +//🟥 end for +//🟥 for-indices : +//🟥 for-index { "," for-index } +//🟥 for-index : +//🟥 IDENT [ in expression ] +//🟥 while-statement : +//🟥 while expression loop +//🟥 { statement ";" } +//🟥 end while +//🟥 when-equation : +//🟥 when expression then +//🟥 { some-equation ";" } +//🟥 { elsewhen expression then +//🟥 { some-equation ";" } +//🟥 } +//🟥 end when +//🟥 when-statement : +//🟥 when expression then +//🟥 { statement ";" } +//🟥 { elsewhen expression then +//🟥 { statement ";" } +//🟥 } +//🟥 end when +//🟥 connect-equation : +//🟥 connect "(" component-reference "," component-reference ")" +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // A.2.7 Expressions -// ============================================================================ -// expression : -// simple-expression -// | if expression then expression -// { elseif expression then expression } -// else expression -// simple-expression : -// logical-expression [ ":" logical-expression [ ":" logical-expression ] ] +// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +// ✅: Implemented, 🟥: Not-Implemented, 🟨: Partial + +//🟨 expression : +//✅ simple-expression +//🟥 | if expression then expression +//🟥 { elseif expression then expression } +//🟥 else expression +//✅ simple-expression : +//✅ logical-expression [ ":" logical-expression [ ":" logical-expression ] ] pub Expression: Box = { -// expression : -// simple-expression -// | if expression then expression -// { elseif expression then expression } -// else expression => { simp }, @@ -681,8 +770,8 @@ pub ElseExpressionBlock: Box = { pub ParenthesisExpression = SimpleExpression; pub SimpleExpression: Box = { -// simple-expression : -// logical-expression [ ":" logical-expression [ ":" logical-expression ] ] +//✅ simple-expression : +//✅ logical-expression [ ":" logical-expression [ ":" logical-expression ] ] #[precedence(level="11")] #[assoc(side="left")] ":" => { Box::new(ast::Expression::Range { @@ -690,8 +779,8 @@ pub SimpleExpression: Box = { rhs, }) }, -// logical-expression : -// logical-term { or logical-term } +//✅ logical-expression : +//✅ logical-term { or logical-term } #[precedence(level="10")] #[assoc(side="left")] "or" => { Box::new(ast::Expression::Or { @@ -699,8 +788,8 @@ pub SimpleExpression: Box = { rhs }) }, -// logical-term : -// logical-factor { and logical-factor } +//✅ logical-term : +//✅ logical-factor { and logical-factor } #[precedence(level="9")] #[assoc(side="left")] "and" => { Box::new(ast::Expression::And { @@ -708,18 +797,18 @@ pub SimpleExpression: Box = { rhs }) }, -// logical-factor : -// [ not ] relation +//✅ logical-factor : +//✅ [ not ] relation #[precedence(level="8")] "not" => { Box::new(ast::Expression::Not { rhs }) }, -// relation : -// arithmetic-expression [ relational-operator arithmetic-expression ] -// relational-operator : -// "<" | "<=" | ">" | ">=" | "==" | "<>" +//✅ relation : +//✅ arithmetic-expression [ relational-operator arithmetic-expression ] +//✅ relational-operator : +//✅ "<" | "<=" | ">" | ">=" | "==" | "<>" #[precedence(level="7")] #[assoc(side="left")] "<" => { Box::new(ast::Expression::LessThan { @@ -763,10 +852,10 @@ pub SimpleExpression: Box = { rhs }) }, -// arithmetic-expression : -// [ add-operator ] term { add-operator term } -// add-operator : -// "+" | "-" | ".+" | ".-" +//✅ arithmetic-expression : +//✅ [ add-operator ] term { add-operator term } +//✅ add-operator : +//✅ "+" | "-" | ".+" | ".-" #[precedence(level="5")] #[assoc(side="left")] "+" => { Box::new(ast::Expression::Add { @@ -792,10 +881,10 @@ pub SimpleExpression: Box = { rhs }) }, -// term : -// factor { mul-operator factor } -// mul-operator : -// "*" | "/" | ".*" | "./" +//✅ term : +//✅ factor { mul-operator factor } +//✅ mul-operator : +//✅ "*" | "/" | ".*" | "./" #[precedence(level="4")] #[assoc(side="left")] "*" => { Box::new(ast::Expression::Mul { @@ -821,8 +910,8 @@ pub SimpleExpression: Box = { rhs }) }, -// factor : -// primary [ ( "^" | ".^" ) primary ] +//✅ factor : +//✅ primary [ ( "^" | ".^" ) primary ] #[precedence(level="3")] #[assoc(side="left")] "^" => { Box::new(ast::Expression::Exp { @@ -836,17 +925,17 @@ pub SimpleExpression: Box = { rhs }) }, -// primary : -// UNSIGNED-NUMBER -// | STRING -// | false -// | true -// | ( component-reference | der | initial | pure ) function-call-args -// | component-reference -// | "(" output-expression-list ")" [ ( array-subscripts | "." IDENT ) ] -// | "[" expression-list { ";" expression-list } "]" -// | "{" array-arguments "}" -// | end +//✅ primary : +//✅ UNSIGNED-NUMBER +//🟥 | STRING +//✅ | false +//✅ | true +//🟨 | ( component-reference | der | initial | pure ) function-call-args +//✅ | component-reference +//🟥 | "(" output-expression-list ")" [ ( array-subscripts | "." IDENT ) ] +//🟥 | "[" expression-list { ";" expression-list } "]" +//🟥 | "{" array-arguments "}" +//🟥 | end #[precedence(level="0")] "(" ")" => { Box::new(ast::Expression::Parenthesis { @@ -858,10 +947,10 @@ pub SimpleExpression: Box = { args }) }, - => { + => { Box::new(ast::Expression::UnsignedInteger(val)) }, - => { + => { Box::new(ast::Expression::UnsignedReal(val)) }, => { @@ -878,10 +967,12 @@ pub SimpleExpression: Box = { }, } -// UNSIGNED-NUMBER : -// UNSIGNED-INTEGER | UNSIGNED-REAL -// type-specifier : -// ["."] name +//✅ UNSIGNED-NUMBER : +//✅ UNSIGNED-INTEGER | UNSIGNED-REAL +// NOTE: flattened in primary + +//✅ type-specifier : +//✅ ["."] name pub TypeSpecifier: ast::TypeSpecifier = { => { ast::TypeSpecifier{ @@ -890,75 +981,123 @@ pub TypeSpecifier: ast::TypeSpecifier = { } }, } -// name : -// IDENT { "." IDENT } +//✅ name : +//✅ IDENT { "." IDENT } pub Name: ast::Name = { - > => { - ast::Name{ - ident + )*> => { + let mut v = vec![first]; + v.extend(remaining); + ast::Name { + ident: v } - }, + } } -// component-reference : -// [ "." ] IDENT [ array-subscripts ] { "." IDENT [ array-subscripts ] } + + +//✅ component-reference : +//✅ [ "." ] IDENT [ array-subscripts ] { "." IDENT [ array-subscripts ] } pub ComponentReference: ast::ComponentReference = { - => { + => { ast::ComponentReference{ + local: local.is_some(), + parts, + } + }, +} +pub RefPart: ast::RefPart = { + => { + ast::RefPart { name, array_subscripts: array_subscripts.unwrap_or(Vec::new()), } - }, + } } -// result-reference : -// component-reference -// | der "(" component-reference [ "," UNSIGNED-INTEGER ] ")" -// function-call-args : -// "(" [ function-arguments ] ")" -// function-arguments : -// expression [ "," function-arguments-non-first | for for-indices ] -// | function-partial-application [ "," function-arguments-non-first ] -// | named-arguments -// function-arguments-non-first : -// function-argument [ "," function-arguments-non-first ] -// | named-arguments + +//🟥 result-reference : +//🟥 component-reference +//🟥 | der "(" component-reference [ "," UNSIGNED-INTEGER ] ")" + +//✅ function-call-args : +//✅ "(" [ function-arguments ] ")" pub FunctionCallArguments: Vec> = { "(" > ")" => args, } -// array-arguments : -// expression [ "," array-arguments-non-first | for for-indices ] -// array-arguments-non-first : -// expression [ "," array-arguments-non-first ] -// named-arguments: named-argument [ "," named-arguments ] -// named-argument: IDENT "=" function-argument -// function-argument : -// function-partial-application | expression -// function-partial-application : -// function type-specifier "(" [ named-arguments ] ")" -// output-expression-list : -// [ expression ] { "," [ expression ] } -// expression-list : -// expression { "," expression } -// array-subscripts : -// "[" subscript { "," subscript } "]" + +//🟥 function-arguments : +//🟥 expression [ "," function-arguments-non-first | for for-indices ] +//🟥 | function-partial-application [ "," function-arguments-non-first ] +//🟥 | named-arguments + +//🟥 function-arguments-non-first : +//🟥 function-argument [ "," function-arguments-non-first ] +//🟥 | named-arguments + +//🟥 array-arguments : +//🟥 expression [ "," array-arguments-non-first | for for-indices ] + +//🟥 array-arguments-non-first : +//🟥 expression [ "," array-arguments-non-first ] + +//🟥 named-arguments: named-argument [ "," named-arguments ] + +//🟥 named-argument: IDENT "=" function-argument + +//🟥 function-argument : +//🟥 function-partial-application | expression + +//🟥 function-partial-application : +//🟥 function type-specifier "(" [ named-arguments ] ")" + +//🟥 output-expression-list : +//🟥 [ expression ] { "," [ expression ] } + +//🟥 expression-list : +//🟥 expression { "," expression } + +//✅ array-subscripts : +//✅ "[" subscript { "," subscript } "]" pub ArraySubscripts: Vec = { "[" > "]" => { subscripts }, } -// subscript : -// ":" | expression +//✅ subscript : +//✅ ":" | expression pub Subscript: ast::Subscript = { ":" => ast::Subscript::Colon, => ast::Subscript::Expression(expr), } -// description : -// description-string [ annotation-clause ] -// description-string : -// [ STRING { "+" STRING } ] -pub Description: String = { - => { - description + +//✅ description : +//✅ description-string [ annotation-clause ] +pub Description: ast::Description = { + + + => { + ast::Description { + strings: strings.unwrap_or(Vec::new()), + annotation: annotation.unwrap_or(Vec::new()), + } }, } -// annotation-clause : -// annotation class-modification \ No newline at end of file + +//✅ description-string : +//✅ [ STRING { "+" STRING } ] +// Note: LALRPOP doesn't like empty expressions, so effectively +// removing outer [ ], and at least one string is required. +// Other expressions will need to treat as option. +pub DescriptionString: Vec = { + )*> => { + let mut v = vec![first]; + v.extend(remaining); + v + } +} + +//✅ annotation-clause : +//✅ annotation class-modification +pub AnnotationClause: Vec = { + "annotation" => { + modification + }, +} \ No newline at end of file diff --git a/src/s2_analyzer/ast.rs b/src/s2_analyzer/ast.rs index ec79d16..b9cfd73 100644 --- a/src/s2_analyzer/ast.rs +++ b/src/s2_analyzer/ast.rs @@ -16,7 +16,7 @@ pub struct Def { pub struct Class { pub name: String, pub class_type: ClassType, - pub description: String, + pub description: Vec, pub components: OrderMap, // dictinoary of components pub c: OrderSet, // constants pub x: OrderSet, // continuous states diff --git a/src/s2_analyzer/flattener.rs b/src/s2_analyzer/flattener.rs index 8049f18..9e9c892 100644 --- a/src/s2_analyzer/flattener.rs +++ b/src/s2_analyzer/flattener.rs @@ -1,4 +1,4 @@ -use crate::s1_parser::ast as parse_ast; +use crate::s1_parser::ast::{self as parse_ast, Statement, Expression, Subscript}; use crate::s2_analyzer::ast; use ndarray::{ArrayBase, ArrayD, IxDyn, OwnedRepr}; use std::collections::HashMap; @@ -6,38 +6,38 @@ use std::error::Error; pub fn evaluate( class: &ast::Class, - expr: &parse_ast::Expression, + expr: &Expression, ) -> Result, IxDyn>, Box> { match expr { - parse_ast::Expression::Add { lhs, rhs } => { + Expression::Add { lhs, rhs } => { Ok(evaluate(class, lhs)? + evaluate(class, rhs)?) } - parse_ast::Expression::Sub { lhs, rhs } => { + Expression::Sub { lhs, rhs } => { Ok(evaluate(class, lhs)? - evaluate(class, rhs)?) } - parse_ast::Expression::Mul { lhs, rhs } => { + Expression::Mul { lhs, rhs } => { // matrix multiplication let a = evaluate(class, lhs)?; let b = evaluate(class, rhs)?; let res = a * b; Ok(res) } - parse_ast::Expression::Div { lhs, rhs } => { + Expression::Div { lhs, rhs } => { Ok(evaluate(class, lhs)? / evaluate(class, rhs)?) } - parse_ast::Expression::ElemAdd { lhs, rhs } => { + Expression::ElemAdd { lhs, rhs } => { Ok(evaluate(class, lhs)? + evaluate(class, rhs)?) } - parse_ast::Expression::ElemSub { lhs, rhs } => { + Expression::ElemSub { lhs, rhs } => { Ok(evaluate(class, lhs)? - evaluate(class, rhs)?) } - parse_ast::Expression::ElemMul { lhs, rhs } => { + Expression::ElemMul { lhs, rhs } => { Ok(evaluate(class, lhs)? * evaluate(class, rhs)?) } - parse_ast::Expression::ElemDiv { lhs, rhs } => { + Expression::ElemDiv { lhs, rhs } => { Ok(evaluate(class, lhs)? / evaluate(class, rhs)?) } - parse_ast::Expression::Exp { lhs, rhs } => { + Expression::Exp { lhs, rhs } => { let base = evaluate(class, lhs)?; let exp = evaluate(class, rhs)?; if base.shape() != [1] { @@ -50,24 +50,26 @@ pub fn evaluate( let values = vec![base[0].powf(exp[0])]; Ok(ArrayD::from_shape_vec(shape, values).unwrap()) } - parse_ast::Expression::Parenthesis { rhs } => Ok(evaluate(class, rhs)?), - parse_ast::Expression::UnsignedReal(v) => { + Expression::Parenthesis { rhs } => Ok(evaluate(class, rhs)?), + Expression::UnsignedReal(v) => { let shape = IxDyn(&[1]); let values = vec![*v]; Ok(ArrayD::from_shape_vec(shape, values).unwrap()) } - parse_ast::Expression::UnsignedInteger(v) => { + Expression::UnsignedInteger(v) => { let shape = IxDyn(&[1]); let values = vec![*v as f64]; Ok(ArrayD::from_shape_vec(shape, values).unwrap()) } - parse_ast::Expression::Ref { comp } => match &class.components[&comp.name].start { - Some(m) => Ok(evaluate(class, &m.expression)?), - None => { - panic!("no start value defined for {:?}", comp); + Expression::Ref { comp } => { + match &class.components[&compref_to_string(comp)].start { + Some(m) => Ok(evaluate(class, &m.expression)?), + None => { + panic!("no start value defined for {:?}", comp); + } } - }, - parse_ast::Expression::ArrayArguments { args } => { + } + Expression::ArrayArguments { args } => { let shape = IxDyn(&[args.len()]); let mut values = Vec::new(); for arg in args { @@ -79,7 +81,7 @@ pub fn evaluate( } Ok(ArrayD::from_shape_vec(shape, values).unwrap()) } - parse_ast::Expression::Negative { rhs } => Ok(-evaluate(class, rhs)?), + Expression::Negative { rhs } => Ok(-evaluate(class, rhs)?), _ => { todo!("{:?}", expr) } @@ -135,29 +137,29 @@ pub fn set_start_expressions( pub fn flatten_class(class: &parse_ast::ClassDefinition, def: &mut ast::Def) { let mut fclass = ast::Class { - name: class.name.clone(), - class_type: class.class_type.clone(), - description: class.description.clone(), + name: class.class_specifier.name.clone(), + class_type: class.class_prefixes.class_type.clone(), + description: class.class_specifier.description.clone(), ..Default::default() }; - for composition in &class.compositions { - flatten_composition(composition, &mut fclass) + for composition_part in &class.class_specifier.composition { + flatten_composition_part(composition_part, &mut fclass) } def.classes.insert(fclass.name.to_string(), fclass.clone()); } -pub fn flatten_composition(composition: &parse_ast::Composition, class: &mut ast::Class) { +pub fn flatten_composition_part(composition: &parse_ast::CompositionPart, class: &mut ast::Class) { match composition { - parse_ast::Composition::ElementList { + parse_ast::CompositionPart::ElementList { visibility: _, elements, } => { - for comp in elements { - flatten_component(comp, class); + for elem in elements { + flatten_element(elem, class); } } - parse_ast::Composition::EquationSection { + parse_ast::CompositionPart::EquationSection { initial: _, equations, } => { @@ -165,7 +167,7 @@ pub fn flatten_composition(composition: &parse_ast::Composition, class: &mut ast flatten_equation(eq, class); } } - parse_ast::Composition::AlgorithmSection { + parse_ast::CompositionPart::AlgorithmSection { initial: _, statements, } => { @@ -176,40 +178,80 @@ pub fn flatten_composition(composition: &parse_ast::Composition, class: &mut ast } } -pub fn flatten_component(comp: &parse_ast::ComponentDeclaration, class: &mut ast::Class) { - let flat_comp = ast::Component { - name: comp.name.clone(), - start: comp.modification.clone(), - start_value: ArrayD::zeros(vec![1, 1]), - array_subscripts: comp.array_subscripts.clone(), - }; +pub fn flatten_element(elem: &parse_ast::Element, class: &mut ast::Class) { + match &elem { + &parse_ast::Element::ComponentClause { + type_prefix, + type_specifier: _, + array_subscripts, + components, + } => { + for comp in 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 { + Some(clause_sub) => { + // take array subscripts from clause + clause_sub.clone() + } + None => { + // scalar, no subscripts + Vec::::new() + } + }, + }; - class - .components - .insert(flat_comp.name.clone(), flat_comp.clone()); + let flat_comp = ast::Component { + name: comp.declaration.name.clone(), + start: comp.declaration.modification.clone(), + start_value: ArrayD::zeros(vec![1, 1]), + array_subscripts: comp_sub, + }; - match comp.variability { - parse_ast::Variability::Constant => { - class.c.insert(flat_comp.name.to_string()); - } - parse_ast::Variability::Continuous => match comp.causality { - parse_ast::Causality::Input => { - class.u.insert(flat_comp.name.to_string()); - } - parse_ast::Causality::Output => { - class.y.insert(flat_comp.name.to_string()); - } - parse_ast::Causality::None => { - class.w.insert(flat_comp.name.to_string()); + class + .components + .insert(flat_comp.name.clone(), flat_comp.clone()); + + match type_prefix.variability { + parse_ast::Variability::Constant => { + class.c.insert(flat_comp.name.to_string()); + } + parse_ast::Variability::Continuous => match type_prefix.causality { + parse_ast::Causality::Input => { + class.u.insert(flat_comp.name.to_string()); + } + parse_ast::Causality::Output => { + class.y.insert(flat_comp.name.to_string()); + } + parse_ast::Causality::None => { + class.w.insert(flat_comp.name.to_string()); + } + }, + parse_ast::Variability::Discrete => { + class.z.insert(flat_comp.name.to_string()); + } + parse_ast::Variability::Parameter => { + class.p.insert(flat_comp.name.to_string()); + } + } } - }, - parse_ast::Variability::Discrete => { - class.z.insert(flat_comp.name.to_string()); } - parse_ast::Variability::Parameter => { - class.p.insert(flat_comp.name.to_string()); + } +} + +pub fn compref_to_string(comp: &parse_ast::ComponentReference) -> String { + let mut s: String = "".to_string(); + for (index, part) in comp.parts.iter().enumerate() { + if index != 0 || comp.local { + s += "."; } + s += &part.name; } + s } pub fn flatten_equation(eq: &parse_ast::Equation, class: &mut ast::Class) { @@ -217,14 +259,15 @@ pub fn flatten_equation(eq: &parse_ast::Equation, class: &mut ast::Class) { // for component references that are taken the derivative of match eq { parse_ast::Equation::Der { comp, rhs } => { - if class.w.contains(&comp.name) { - class.x.insert(class.w.remove_full(&comp.name).unwrap().1); - } else if class.y.contains(&comp.name) { - class.x.insert(comp.name.clone()); + let comp_key = compref_to_string(comp); + if class.w.contains(&comp_key) { + class.x.insert(class.w.remove_full(&comp_key).unwrap().1); + } else if class.y.contains(&comp_key) { + class.x.insert(comp_key.clone()); } else { - panic!("derivative state not declared {:?}", comp.name); + panic!("derivative state not declared {:?}", comp_key); } - class.ode.insert(comp.name.clone(), rhs.clone()); + class.ode.insert(comp_key.clone(), rhs.clone()); } parse_ast::Equation::Simple { lhs: _, rhs: _ } => { class.algebraic.push(eq.clone()); @@ -235,9 +278,18 @@ pub fn flatten_equation(eq: &parse_ast::Equation, class: &mut ast::Class) { else_if_blocks: _, else_eqs: _, } => { - class.algebraic.push(eq.clone()); + todo!("{:?}", eq); } } } -pub fn flatten_statement(_stmt: &parse_ast::Statement, _class: &mut ast::Class) {} +pub fn flatten_statement(stmt: &parse_ast::Statement, class: &mut ast::Class) { + match &stmt { + Statement::Assignment { comp: _, rhs: _ } => { + class.algorithm.push(stmt.clone()); + } + Statement::If { if_cond: _, if_eqs: _, else_if_blocks: _, else_eqs: _ } => { + todo!("{:?}", stmt); + } + } +} diff --git a/test/models/quadrotor.mo b/test/models/quadrotor.mo index 0ba10db..2308820 100644 --- a/test/models/quadrotor.mo +++ b/test/models/quadrotor.mo @@ -53,29 +53,29 @@ equation CT * omega_motor[3]^2, CT * omega_motor[4]^2}; - if (omega_motor_cmd[1] > omega_motor[1]) then - tau_inv[1] = 1.0/tau_up; - else - tau_inv[1] = 1.0/tau_down; - end if; + // if (omega_motor_cmd[1] > omega_motor[1]) then + // tau_inv[1] = 1.0/tau_up; + // else + // tau_inv[1] = 1.0/tau_down; + // end if; - if (omega_motor_cmd[2] > omega_motor[2]) then - tau_inv[2] = 1.0/tau_up; - else - tau_inv[2] = 1.0/tau_down; - end if; + // if (omega_motor_cmd[2] > omega_motor[2]) then + // tau_inv[2] = 1.0/tau_up; + // else + // tau_inv[2] = 1.0/tau_down; + // end if; - if (omega_motor_cmd[3] > omega_motor[3]) then - tau_inv[3] = 1.0/tau_up; - else - tau_inv[3] = 1.0/tau_down; - end if; + // if (omega_motor_cmd[3] > omega_motor[3]) then + // tau_inv[3] = 1.0/tau_up; + // else + // tau_inv[3] = 1.0/tau_down; + // end if; - if (omega_motor_cmd[4] > omega_motor[4]) then - tau_inv[4] = 1.0/tau_up; - else - tau_inv[4] = 1.0/tau_down; - end if; + // if (omega_motor_cmd[4] > omega_motor[4]) then + // tau_inv[4] = 1.0/tau_up; + // else + // tau_inv[4] = 1.0/tau_down; + // end if; // state derivative der(position_op_w) = {0, 0, 0}; //QuatToMatrix(quaternion_wb) * velocity_w_p_b; diff --git a/test/templates/casadi_sx.jinja b/test/templates/casadi_sx.jinja index cbd9f2b..ecb4400 100644 --- a/test/templates/casadi_sx.jinja +++ b/test/templates/casadi_sx.jinja @@ -1,5 +1,10 @@ -{%- macro render_class_model(class) %} -class {{ class.name }}(BaseModel): +{%- macro render_class(class) %} + {%- if class.class_type == "Model" -%} + {%- elif class.class_type == "Function" -%} + {%- else -%} + {{ panic("unhandled class type: " + class.class_type) }} + {%- endif -%} +class {% if class.class_type == "Function" -%}__{% endif -%}{{ class.name }}(BaseModel): """ {{ class.description }} """ @@ -36,7 +41,7 @@ class {{ class.name }}(BaseModel): {{ render_vector("self.y", class, class.y) | indent(12) }} # declare internal variables - {{ render_symbols(class.w) | indent(4) }} + {{ render_symbols(class, class.w) | indent(4) }} # declare continuous states {{ render_symbols(class, class.x) | indent(4) }} @@ -45,41 +50,16 @@ class {{ class.name }}(BaseModel): # declare continuous states start values {{ render_vector_start_dict("self.x0", class, class.x) | indent(4) }} - # alg - {{ render_statement_list(class.alg) | indent(4) }} + # algorithmic + {{ render_statement_list(class.algorithm) | indent(4) }} + + # algebraic + {{ render_statement_list(class.algebric) | indent(4) }} # ode {{ render_ordermap_expression("self.ode", class.ode, class.x) | indent(8) }} -{%- endmacro %} - -{%- macro render_class_function(class) %} -class __{{ class.name }}(BaseModel): - """ - {{ class.description }} - """ - - def __init__(self): - super().__init__() - - # declare constants - {%- for var in class.c %} - {{ key }} = {{ render_expression(expr=val.start) }} - {%- endfor %} - - # declare inputs - {{ render_symbols(class.u) | indent(4) }} - {{ render_vector("self.u", class.u) | indent(4) }} - - # declare internal variables - {{ render_symbols(class.w) | indent(4) }} - - # declare outputs - {{ render_zero_symbols(class.y) | indent(4) }} - - # alg - {{ render_statement_list(class.alg) | indent(4) }} - +{% if class.class_type == "Function" %} # build function {{ render_vector("self.y", class.y) | indent(4) }} self.F = ca.Function("{{ class.name }}", [self.u], [self.y], ['u'], ['y']) @@ -87,18 +67,9 @@ class __{{ class.name }}(BaseModel): def __call__(self, *args): return self.F(ca.vertcat(*args)) - {{ class.name }} = __{{ class .name }}() -{%- endmacro %} -{%- macro render_class(class) %} - {% if class.class_type == "Model" %} - {{ render_class_model(class) }} - {% elif class.class_type == "Function" %} - {{ render_class_function(class) }} - {% else %} - {{ warn("unhandled class type: " + class.class_type) }} - {% endif %} +{% endif %} {%- endmacro %} {%- macro render_symbols(class, var_list) -%} @@ -176,13 +147,16 @@ class __{{ class.name }}(BaseModel): {%- endmacro -%} {%- macro render_component_reference(comp) -%} - {{ comp.name }} - {%- if comp.array_subscripts | length > 0 %}[ - {%- for sub in comp.array_subscripts -%} - {#- handles index from 1 to 0 from Modelica to python-#} - {{ render_subscript(sub) | int -1 }} - {%- endfor -%}] - {%- endif -%} + {%- if comp.local %}.{% endif -%} + {%- for part in comp.parts -%} + {{ part.name }} + {%- if part.array_subscripts | length > 0 %}[ + {%- for sub in part.array_subscripts -%} + {#- handles index from 1 to 0 from Modelica to python-#} + {{ render_subscript(sub) | int -1 }}{% if not loop.last -%}, {% endif %} + {%- endfor -%}] + {%- endif -%} + {%- endfor -%} {%- endmacro -%} {%- macro render_expression(expr) -%} @@ -259,6 +233,7 @@ class __{{ class.name }}(BaseModel): import casadi as ca import numpy as np + class BaseModel: def __init__(self): @@ -295,9 +270,12 @@ class BaseModel: D = ca.jacobian(self.y, self.u) return (A, B, C, D) + def cat(axis, *args): return ca.vertcat(*args) + {%- for key, val in def.classes | items %} + {{ render_class(class=val) }} {%- endfor %}