extern crate modelica_parser; use self::modelica_parser::*; use errors::Result; pub trait TranspileJS { fn transpile_js(&self) -> Result; } pub trait TranspileJSODE { fn transpile_js_ode(&self) -> Result; } impl TranspileJS for ModelicaModel { fn transpile_js(&self) -> Result { let mut params = vec![]; let mut constants = vec![]; for (c, e) in self.get_constant_vars() { if let Some(v) = e { constants.push(format!("var {} = {};", c, try!(v.transpile_js()))); } else { params.push(c); } } // HashMaps are unsorted, so we need to re-sort here constants.sort(); params.sort(); let mut binds = vec![]; let mut outputs = vec![]; for eq in self.equations.iter() { if let Expr::Ident(ref symb) = eq.lhs { binds.push(format!("var {} = {};", symb, try!(eq.rhs.transpile_js()))); outputs.push(symb.to_string()); } else { bail!("Expected an identifier on LHS (in this partial implementation)") } } let mut args: Vec = self.get_free_vars().iter().map(|s| s.clone()).collect(); args.sort(); args.extend(params); Ok(format!( r#"function ({args}) {{ {constants} {binds} return [{outputs}]; }};"#, args = args.join(", "), constants = constants.join("\n "), binds = binds.join("\n "), outputs = outputs.join(", "))) } } impl TranspileJSODE for ModelicaModel { fn transpile_js_ode(&self) -> Result { let mut params = vec![]; let mut constants = vec![]; for (c, e) in self.get_constant_vars() { if let Some(v) = e { constants.push(format!("var {} = {};", c, try!(v.transpile_js()))); } else { params.push(c); } } // HashMaps are unsorted, so we need to re-sort here constants.sort(); params.sort(); let mut exprs = vec![]; for eq in self.equations.iter() { if let Expr::Der(ref der_of) = eq.lhs { if let &Expr::Ident(_) = der_of.as_ref() { // Ok } else { bail!("Non-trivial derivatives not supported (aka, of non-variable expressions)"); } exprs.push(try!(eq.rhs.transpile_js())); } else { bail!("Not a simple set of ODEs (aka, all derivatives on LHS of equations)"); } } let mut args: Vec = self.get_free_vars().iter().map(|s| s.clone()).collect(); args.sort(); Ok(format!( r#"function ({params}) {{ return function({args}) {{ {constants} return [ {expressions} ]; }}; }};"#, params = params.join(", "), args = args.join(", "), constants = constants.join("\n "), // NB: whitespace expressions = exprs.join(",\n "))) // NB: whitespace } } impl TranspileJS for Expr { fn transpile_js(&self) -> Result { use modelica_parser::Expr::*; match *self { Integer(e) => Ok(format!("{}", e)), Float(e) => Ok(format!("{}", e)), Boolean(true) => Ok(format!("true")), Boolean(false) => Ok(format!("false")), StringLiteral(ref s) => Ok(format!("\"{}\"", s)), Ident(ref e) => Ok(format!("{}", e)), Der(_) => unimplemented!(), Sign(_) => unimplemented!(), MathUnaryExpr(func, ref e) => Ok(format!("{:?}({})", func, try!(e.transpile_js()))), BinExpr(op, ref l, ref r) => { Ok(format!("({} {:?} {})", try!(l.transpile_js()), op, try!(r.transpile_js()))) } Array(_) => unimplemented!(), } } }