diff options
Diffstat (limited to 'modelica-parser-lalrpop/src/ast.rs')
-rw-r--r-- | modelica-parser-lalrpop/src/ast.rs | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/modelica-parser-lalrpop/src/ast.rs b/modelica-parser-lalrpop/src/ast.rs new file mode 100644 index 0000000..99d443c --- /dev/null +++ b/modelica-parser-lalrpop/src/ast.rs @@ -0,0 +1,241 @@ + +use std::clone::Clone; +use std::fmt::{Debug, Formatter, Error}; +use std::collections::HashMap; + +#[derive(Clone, PartialEq)] +pub struct ModelicaModel { + pub name: String, + pub components: Vec<Component>, + pub equations: Vec<SimpleEquation>, + pub connections: Vec<Connection>, + pub extends: Vec<String>, +} + +#[derive(Copy, Clone, PartialEq)] +pub enum ComponentPrefix { + // incomplete: eg, can be parameter and input + Flow, + Stream, + Input, + Output, + Discrete, + Parameter, + Constant, +} + +#[derive(Clone, PartialEq)] +pub struct Component { + pub prefix: Option<ComponentPrefix>, + pub specifier: String, + pub name: String, + pub value: Option<Expr>, + pub units: Option<String>, + pub description: Option<String>, +} + +#[derive(Clone, PartialEq)] +pub struct Connection { + pub a: String, + pub b: String, +} + +#[derive(Clone, PartialEq)] +pub struct SimpleEquation { + pub lhs: Expr, + pub rhs: Expr, +} + +#[derive(Clone, PartialEq)] +pub enum Expr { + Integer(i64), + Float(f64), + Ident(String), + Der(Box<Expr>), + Abs(Box<Expr>), + BinExpr(BinOperator, Box<Expr>, Box<Expr>), +} + +#[derive(Copy, Clone, PartialEq)] +pub enum BinOperator { + Multiply, + Divide, + Add, + Subtract, +} + +//// Helpers + +impl ModelicaModel { + + pub fn get_constant_vars(&self) -> HashMap<String,Option<Expr>> { + let mut binds = HashMap::new(); + // XXX: actually implement this... + for c in &self.components { + match c.prefix { + Some(ComponentPrefix::Constant) => { binds.insert(c.name.clone(), Some(Expr::Integer(123))); }, + Some(ComponentPrefix::Parameter) => { binds.insert(c.name.clone(), Some(Expr::Float(4.56))); }, + _ => (), + } + } + binds + } + + // This crude function finds "unbound" variables: those which are not constants, parameters, or + // the sole element on the LHS of an equation. + // Bugs: + // if a var is on LHS and RHS of same equation + pub fn get_free_vars(&self) -> Vec<String> { + // Start with components, and remove constants and parameters + let vars = self.components.iter().filter(|v| match v.prefix { + Some(ComponentPrefix::Constant) | Some(ComponentPrefix::Parameter) => false, + _ => true, + }); + + // Remove LHS (bound) vars + let mut outputs = vec![]; + for eq in self.equations.iter() { + // TODO: + if let Expr::Ident(ref symb) = eq.lhs { + outputs.push(symb.to_string()); + } + } + let vars = vars.filter(|v| !outputs.contains(&v.name)); + + vars.map(|c| c.name.clone()).collect() + } + +} + +fn union_strings(a: &Vec<String>, b: &Vec<String>) -> Vec<String> { + let mut u = a.clone(); + for e in b { + if !(u.contains(&e)) { + u.push(e.clone()); + } + } + u +} + +impl Expr { + + // Order is undefined + // TODO: should return a HashSet, not a Vec + pub fn identifiers(&self) -> Vec<String> { + use self::Expr::*; + match *self { + Integer(_) | Float(_) => vec![], + Ident(ref s) => vec![s.clone()], + Der(ref e) | Abs(ref e) => e.identifiers(), + BinExpr(_, ref e1, ref e2) => { + union_strings(&e1.identifiers(), &e2.identifiers()) + }, + } + } + + pub fn contains(&self, ident: &str) -> bool{ + self.identifiers().contains(&ident.to_string()) + } +} + +impl SimpleEquation { + + // Order is undefined + pub fn identifiers(&self) -> Vec<String> { + union_strings(&self.lhs.identifiers(), &self.rhs.identifiers()) + } + + pub fn contains(&self, ident: &str) -> bool{ + let s = &ident.to_string(); + self.lhs.identifiers().contains(s) || self.rhs.identifiers().contains(s) + } +} + +//// Debug Implementations + +impl Debug for ModelicaModel { + fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { + try!(write!(fmt, "model {}\n", self.name)); + for e in self.extends.iter() { + try!(write!(fmt, " extends {};\n", e)); + } + for v in self.components.iter() { + try!(write!(fmt, " {:?};\n", v)); + } + try!(write!(fmt, "equation\n")); + for c in self.connections.iter() { + try!(write!(fmt, " {:?};\n", c)); + } + for e in self.equations.iter() { + try!(write!(fmt, " {:?};\n", e)); + } + write!(fmt, "end {};\n", self.name) + } +} + +impl Debug for ComponentPrefix { + fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { + use self::ComponentPrefix::*; + write!(fmt, "{}", + match *self { + Flow => "flow", + Stream => "stream", + Input => "input", + Output => "output", + Discrete => "discrete", + Parameter => "parameter", + Constant => "constant", + }) + } +} + +impl Debug for Component { + fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { + write!(fmt, "{}{} {}", + match self.prefix { + Some(p) => format!("{:?} ", p), + None => "".to_string(), + }, + self.specifier, + self.name, + ) + } +} + +impl Debug for Connection { + fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { + write!(fmt, "connect({}, {})", self.a, self.b) + } +} + +impl Debug for SimpleEquation { + fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { + write!(fmt, "{:?} = {:?}", self.lhs, self.rhs) + } +} + +impl Debug for Expr { + fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { + use self::Expr::*; + match *self { + Integer(e) => write!(fmt, "{}", e), + Float(e) => write!(fmt, "{}", e), + Ident(ref e) => write!(fmt, "{}", e), + Der(ref e) => write!(fmt, "der({:?})", e), + Abs(ref e) => write!(fmt, "abs({:?})", e), + BinExpr(op, ref l, ref r) => write!(fmt, "({:?} {:?} {:?})", l, op, r), + } + } +} + +impl Debug for BinOperator { + fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { + use self::BinOperator::*; + match *self { + Multiply => write!(fmt, "*"), + Divide => write!(fmt, "/"), + Add => write!(fmt, "+"), + Subtract => write!(fmt, "-"), + } + } +} |