aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs35
-rw-r--r--src/modelica_model.rs178
-rw-r--r--src/transpile_js.rs31
-rw-r--r--src/transpile_scheme.rs27
4 files changed, 163 insertions, 108 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 7c3bb8b..e20c8fb 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -47,14 +47,16 @@ pub struct ModelEntry {
pub markdown: String,
}
-pub fn parse_metadata(raw: String) -> Result<ModelMetadata,String> {
+pub fn parse_metadata(raw: String) -> Result<ModelMetadata, String> {
let root = toml::Parser::new(&raw).parse().unwrap();
let model = root.get("model")
.expect("missing 'model' section")
- .as_table().unwrap();
+ .as_table()
+ .unwrap();
let variables = root.get("variables")
.expect("missing 'variables' section")
- .as_table().unwrap();
+ .as_table()
+ .unwrap();
let mut vars = vec![];
for (slug, info) in variables {
let info = info.as_table().unwrap();
@@ -82,24 +84,30 @@ pub fn parse_metadata(raw: String) -> Result<ModelMetadata,String> {
})
}
-pub fn load_model_entry(p: &Path) -> Result<ModelEntry,String> {
+pub fn load_model_entry(p: &Path) -> Result<ModelEntry, String> {
debug!("Attempting to load model from: {:?}", p);
let ast = {
let mut s = String::new();
- try!(File::open(p.join("model.modelica")).and_then(|mut f| f.read_to_string(&mut s)).map_err(|e| e.to_string()));
+ try!(File::open(p.join("model.modelica"))
+ .and_then(|mut f| f.read_to_string(&mut s))
+ .map_err(|e| e.to_string()));
try!(modelica_parser::parser::parse_model(&s).map_err(|e| format!("{:?}", e)))
};
let metadata = {
let mut s = String::new();
- try!(File::open(p.join("metadata.toml")).and_then(|mut f| f.read_to_string(&mut s)).map_err(|e| e.to_string()));
+ try!(File::open(p.join("metadata.toml"))
+ .and_then(|mut f| f.read_to_string(&mut s))
+ .map_err(|e| e.to_string()));
parse_metadata(s).unwrap()
};
let markdown = {
let mut s = String::new();
- try!(File::open(p.join("page.md")).and_then(|mut f| f.read_to_string(&mut s)).map_err(|e| e.to_string()));
+ try!(File::open(p.join("page.md"))
+ .and_then(|mut f| f.read_to_string(&mut s))
+ .map_err(|e| e.to_string()));
s
};
@@ -112,12 +120,13 @@ pub fn load_model_entry(p: &Path) -> Result<ModelEntry,String> {
pub fn search_models(p: &Path) -> Vec<String> {
if fs::metadata(p).unwrap().is_dir() {
- fs::read_dir(p).unwrap()
- .map(|x| x.unwrap())
- .filter(|x| x.metadata().unwrap().is_dir())
- .filter(|x| x.path().join("model.modelica").exists())
- .map(|x| x.path().to_string_lossy().to_string())
- .collect()
+ fs::read_dir(p)
+ .unwrap()
+ .map(|x| x.unwrap())
+ .filter(|x| x.metadata().unwrap().is_dir())
+ .filter(|x| x.path().join("model.modelica").exists())
+ .map(|x| x.path().to_string_lossy().to_string())
+ .collect()
} else {
vec![]
}
diff --git a/src/modelica_model.rs b/src/modelica_model.rs
index 36c5a2e..81680d6 100644
--- a/src/modelica_model.rs
+++ b/src/modelica_model.rs
@@ -8,23 +8,29 @@ use std::collections::HashSet;
use self::modelica_parser::ast::*;
-//// Helpers
+/// / Helpers
pub trait ModelicaModelExt {
- fn get_constant_vars(&self) -> HashMap<String,Option<Expr>>;
+ fn get_constant_vars(&self) -> HashMap<String, Option<Expr>>;
fn get_free_vars(&self) -> Vec<String>;
- fn solve_for(&self, indep_vars: Vec<String>, dep_vars: Vec<String>) -> Result<ModelicaModel,String>;
+ fn solve_for(&self,
+ indep_vars: Vec<String>,
+ dep_vars: Vec<String>)
+ -> Result<ModelicaModel, String>;
}
impl ModelicaModelExt for ModelicaModel {
-
- fn get_constant_vars(&self) -> HashMap<String,Option<Expr>> {
+ 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))); },
+ 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)));
+ }
_ => (),
}
}
@@ -38,9 +44,10 @@ impl ModelicaModelExt for ModelicaModel {
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,
- });
+ Some(ComponentPrefix::Constant) |
+ Some(ComponentPrefix::Parameter) => false,
+ _ => true,
+ });
// Remove LHS (bound) vars
let mut outputs = vec![];
@@ -63,7 +70,10 @@ impl ModelicaModelExt for ModelicaModel {
// N equations with unknowns
//
// TODO: allow passing in Q
- fn solve_for(&self, indep_vars: Vec<String>, dep_vars: Vec<String>) -> Result<ModelicaModel,String> {
+ fn solve_for(&self,
+ indep_vars: Vec<String>,
+ dep_vars: Vec<String>)
+ -> Result<ModelicaModel, String> {
let constants = self.get_constant_vars();
let mut all_vars: HashSet<String> = HashSet::new();
for eqn in &self.equations {
@@ -82,25 +92,30 @@ impl ModelicaModelExt for ModelicaModel {
// check that V = Q + P + M
if all_vars.len() != (constants.len() + indep_vars.len() + dep_vars.len()) {
return Err(format!("Variable counts don't add up (V={} Q={} P={} M={})",
- all_vars.len(),
- constants.len(),
- indep_vars.len(),
- dep_vars.len()));
+ all_vars.len(),
+ constants.len(),
+ indep_vars.len(),
+ dep_vars.len()));
}
// check that all constants are bound and simple
for (name, value) in &constants {
match *value {
None => return Err(format!("UnderSpecifiedConstant: {}", name)),
- Some(Expr::Integer(_)) | Some(Expr::Float(_)) => (), // Ok,
- Some(_) => return Err(format!("NaiveImplementation: can't handle constant: {}", name)),
+ Some(Expr::Integer(_)) |
+ Some(Expr::Float(_)) => (), // Ok,
+ Some(_) => {
+ return Err(format!("NaiveImplementation: can't handle constant: {}", name))
+ }
}
}
// check that there is a depdendent variable in each equation
for eqn in &self.equations {
if intersect_strings(&dep_vars, &eqn.identifiers()).len() == 0 {
- return Err("NaiveImplementation/OverConstrained: at least one equation is missing a dependent variable".to_string());
+ return Err("NaiveImplementation/OverConstrained: at least one equation is \
+ missing a dependent variable"
+ .to_string());
}
}
@@ -110,17 +125,21 @@ impl ModelicaModelExt for ModelicaModel {
}
println!("Soliving for {:?} in terms of params {:?} and constants {:?}, with {} equations",
- dep_vars, indep_vars, constants, self.equations.len());
+ dep_vars,
+ indep_vars,
+ constants,
+ self.equations.len());
let mut unsolved_eqns = self.equations.clone();
let mut solved: Vec<SimpleEquation> = vec![];
let mut unsolved_vars = dep_vars.clone();
while unsolved_eqns.len() > 0 {
- let next_i = unsolved_eqns
- .iter()
+ let next_i = unsolved_eqns.iter()
.position(|ref x| intersect_strings(&unsolved_vars, &x.identifiers()).len() == 1);
let eqn = match next_i {
- None => { return Err("NaiveImplementation (or poor equation selection?)".to_string()); },
+ None => {
+ return Err("NaiveImplementation (or poor equation selection?)".to_string());
+ }
Some(i) => unsolved_eqns.remove(i),
};
let ref var = intersect_strings(&unsolved_vars, &eqn.identifiers())[0];
@@ -128,10 +147,10 @@ impl ModelicaModelExt for ModelicaModel {
solved.push(eqn);
let var_i = unsolved_vars.iter().position(|ref x| x == &var).unwrap();
unsolved_vars.remove(var_i);
- };
+ }
// TODO: sort output equations by LHS
- Ok(ModelicaModel{
+ Ok(ModelicaModel {
name: self.name.clone(),
description: self.description.clone(),
components: self.components.clone(),
@@ -152,13 +171,12 @@ fn intersect_strings(a: &Vec<String>, b: &Vec<String>) -> Vec<String> {
}
pub trait SimpleEquationExt {
- fn rebalance_for(&self, ident: String) -> Result<SimpleEquation,String>;
- fn simplify_lhs(&self, ident: &str) -> Result<SimpleEquation,String>;
+ fn rebalance_for(&self, ident: String) -> Result<SimpleEquation, String>;
+ fn simplify_lhs(&self, ident: &str) -> Result<SimpleEquation, String>;
}
impl SimpleEquationExt for SimpleEquation {
-
- fn rebalance_for(&self, ident: String) -> Result<SimpleEquation,String> {
+ fn rebalance_for(&self, ident: String) -> Result<SimpleEquation, String> {
let lvars = self.lhs.identifiers();
let rvars = self.rhs.identifiers();
@@ -166,9 +184,13 @@ impl SimpleEquationExt for SimpleEquation {
(true, true) => Err("SymbolicError: NaiveImplementation".to_string()),
(false, false) => Err("SymbolicError: VariableNotFound".to_string()),
(true, false) => self.simplify_lhs(&ident),
- (false, true) =>
- SimpleEquation{lhs: self.rhs.clone(),
- rhs: self.lhs.clone()}.simplify_lhs(&ident),
+ (false, true) => {
+ SimpleEquation {
+ lhs: self.rhs.clone(),
+ rhs: self.lhs.clone(),
+ }
+ .simplify_lhs(&ident)
+ }
};
match ret {
Ok(eqn) => {
@@ -176,56 +198,86 @@ impl SimpleEquationExt for SimpleEquation {
Err("SymbolicError: NaiveImplementation".to_string())
} else {
Ok(eqn)
- }},
+ }
+ }
Err(_) => ret,
}
}
- fn simplify_lhs(&self, ident: &str) -> Result<SimpleEquation,String> {
+ fn simplify_lhs(&self, ident: &str) -> Result<SimpleEquation, String> {
use modelica_parser::ast::Expr::*;
use modelica_parser::ast::BinOperator::*;
match self.lhs {
Ident(ref s) if s == ident => Ok((*self).clone()),
- Ident(_) | Integer(_) | Float(_) | Boolean(_) | StringLiteral(_) =>
- Err("SymbolicError: InternalError: expected var on LHS".to_string()),
- Der(_) | MathUnaryExpr(_,_) | Sign(_) | Array(_) =>
- Err("SymbolicError: NaiveImplementation: can't simplify".to_string()),
+ Ident(_) | Integer(_) | Float(_) | Boolean(_) | StringLiteral(_) => {
+ Err("SymbolicError: InternalError: expected var on LHS".to_string())
+ }
+ Der(_) |
+ MathUnaryExpr(_, _) |
+ Sign(_) |
+ Array(_) => Err("SymbolicError: NaiveImplementation: can't simplify".to_string()),
// TODO: create a macro for the below...
BinExpr(Multiply, ref a, ref b) if a.contains(ident) => {
- SimpleEquation{
- lhs: *a.clone(),
- rhs: BinExpr(Divide, Box::new(self.rhs.clone()), b.clone())}.simplify_lhs(&ident) },
+ SimpleEquation {
+ lhs: *a.clone(),
+ rhs: BinExpr(Divide, Box::new(self.rhs.clone()), b.clone()),
+ }
+ .simplify_lhs(&ident)
+ }
BinExpr(Multiply, ref a, ref b) if b.contains(ident) => {
- SimpleEquation{
- lhs: *b.clone(),
- rhs: BinExpr(Divide, Box::new(self.rhs.clone()), a.clone())}.simplify_lhs(&ident) },
+ SimpleEquation {
+ lhs: *b.clone(),
+ rhs: BinExpr(Divide, Box::new(self.rhs.clone()), a.clone()),
+ }
+ .simplify_lhs(&ident)
+ }
BinExpr(Divide, ref a, ref b) if a.contains(ident) => {
- SimpleEquation{
- lhs: *a.clone(),
- rhs: BinExpr(Multiply, Box::new(self.rhs.clone()), b.clone())}.simplify_lhs(&ident) },
+ SimpleEquation {
+ lhs: *a.clone(),
+ rhs: BinExpr(Multiply, Box::new(self.rhs.clone()), b.clone()),
+ }
+ .simplify_lhs(&ident)
+ }
BinExpr(Divide, ref a, ref b) if b.contains(ident) => {
- SimpleEquation{
- lhs: *b.clone(),
- rhs: BinExpr(Divide, a.clone(), Box::new(self.rhs.clone()))}.simplify_lhs(&ident) },
+ SimpleEquation {
+ lhs: *b.clone(),
+ rhs: BinExpr(Divide, a.clone(), Box::new(self.rhs.clone())),
+ }
+ .simplify_lhs(&ident)
+ }
BinExpr(Add, ref a, ref b) if a.contains(ident) => {
- SimpleEquation{
- lhs: *a.clone(),
- rhs: BinExpr(Subtract, Box::new(self.rhs.clone()), b.clone())}.simplify_lhs(&ident) },
+ SimpleEquation {
+ lhs: *a.clone(),
+ rhs: BinExpr(Subtract, Box::new(self.rhs.clone()), b.clone()),
+ }
+ .simplify_lhs(&ident)
+ }
BinExpr(Add, ref a, ref b) if b.contains(ident) => {
- SimpleEquation{
- lhs: *b.clone(),
- rhs: BinExpr(Subtract, Box::new(self.rhs.clone()), a.clone())}.simplify_lhs(&ident) },
+ SimpleEquation {
+ lhs: *b.clone(),
+ rhs: BinExpr(Subtract, Box::new(self.rhs.clone()), a.clone()),
+ }
+ .simplify_lhs(&ident)
+ }
BinExpr(Subtract, ref a, ref b) if a.contains(ident) => {
- SimpleEquation{
- lhs: *a.clone(),
- rhs: BinExpr(Add, Box::new(self.rhs.clone()), b.clone())}.simplify_lhs(&ident) },
+ SimpleEquation {
+ lhs: *a.clone(),
+ rhs: BinExpr(Add, Box::new(self.rhs.clone()), b.clone()),
+ }
+ .simplify_lhs(&ident)
+ }
BinExpr(Subtract, ref a, ref b) if b.contains(ident) => {
- SimpleEquation{
- lhs: *b.clone(),
- rhs: BinExpr(Subtract, a.clone(), Box::new(self.rhs.clone()))}.simplify_lhs(&ident) },
- BinExpr(_, _, _) => Err("SymbolicError: NotImplemented BinOperator (or else couldn't find var...)".to_string()),
+ SimpleEquation {
+ lhs: *b.clone(),
+ rhs: BinExpr(Subtract, a.clone(), Box::new(self.rhs.clone())),
+ }
+ .simplify_lhs(&ident)
+ }
+ BinExpr(_, _, _) => {
+ Err("SymbolicError: NotImplemented BinOperator (or else couldn't find var...)"
+ .to_string())
+ }
// in case we add opers: _ => Err("NotImplemented".to_string()),
}
}
}
-
diff --git a/src/transpile_js.rs b/src/transpile_js.rs
index d4ed5f7..1fa6075 100644
--- a/src/transpile_js.rs
+++ b/src/transpile_js.rs
@@ -13,33 +13,30 @@ impl TranspileJS for ModelicaModel {
let mut constants = vec![];
for (c, e) in self.get_constant_vars() {
if let Some(v) = e {
- constants.push(format!("var {} = {};",
- c, try!(v.repr_js())));
+ constants.push(format!("var {} = {};", c, try!(v.repr_js())));
}
}
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.repr_js())));
+ binds.push(format!("var {} = {};", symb, try!(eq.rhs.repr_js())));
outputs.push(symb.to_string());
} else {
- return Err("Expected an identifier on LHS (in this partial implementation)".to_string())
+ return Err("Expected an identifier on LHS (in this partial implementation)"
+ .to_string());
}
}
- Ok(format!(
- r#"function {slug}({args}) {{
+ Ok(format!(r#"function {slug}({args}) {{
{constants}
{binds}
return [{outputs}];
}}"#,
- slug = "f",
- args = self.get_free_vars().join(", "),
- constants = constants.join("\n "),
- binds = binds.join("\n "),
- outputs = outputs.join(", ")))
+ slug = "f",
+ args = self.get_free_vars().join(", "),
+ constants = constants.join("\n "),
+ binds = binds.join("\n "),
+ outputs = outputs.join(", ")))
}
}
@@ -56,11 +53,9 @@ impl TranspileJS for Expr {
Der(ref e) => Ok(format!("der({})", try!(e.repr_js()))),
Sign(ref e) => Ok(format!("sign({})", try!(e.repr_js()))),
MathUnaryExpr(func, ref e) => Ok(format!("{:?}({})", func, try!(e.repr_js()))),
- BinExpr(op, ref l, ref r) =>
- Ok(format!("({} {:?} {})",
- try!(l.repr_js()),
- op,
- try!(r.repr_js()))),
+ BinExpr(op, ref l, ref r) => {
+ Ok(format!("({} {:?} {})", try!(l.repr_js()), op, try!(r.repr_js())))
+ }
Array(_) => Err("Array unimplemented".to_string()),
}
}
diff --git a/src/transpile_scheme.rs b/src/transpile_scheme.rs
index 79492d8..7c25047 100644
--- a/src/transpile_scheme.rs
+++ b/src/transpile_scheme.rs
@@ -13,30 +13,28 @@ impl TranspileScheme for ModelicaModel {
let mut constants = vec![];
for (c, e) in self.get_constant_vars() {
if let Some(v) = e {
- constants.push(format!("({} {})",
- c, try!(v.repr_scheme())));
+ constants.push(format!("({} {})", c, try!(v.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())));
+ 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())
+ 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(" ")))
+ args = self.get_free_vars().join(" "),
+ constants = constants.join("\n "),
+ binds = binds.join("\n "),
+ outputs = outputs.join(" ")))
}
}
@@ -53,11 +51,12 @@ impl TranspileScheme for Expr {
Der(ref e) => Ok(format!("(der {})", try!(e.repr_scheme()))),
Sign(ref e) => Ok(format!("(sign {})", try!(e.repr_scheme()))),
MathUnaryExpr(func, ref e) => Ok(format!("({:?} {})", func, try!(e.repr_scheme()))),
- BinExpr(op, ref l, ref r) =>
+ BinExpr(op, ref l, ref r) => {
Ok(format!("({:?} {} {})",
- op,
- try!(l.repr_scheme()),
- try!(r.repr_scheme()))),
+ op,
+ try!(l.repr_scheme()),
+ try!(r.repr_scheme())))
+ }
Array(_) => Err("Array unimplemented".to_string()),
}
}