diff options
-rw-r--r-- | modelica-parser-lalrpop/examples/modelica_models/heat_tank.mo | 28 | ||||
-rw-r--r-- | modelica-parser-lalrpop/src/ast.rs | 16 | ||||
-rw-r--r-- | modelica-parser-lalrpop/src/parser.lalrpop | 69 |
3 files changed, 74 insertions, 39 deletions
diff --git a/modelica-parser-lalrpop/examples/modelica_models/heat_tank.mo b/modelica-parser-lalrpop/examples/modelica_models/heat_tank.mo index dde1ae0..320c3f5 100644 --- a/modelica-parser-lalrpop/examples/modelica_models/heat_tank.mo +++ b/modelica-parser-lalrpop/examples/modelica_models/heat_tank.mo @@ -1,17 +1,17 @@ model HeatTankT - parameter Area=1; - connector TankStream - Real pressure; - flow Real volumeFlowRate; - Real temp; - end TankStream; - TankStream Inlet, Outlet; - Real level; - Real temp; + parameter Real Area=1; + connector TankStream + Real pressure; + flow Real volumeFlowRate; + Real temp; + end TankStream; + TankStream Inlet, Outlet; + Real level; + Real temp; equation - Area*der(level) = Inlet.volumeFlowRate + Outlet.volumeFlowRate; - Outlet.pressure = Inlet.pressure; -Area*level*der(temp) = Inlet.volumeFlowRate*Inlet.temp + - Outlet.volumeFlowRate*Outlet.temp; -Outlet.temp = temp; + Area*der(level) = Inlet.volumeFlowRate + Outlet.volumeFlowRate; + Outlet.pressure = Inlet.pressure; + Area*level*der(temp) = Inlet.volumeFlowRate*Inlet.temp + + Outlet.volumeFlowRate*Outlet.temp; + Outlet.temp = temp; end HeatTankT; diff --git a/modelica-parser-lalrpop/src/ast.rs b/modelica-parser-lalrpop/src/ast.rs index addb90f..e367b10 100644 --- a/modelica-parser-lalrpop/src/ast.rs +++ b/modelica-parser-lalrpop/src/ast.rs @@ -7,7 +7,7 @@ use std::collections::HashMap; // A valid .mo file will be a sequence of these #[derive(Clone, PartialEq)] pub enum ModelicaCode { - Class, // unimpl + Class, // unimpl; generic Model(ModelicaModel), Record, // unimpl Block(ModelicaBlock), @@ -39,8 +39,8 @@ pub struct ModelicaBlock { pub name: String, pub description: Option<String>, pub component_clauses: Vec<ComponentClause>, - pub public_component_clauses: Option<Vec<ComponentClause>>, - pub protected_component_clauses: Option<Vec<ComponentClause>>, + pub public_component_clauses: Vec<ComponentClause>, + pub protected_component_clauses: Vec<ComponentClause>, pub equations: Vec<SimpleEquation>, pub connections: Vec<Connection>, pub extends: Vec<String>, @@ -88,7 +88,7 @@ pub struct ComponentDeclaration { pub dimensions: Option<Vec<i64>>, pub value: Option<Expr>, pub quantity: Option<String>, - pub units: Option<String>, + pub mods: HashMap<String, Expr>, pub description: Option<String>, } @@ -99,7 +99,7 @@ pub struct Component { pub specifier: String, pub name: String, pub value: Option<Expr>, - pub units: Option<String>, + pub mods: HashMap<String, Expr>, pub description: Option<String>, } @@ -120,6 +120,7 @@ pub enum Expr { Integer(i64), Float(f64), Boolean(bool), + StringLiteral(String), Ident(String), Der(Box<Expr>), Sign(Box<Expr>), @@ -172,7 +173,7 @@ impl ModelicaModel { specifier: clause.specifier.clone(), name: dec.name.clone(), value: dec.value.clone(), - units: dec.units.clone(), + mods: dec.mods.clone(), description: dec.description.clone(), })) } @@ -237,7 +238,7 @@ impl Expr { pub fn identifiers(&self) -> Vec<String> { use self::Expr::*; match *self { - Integer(_) | Float(_) | Boolean(_) => vec![], + Integer(_) | Float(_) | Boolean(_) | StringLiteral(_) => vec![], Ident(ref s) => vec![s.clone()], Der(ref e) | Sign(ref e) => e.identifiers(), MathUnaryExpr(_, ref e) => e.identifiers(), @@ -342,6 +343,7 @@ impl Debug for Expr { Integer(e) => write!(fmt, "{}", e), Float(e) => write!(fmt, "{}", e), Boolean(e) => write!(fmt, "{}", e), + StringLiteral(ref e) => write!(fmt, "\"{}\"", e), Ident(ref e) => write!(fmt, "{}", e), Der(ref e) => write!(fmt, "der({:?})", e), Sign(ref e) => write!(fmt, "sign({:?})", e), diff --git a/modelica-parser-lalrpop/src/parser.lalrpop b/modelica-parser-lalrpop/src/parser.lalrpop index 447c51f..b05ad76 100644 --- a/modelica-parser-lalrpop/src/parser.lalrpop +++ b/modelica-parser-lalrpop/src/parser.lalrpop @@ -1,4 +1,5 @@ use std::str::FromStr; +use std::collections::HashMap; use ast::{ModelicaCode, ModelicaPackage, ModelicaBlock, ModelicaConnector, ModelicaType, ModelicaModel, ComponentDeclaration, ComponentClause, ComponentPrefix, Connection, SimpleEquation, Expr, BinOperator, MathUnaryFunc}; @@ -6,18 +7,20 @@ use ast::{ModelicaCode, ModelicaPackage, ModelicaBlock, ModelicaConnector, Model // This is an incomplete, non-standards-compliant, minimum-viable parser // Based on the Modelica 3.3r1 Spec + grammar; + // === Lexical Tokens === // Roughly (but possibly not exactly) follows B.1 pub identifier: String = { r"[a-zA-Z_][a-zA-Z_0-9]*" => <>.to_string(), + r"[a-zA-Z_][a-zA-Z_0-9]*\.[a-zA-Z_0-9]*" => <>.to_string(), }; string_literal: String = { r#""[^"\\]*""# => <>.to_string(), - //<s:r#""[^"\\]*""#> => &s[1..s.len()-1], }; pub integer: i64 = { @@ -71,7 +74,7 @@ pub connector: ModelicaConnector = { component_clauses:cpc, }, }; -pub type_declaration: ModelicaType = { +type_declaration: ModelicaType = { "type" <n:identifier> <desc:string_literal?> "=" <cpd:component_declaration> ";" => ModelicaType { @@ -93,16 +96,17 @@ pub block: ModelicaBlock = { name:n, description:desc, component_clauses:cpc, - public_component_clauses:public, - protected_component_clauses:protected, + public_component_clauses: { public.unwrap_or(vec![]) }, + protected_component_clauses: { protected.unwrap_or(vec![]) }, connections:cc, equations:se, extends:vec![] }, }; pub model: ModelicaModel = { - "model" <n:identifier> <desc:string_literal?> + "partial"? "model" <n:identifier> <desc:string_literal?> <cpc:component_clause*> + connector* "equation" <cc:connect_clause*> <se:simple_equation*> @@ -116,24 +120,21 @@ pub model: ModelicaModel = { extends:vec![] }, }; -value_declaration: Expr = { - "=" <value:expr> => value -}; - -units_declaration: String = { - "(" "unit" "=" <units:string_literal> ")" => units -}; - component_clause: ComponentClause = { - <prefix:component_prefix?> <specifier:identifier> <declarations:component_declaration+> ";" => - ComponentClause { prefix:prefix, specifier:specifier, declarations:declarations }, + <prefix:component_prefix?> + <specifier:identifier> + <declarations:component_declaration+> ";" => + ComponentClause { + prefix:prefix, + specifier:specifier, + declarations:declarations }, }; component_declaration: ComponentDeclaration = { <name:identifier> <ad:array_dimensions?> - <units:units_declaration?> - <value:value_declaration?> + <mods:class_mod?> + <value:assignment_mod?> <desc:string_literal?> (",")? => ComponentDeclaration { @@ -141,10 +142,40 @@ component_declaration: ComponentDeclaration = { dimensions:ad, description:desc, value:value, - units:units, + mods: { mods.unwrap_or(HashMap::new()) }, quantity:None }, }; +// component_assigns happen in: +// component declarations +// argument lists +// class_modifications (parens) happen in the above plus: +// annotations +// extends +// RHS of single-line class defs + +assignment_mod: Expr = { + "=" <expr> => <>, +}; + +class_mod: HashMap<String, Expr> = { + "(" <calist:(<component_assign> ","?)+> ")" => { + let mut out: HashMap<String, Expr> = HashMap::new(); + for ca in calist { + out.insert(ca.0, ca.1); + } + out + } +}; + +component_assign: (String, Expr) = { + <i:identifier> "=" <e:expr> => (i, e), +}; + +annotation: () = { + "annotation" class_mod? => (), +}; + // TODO: this is very partial/cludgy array_dimensions: Vec<i64> = { "[" <dimensions:(<integer> ","?)+> "]" => dimensions, @@ -198,6 +229,7 @@ term: Expr = { boolean => Expr::Boolean(<>), float => Expr::Float(<>), identifier => Expr::Ident(<>), + string_literal => Expr::StringLiteral(<>), "der" "(" <e:expr> ")" => Expr::Der(Box::new(e)), "abs" "(" <e:expr> ")" => Expr::MathUnaryExpr(MathUnaryFunc::Abs, Box::new(e)), "sqrt" "(" <e:expr> ")" => Expr::MathUnaryExpr(MathUnaryFunc::Sqrt, Box::new(e)), @@ -216,6 +248,7 @@ term: Expr = { "(" <e:expr> ")" => e, // Obviously a hack here, only supporting up to 4 elements in an array "[" <e:expr> "]" => Expr::Array(vec![e]), + "[" <e1:expr> ";" <e2:expr> "]" => Expr::Array(vec![e1, e2]), "[" <e1:expr> "," <e2:expr> "]" => Expr::Array(vec![e1, e2]), "[" <e1:expr> "," <e2:expr> "," <e3:expr> "]" => Expr::Array(vec![e1, e2, e3]), "[" <e1:expr> "," <e2:expr> "," <e3:expr> "," <e4:expr> "]" => Expr::Array(vec![e1, e2, e3, e4]), |