From 3bc4e5baae51ef622a2cac98f677487cf9342286 Mon Sep 17 00:00:00 2001 From: bnewbold Date: Sat, 28 Jan 2017 21:18:19 -0800 Subject: basic python compiling --- src/transpile_python.rs | 147 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 src/transpile_python.rs (limited to 'src/transpile_python.rs') diff --git a/src/transpile_python.rs b/src/transpile_python.rs new file mode 100644 index 0000000..d980e60 --- /dev/null +++ b/src/transpile_python.rs @@ -0,0 +1,147 @@ + +extern crate modelica_parser; + +use self::modelica_parser::*; +use errors::Result; + +pub trait TranspilePython { + fn transpile_python(&self) -> Result; +} + +pub trait TranspilePythonODE { + fn transpile_python_ode(&self) -> Result; +} + + +impl TranspilePython for ModelicaModel { + fn transpile_python(&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!("{} = {}", c, try!(v.transpile_python()))); + } 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!("{} = {}", + symb, + try!(eq.rhs.transpile_python()))); + 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#"def {slug}({args}): + """{description} + + Args: + {param_doc} + + Returns array of: + {ret_doc} + """ + {constants} + {binds} + return ({outputs}) +"#, + description = self.description.clone().unwrap_or("(undocumented)".to_string()), + param_doc = args.join("\n "), // whitespace sensitive + ret_doc = outputs.join("\n "), // whitespace sensitive + slug = self.name, + args = args.join(", "), + constants = constants.join("\n "), // whitespace sensitive + binds = binds.join("\n "), // whitespace sensitive + outputs = outputs.join(", "))) + } + +} + +impl TranspilePythonODE for ModelicaModel { + + fn transpile_python_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!("{} = {}", c, try!(v.transpile_python()))); + } 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_python())); + } 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#"def {slug}_ode({params}): + def f({args}): + {constants} + return ( + {expressions} + ) + return f +"#, + slug = self.name, + params = params.join(", "), + args = args.join(", "), + constants = constants.join("\n "), // NB: whitespace + expressions = exprs.join(",\n "))) // NB: whitespace + } +} + +impl TranspilePython for Expr { + fn transpile_python(&self) -> Result { + use modelica_parser::Expr::*; + use modelica_parser::BinOperator::*; + 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_python()))), + BinExpr(op, ref l, ref r) => { + // Have override for Python's exponentiation + let op_str = match op { + Multiply => "*", + Divide => "/", + Exponentiate => "**", + Add => "+", + Subtract => "-", + }; + Ok(format!("({} {} {})", try!(l.transpile_python()), op_str, try!(r.transpile_python()))) + } + Array(_) => unimplemented!(), + } + } +} -- cgit v1.2.3