use std::str::FromStr; use std::collections::HashMap; use ast::{ModelicaCode, ModelicaPackage, ModelicaBlock, ModelicaConnector, ModelicaType, ModelicaModel, ComponentDeclaration, ModelicaRecord, ComponentClause, ComponentPrefix, Connection, SimpleEquation, Expr, BinOperator, MathUnaryFunc, collapse_components}; // 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(), r"[a-zA-Z_][a-zA-Z_0-9]*\.[a-zA-Z_0-9]+\.[a-zA-Z_0-9]" => <>.to_string(), }; string_literal: String = { r#""[^"\\]*""# => <>.to_string(), }; pub integer: i64 = { r"[+-]?\d+" => i64::from_str(<>).unwrap(), }; pub float: f64 = { r"[+-]?\d+\.\d*([eE][-+]?\d+)?" => f64::from_str(<>).unwrap(), }; pub boolean: bool = { "true" => true, "false" => false, }; // Grammar pub file: Vec = { within_clause? => chunks, }; pub modelica_code: ModelicaCode = { model => ModelicaCode::Model(<>), // TODO: class record => ModelicaCode::Record(<>), block => ModelicaCode::Block(<>), connector => ModelicaCode::Connector(<>), type_declaration => ModelicaCode::Type(<>), package => ModelicaCode::Package(<>), // TODO: function }; pub package: ModelicaPackage = { "package" extends_clause* "end" identifier ";" => ModelicaPackage { name:n, description:desc, children:children, }, }; pub connector: ModelicaConnector = { "connector" "end" identifier ";" => ModelicaConnector { name:n, description:desc, components: { collapse_components(&cpc) } }, }; pub record: ModelicaRecord = { "record" "end" identifier ";" => ModelicaRecord { name:n, description:desc, components: { collapse_components(&cpc) } }, }; type_declaration: ModelicaType = { "type" "=" ";" => ModelicaType { name:n, description:desc, component:cpd, }, }; pub block: ModelicaBlock = { "block" extends_clause* )?> )?> "equation" "end" identifier ";" => ModelicaBlock { name:n, description:desc, components: { collapse_components(&cpc) }, public_components: { collapse_components(&public.unwrap_or(vec![])) }, protected_components: { collapse_components(&protected.unwrap_or(vec![])) }, connections:cc, equations:se }, }; pub model: ModelicaModel = { "partial"? "model" extends_clause* connector* "equation" "end" identifier ";" => ModelicaModel { name:n, description:desc, components: { collapse_components(&cpc) }, connections:cc, equations:se, }, }; extends_clause: String = { "extends" ";" => <>, }; within_clause: String = { "within" ";" => <>, }; component_clause: ComponentClause = { ";" => ComponentClause { prefix:prefix, specifier:specifier, declarations:declarations }, }; component_declaration: ComponentDeclaration = { (",")? => ComponentDeclaration { name:name, dimensions:ad, description:desc, value:value, 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 = { "=" => <>, }; class_mod: HashMap = { "(" ","?)+> ")" => { let mut out: HashMap = HashMap::new(); for ca in calist { out.insert(ca.0, ca.1); } out } }; component_assign: (String, Expr) = { "=" => (i, e), }; annotation: () = { "annotation" class_mod? => (), }; // TODO: this is very partial/cludgy array_dimensions: Vec = { "[" ","?)+> "]" => dimensions, "[" ":" "]" => vec![], }; component_prefix: ComponentPrefix = { "flow" => ComponentPrefix::Flow, "stream" => ComponentPrefix::Stream, "input" => ComponentPrefix::Input, "output" => ComponentPrefix::Output, "discrete" => ComponentPrefix::Discrete, "parameter" => ComponentPrefix::Parameter, "constant" => ComponentPrefix::Constant, }; simple_equation: SimpleEquation = { "=" ";" => SimpleEquation {lhs:lhs, rhs:rhs}, }; connect_clause: Connection = { "connect" "(" "," ")" ";" => Connection { a: a.to_string(), b: b.to_string()}, }; // This weird expr/factor/term hierarchy is for binary operator precedence expr: Expr = { "+" => Expr::BinExpr(BinOperator::Add, Box::new(lhs), Box::new(rhs)), "-" => Expr::BinExpr(BinOperator::Subtract, Box::new(lhs), Box::new(rhs)), factor, }; factor: Expr = { "*" => Expr::BinExpr(BinOperator::Multiply, Box::new(lhs), Box::new(rhs)), "/" => Expr::BinExpr(BinOperator::Divide, Box::new(lhs), Box::new(rhs)), "^" => Expr::BinExpr(BinOperator::Divide, Box::new(lhs), Box::new(rhs)), "-" => Expr::BinExpr(BinOperator::Multiply, Box::new(Expr::Integer(-1)), Box::new(t)), term, }; // TODO: elementwise operators (".+", "./", ".*", ".-") term: Expr = { integer => Expr::Integer(<>), boolean => Expr::Boolean(<>), float => Expr::Float(<>), identifier => Expr::Ident(<>), string_literal => Expr::StringLiteral(<>), "der" "(" ")" => Expr::Der(Box::new(e)), "abs" "(" ")" => Expr::MathUnaryExpr(MathUnaryFunc::Abs, Box::new(e)), "sqrt" "(" ")" => Expr::MathUnaryExpr(MathUnaryFunc::Sqrt, Box::new(e)), "sin" "(" ")" => Expr::MathUnaryExpr(MathUnaryFunc::Sin, Box::new(e)), "cos" "(" ")" => Expr::MathUnaryExpr(MathUnaryFunc::Cos, Box::new(e)), "tan" "(" ")" => Expr::MathUnaryExpr(MathUnaryFunc::Tan, Box::new(e)), "asin" "(" ")" => Expr::MathUnaryExpr(MathUnaryFunc::Asin, Box::new(e)), "acos" "(" ")" => Expr::MathUnaryExpr(MathUnaryFunc::Acos, Box::new(e)), "atan" "(" ")" => Expr::MathUnaryExpr(MathUnaryFunc::Atan, Box::new(e)), "sinh" "(" ")" => Expr::MathUnaryExpr(MathUnaryFunc::Sinh, Box::new(e)), "cosh" "(" ")" => Expr::MathUnaryExpr(MathUnaryFunc::Cosh, Box::new(e)), "tanh" "(" ")" => Expr::MathUnaryExpr(MathUnaryFunc::Tanh, Box::new(e)), "exp" "(" ")" => Expr::MathUnaryExpr(MathUnaryFunc::Exp, Box::new(e)), "log" "(" ")" => Expr::MathUnaryExpr(MathUnaryFunc::Log, Box::new(e)), "log10" "(" ")" => Expr::MathUnaryExpr(MathUnaryFunc::Log10, Box::new(e)), "(" ")" => e, // Obviously a hack here, only supporting up to 4 elements in an array "[" "]" => Expr::Array(vec![e]), "[" ";" "]" => Expr::Array(vec![e1, e2]), "[" "," "]" => Expr::Array(vec![e1, e2]), "[" "," "," "]" => Expr::Array(vec![e1, e2, e3]), "[" "," "," "," "]" => Expr::Array(vec![e1, e2, e3, e4]), };