From ece67d35847ec89cbf4d3d13236ce5bb1d51b716 Mon Sep 17 00:00:00 2001 From: bnewbold Date: Wed, 2 Nov 2016 19:06:23 -0700 Subject: skeletal scheme transpilation --- src/bin/mt-tool.rs | 9 ++++++++ src/lib.rs | 1 + src/modelica_ast.rs | 38 ++++++++++++++++++++++++++++++++++ src/transpile_scheme.rs | 55 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+) create mode 100644 src/transpile_scheme.rs (limited to 'src') diff --git a/src/bin/mt-tool.rs b/src/bin/mt-tool.rs index 4d66339..8aac6ca 100644 --- a/src/bin/mt-tool.rs +++ b/src/bin/mt-tool.rs @@ -4,6 +4,7 @@ extern crate rustc_serialize; extern crate getopts; use modelthing::modelica_parser; +use modelthing::transpile_scheme::TranspileScheme; use getopts::Options; use std::env; use std::io::Read; @@ -81,6 +82,14 @@ fn main() { let cmd = matches.free[0].clone(); match cmd.as_str() { "parse" => { parse_modelica_files(matches.free[1..].iter().map(|x| x.to_string()).collect()); }, + "transpile" => { + if matches.free.len() != 2 { + println!("Expected a single path to load"); + exit(-1); + } + let me = modelthing::load_model_entry(Path::new(&matches.free[1])).unwrap(); + println!("{}", me.ast.repr_scheme().unwrap()); + }, "list" => { // XXX: search path? for m in modelthing::search_models(Path::new("examples")) { diff --git a/src/lib.rs b/src/lib.rs index 1f7ed27..e6b2f41 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ extern crate toml; pub mod modelica_parser; pub mod modelica_ast; +pub mod transpile_scheme; use std::path::Path; use std::fs; diff --git a/src/modelica_ast.rs b/src/modelica_ast.rs index 68eafaf..9e25b1b 100644 --- a/src/modelica_ast.rs +++ b/src/modelica_ast.rs @@ -1,5 +1,6 @@ use std::fmt::{Debug, Formatter, Error}; +use std::collections::HashMap; #[derive(PartialEq)] pub struct ModelicaModel { @@ -59,6 +60,43 @@ pub enum BinOperator { Subtract, } +//// Helpers + +impl ModelicaModel { + + pub fn get_constant_vars(&self) -> HashMap { + let mut binds = HashMap::new(); + for c in &self.components { + match c.prefix { + Some(ComponentPrefix::Constant) => { binds.insert(c.name.clone(), Expr::Integer(123)); }, + Some(ComponentPrefix::Parameter) => { binds.insert(c.name.clone(), Expr::Float(4.56)); }, + _ => (), + } + } + binds + } + + pub fn get_free_vars(&self) -> Vec { + // 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() + } +} + //// Debug Implementations impl Debug for ModelicaModel { diff --git a/src/transpile_scheme.rs b/src/transpile_scheme.rs new file mode 100644 index 0000000..ce66d10 --- /dev/null +++ b/src/transpile_scheme.rs @@ -0,0 +1,55 @@ + +use modelica_ast::*; + +pub trait TranspileScheme { + fn repr_scheme(&self) -> Result; +} + + +impl TranspileScheme for ModelicaModel { + fn repr_scheme(&self) -> Result { + let mut constants = vec![]; + for (c, e) in self.get_constant_vars() { + constants.push(format!("({} {})", + c, try!(e.repr_scheme()))); + } + 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.repr_scheme()))); + outputs.push(symb.to_string()); + } else { + return Err("Expected an identifier on LHS (in this partial implementation)".to_string()) + } + } + Ok(format!(r#"(lambda ({args}) + (let ({constants}) + (letrec ({binds}) + (list {outputs}))))"#, + args = self.get_free_vars().join(" "), + constants = constants.join("\n "), + binds = binds.join("\n "), + outputs = outputs.join(" "))) + } +} + +impl TranspileScheme for Expr { + fn repr_scheme(&self) -> Result { + use modelica_ast::Expr::*; + match *self { + Integer(e) => Ok(format!("{}", e)), + Float(e) => Ok(format!("{}", e)), + Ident(ref e) => Ok(format!("{}", e)), + Der(ref e) => Ok(format!("(der {})", try!(e.repr_scheme()))), + Abs(ref e) => Ok(format!("(abs {})", try!(e.repr_scheme()))), + BinExpr(op, ref l, ref r) => + Ok(format!("({:?} {} {})", + op, + try!(l.repr_scheme()), + try!(r.repr_scheme()))), + } + } +} -- cgit v1.2.3