#[macro_use] extern crate log; extern crate toml; pub mod modelica_parser; pub mod modelica_ast; pub mod transpile_scheme; pub mod transpile_js; use std::path::Path; use std::fs; use std::io::Read; use std::fs::File; #[derive(Debug, PartialEq)] pub struct ModelMetadata { pub name_en: String, pub description_en: Option, pub vars: Vec, } #[derive(Debug, PartialEq)] pub enum ModelVarType { Independent, Dependent, Constant, Time, State, Parameter, } #[derive(Debug, PartialEq)] pub struct ModelVar { pub slug: String, pub name_en: Option, pub vtype: ModelVarType, pub latex: Option, pub units_si: Option, } #[derive(Debug, PartialEq)] pub struct ModelEntry { pub ast: modelica_ast::ModelicaModel, pub metadata: ModelMetadata, pub markdown: String, } pub fn parse_metadata(raw: String) -> Result { let root = toml::Parser::new(&raw).parse().unwrap(); let model = root.get("model").unwrap().as_table().unwrap(); let variables = root.get("variables").unwrap().as_table().unwrap(); let mut vars = vec![]; for (slug, info) in variables { let info = info.as_table().unwrap(); let vtype = match info.get("type").unwrap().as_str().unwrap() { "independent" => ModelVarType::Independent, "dependent" => ModelVarType::Dependent, "constant" => ModelVarType::Constant, "time" => ModelVarType::Time, "state" => ModelVarType::State, "parameter" => ModelVarType::Parameter, other => return Err(format!("Unknown variable type: {}", other)), }; vars.push(ModelVar { slug: slug.to_string(), name_en: info.get("name-en").map(|x| x.as_str().unwrap().to_string()), vtype: vtype, latex: info.get("latex").map(|x| x.as_str().unwrap().to_string()), units_si: info.get("units-si").map(|x| x.as_str().unwrap().to_string()), }); } Ok(ModelMetadata { name_en: model.get("name-en").unwrap().as_str().unwrap().to_string(), description_en: model.get("description-en").map(|x| x.as_str().unwrap().to_string()), vars: vars, }) } pub fn load_model_entry(p: &Path) -> Result { 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!(modelica_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())); 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())); s }; Ok(ModelEntry { ast: ast, metadata: metadata, markdown: markdown, }) } pub fn search_models(p: &Path) -> Vec { 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() } else { vec![] } } /* ******************************** Tests ******************************* */ #[test] fn test_parse_metadata() { assert_eq!(parse_metadata("asdf".to_string()).unwrap(), ModelMetadata { name_en: "Bogus Dummy Model".to_string(), description_en: None, vars: vec![], }); } #[test] fn test_load_model_entry() { load_model_entry(Path::new("./examples/classic_gravitation/")).unwrap(); } #[test] fn test_search_models() { assert_eq!(search_models(Path::new("./examples/")).len() > 1, true); } #[test] fn test_lexical() { assert_eq!(&format!("{:?}", modelica_parser::parse_integer("+123").unwrap()), "123"); assert_eq!(&format!("{:?}", modelica_parser::parse_integer("-9").unwrap()), "-9"); assert_eq!(&format!("{:?}", modelica_parser::parse_float("-1.0e0").unwrap()), "-1"); assert_eq!(&format!("{:?}", modelica_parser::parse_float("123.456").unwrap()), "123.456"); } #[test] fn test_parse() { let example1 = r#"model MinimalModel Real x; equation x = 1; end MinimalModel; "#; assert_eq!(&format!("{:?}", modelica_parser::parse_model(example1).unwrap()), example1); let example2 = r#"model MinimalModel parameter Real a; Real b; equation connect(a, b); a = 1; b = ((abs(a) + 2) / 4); end MinimalModel; "#; assert_eq!(&format!("{:?}", modelica_parser::parse_model(example2).unwrap()), example2); }