From cc06bafd0d0b3fd662855706f7f419b73f3b2a25 Mon Sep 17 00:00:00 2001 From: Micahel Langhammer Date: Tue, 19 Mar 2024 21:38:41 +0100 Subject: [PATCH 01/43] create empty rust project --- Readme.md | 3 ++- mps-cli-rs/Cargo.lock | 7 +++++++ mps-cli-rs/Cargo.toml | 8 ++++++++ mps-cli-rs/src/main.rs | 3 +++ 4 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 mps-cli-rs/Cargo.lock create mode 100644 mps-cli-rs/Cargo.toml create mode 100644 mps-cli-rs/src/main.rs diff --git a/Readme.md b/Readme.md index 2db21f7..53ced36 100644 --- a/Readme.md +++ b/Readme.md @@ -11,7 +11,8 @@ This repository contains tooling for reading MPS models from command line - with ### Repository Structure - `mps-cli-gradle-plugin` - the gradle plugin to read MPS models - `mps-cli-py` - a Python library to read MPS models -- `mps-cli-ts` - a Typescript library to read MPS models +- `mps-cli-ts` - a Typescript library to read MPS models +- `mps-cli-ts` - a Rust library to read MPS models - `demos` - examples for the use of the MPS-CLI tooling - `gradle-plugin-use` - example of the use of the `mps-cli-gradle-plugin` - `jupyter-notebook` - example of the use of the `mps-cli-py` library in a Jupyter Notebook diff --git a/mps-cli-rs/Cargo.lock b/mps-cli-rs/Cargo.lock new file mode 100644 index 0000000..aee7e72 --- /dev/null +++ b/mps-cli-rs/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "mps-cli-rs" +version = "0.1.0" diff --git a/mps-cli-rs/Cargo.toml b/mps-cli-rs/Cargo.toml new file mode 100644 index 0000000..41ba1d6 --- /dev/null +++ b/mps-cli-rs/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "mps-cli-rs" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/mps-cli-rs/src/main.rs b/mps-cli-rs/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/mps-cli-rs/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} From 327d8c7f884483447a8e5515e8090331485df979 Mon Sep 17 00:00:00 2001 From: Michael Langhammer Date: Fri, 22 Mar 2024 18:20:10 +0100 Subject: [PATCH 02/43] add rust model --- .gitignore | 1 + mps-cli-rs/.vscode/settings.json | 7 ++ mps-cli-rs/Cargo.lock | 45 +++++++++++ mps-cli-rs/Cargo.toml | 2 + mps-cli-rs/src/main.rs | 2 + mps-cli-rs/src/model/mod.rs | 7 ++ mps-cli-rs/src/model/sconcept.rs | 112 ++++++++++++++++++++++++++++ mps-cli-rs/src/model/slanguage.rs | 54 ++++++++++++++ mps-cli-rs/src/model/smodel.rs | 38 ++++++++++ mps-cli-rs/src/model/snode.rs | 74 ++++++++++++++++++ mps-cli-rs/src/model/snoderef.rs | 25 +++++++ mps-cli-rs/src/model/srepository.rs | 44 +++++++++++ mps-cli-rs/src/model/ssolution.rs | 9 +++ 13 files changed, 420 insertions(+) create mode 100644 mps-cli-rs/.vscode/settings.json create mode 100644 mps-cli-rs/src/model/mod.rs create mode 100644 mps-cli-rs/src/model/sconcept.rs create mode 100644 mps-cli-rs/src/model/slanguage.rs create mode 100644 mps-cli-rs/src/model/smodel.rs create mode 100644 mps-cli-rs/src/model/snode.rs create mode 100644 mps-cli-rs/src/model/snoderef.rs create mode 100644 mps-cli-rs/src/model/srepository.rs create mode 100644 mps-cli-rs/src/model/ssolution.rs diff --git a/.gitignore b/.gitignore index f51ed76..297a4e9 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ **/venv/ **/node_modules/ **/dist/ +/mps-cli-rs/target gradle.properties **/workspace.xml diff --git a/mps-cli-rs/.vscode/settings.json b/mps-cli-rs/.vscode/settings.json new file mode 100644 index 0000000..868d3ca --- /dev/null +++ b/mps-cli-rs/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "rust-analyzer.linkedProjects": [ + "./Cargo.toml", + "./Cargo.toml", + "./Cargo.toml" + ] +} \ No newline at end of file diff --git a/mps-cli-rs/Cargo.lock b/mps-cli-rs/Cargo.lock index aee7e72..0adf37d 100644 --- a/mps-cli-rs/Cargo.lock +++ b/mps-cli-rs/Cargo.lock @@ -2,6 +2,51 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "builder" +version = "0.1.0" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + [[package]] name = "mps-cli-rs" version = "0.1.0" +dependencies = [ + "uuid", +] + +[[package]] +name = "uuid" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +dependencies = [ + "getrandom", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/mps-cli-rs/Cargo.toml b/mps-cli-rs/Cargo.toml index 41ba1d6..80867f1 100644 --- a/mps-cli-rs/Cargo.toml +++ b/mps-cli-rs/Cargo.toml @@ -1,3 +1,4 @@ +workspace = { members = ["src/builder"] } [package] name = "mps-cli-rs" version = "0.1.0" @@ -6,3 +7,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +uuid = { version = "1.8.0", features = ["v4"] } diff --git a/mps-cli-rs/src/main.rs b/mps-cli-rs/src/main.rs index e7a11a9..ccdc71c 100644 --- a/mps-cli-rs/src/main.rs +++ b/mps-cli-rs/src/main.rs @@ -1,3 +1,5 @@ +mod model; + fn main() { println!("Hello, world!"); } diff --git a/mps-cli-rs/src/model/mod.rs b/mps-cli-rs/src/model/mod.rs new file mode 100644 index 0000000..5092e45 --- /dev/null +++ b/mps-cli-rs/src/model/mod.rs @@ -0,0 +1,7 @@ +pub mod sconcept; +mod slanguage; +mod smodel; +mod snode; +mod snoderef; +mod ssolution; +mod srepository; \ No newline at end of file diff --git a/mps-cli-rs/src/model/sconcept.rs b/mps-cli-rs/src/model/sconcept.rs new file mode 100644 index 0000000..844baa6 --- /dev/null +++ b/mps-cli-rs/src/model/sconcept.rs @@ -0,0 +1,112 @@ +use std::collections::HashMap; + +use uuid::Uuid; + +#[derive(Debug, PartialEq)] +pub struct SConcept { + pub(crate) name: String, + uuid: Uuid, + pub(crate) properties: HashMap, + containment_links: HashMap, + reference_links: HashMap, +} + +#[derive(PartialEq, Eq, Hash, Debug)] +pub struct SProperty { + pub(crate) name: String, + uuid: Uuid, +} + +#[derive(PartialEq, Eq, Hash, Debug)] +pub struct SContainmentLink { + pub(crate) name: String, + uuid: Uuid, +} + +#[derive(PartialEq, Eq, Hash, Debug)] +pub struct SReferenceLink { + pub(crate) name: String, + uuid: Uuid, +} + +impl SConcept { + pub fn new(name: String, uuid: Uuid) -> Self { + SConcept { + name, + uuid, + properties: HashMap::new(), + containment_links: HashMap::new(), + reference_links: HashMap::new(), + } + } + + pub fn print_concept_details(&self) { + let properties_string_vector: Vec = self.properties.iter().map(|prop| format!("{} {}", prop.0, prop.1.name)).collect(); + let properties_info = properties_string_vector.join(", "); + let children_info = self.containment_links.iter().map(|child| { format!("{} {}", child.0, child.1.name) }).collect::>().join(", "); + let reference_info = self.reference_links.iter().map(|reference| format!("{} {}", reference.0, reference.1.name)).collect::>().join(", "); + println!("concept {}\n\ + properties: \n\ + \t\t{}\n\ + children: \n\ + \t\t{}\n\ + references: \n\ + \t\t{}\n\ + <<<", self.name, properties_info, children_info, reference_info); + } +} + +impl SProperty { + pub fn new(name: String, uuid: Uuid) -> Self { + SProperty { + name, + uuid, + } + } +} + +impl SContainmentLink { + pub fn new(name: String, uuid: Uuid) -> Self { + SContainmentLink { + name, + uuid, + } + } +} + +impl SReferenceLink { + pub fn new(name: String, uuid: Uuid) -> Self { + SReferenceLink { + name, + uuid, + } + } +} + +#[cfg(test)] +mod tests { + use uuid::Uuid; + + use crate::model::sconcept::{SConcept, SContainmentLink, SProperty, SReferenceLink}; + + #[test] + fn test_sconcept() { + // given + let mut sconcept: SConcept = SConcept::new("FirstConcept".to_string(), Uuid::new_v4()); + let sproperty = SProperty::new("FirstProperty".to_string(), Uuid::new_v4()); + let reference_link = SReferenceLink::new("FirstLink".to_string(), Uuid::new_v4()); + let containment_link_1 = SContainmentLink::new("FirstContainment".to_string(), Uuid::new_v4()); + let containment_link_2 = SContainmentLink::new("SecondContainment".to_string(), Uuid::new_v4()); + + //when + sconcept.properties.insert("property".to_string(), sproperty); + sconcept.reference_links.insert("ref".to_string(), reference_link); + sconcept.containment_links.insert("child1".to_string(), containment_link_1); + sconcept.containment_links.insert("child2".to_string(), containment_link_2); + + //assert + assert_eq!(sconcept.properties.len(), 1); + assert_eq!(sconcept.reference_links.len(), 1); + assert_eq!(sconcept.containment_links.len(), 2); + } +} \ No newline at end of file diff --git a/mps-cli-rs/src/model/slanguage.rs b/mps-cli-rs/src/model/slanguage.rs new file mode 100644 index 0000000..3c3c897 --- /dev/null +++ b/mps-cli-rs/src/model/slanguage.rs @@ -0,0 +1,54 @@ +use uuid::Uuid; + +use crate::model::sconcept::SConcept; + +pub struct SLanguage { + name: String, + uuid: Uuid, + concepts: Vec, +} + +impl SLanguage { + pub fn new(name: String, uuid: Uuid) -> Self { + SLanguage { + name, + uuid, + concepts: vec![], + } + } + + pub fn find_concept_by_name(&self, concept_name: &str) -> Option<&SConcept> { + self.concepts.iter().find(|&concept| concept.name.eq(concept_name)) + } +} + +#[cfg(test)] +mod tests { + use uuid::Uuid; + + use crate::model::sconcept::SConcept; + use crate::model::slanguage::SLanguage; + + #[test] + fn test_find_concept_by_name() { + // given + let mut slanguage = SLanguage::new("FirstLanguage".to_string(), Uuid::new_v4()); + let first_concept_name = "FirstConcept"; + let first_concept: SConcept = SConcept::new(first_concept_name.to_string(), Uuid::new_v4()); + let second_concept_name = "SecondConcept"; + let second_concept = SConcept::new(second_concept_name.to_string(), Uuid::new_v4()); + slanguage.concepts.push(first_concept); + slanguage.concepts.push(second_concept); + + //when + let found_first_concept = slanguage.find_concept_by_name(first_concept_name); + let found_second_concept = slanguage.find_concept_by_name(second_concept_name); + let non_found_concept = slanguage.find_concept_by_name("ThirdConcept"); + + //assert + assert_eq!(slanguage.concepts.len(), 2); + assert_eq!(found_first_concept, slanguage.concepts.get(0), "First concept not found"); + assert_eq!(found_second_concept, slanguage.concepts.get(1), "Second concept not found"); + assert_eq!(non_found_concept, None); + } +} \ No newline at end of file diff --git a/mps-cli-rs/src/model/smodel.rs b/mps-cli-rs/src/model/smodel.rs new file mode 100644 index 0000000..e30726e --- /dev/null +++ b/mps-cli-rs/src/model/smodel.rs @@ -0,0 +1,38 @@ +use uuid::Uuid; + +use crate::model::snode::SNode; + +pub struct SModel<'a> { + name: String, + uuid: Uuid, + root_nodes: Vec>, + path_to_model_file: String, + is_do_not_generate: bool, + is_file_per_root_persistency: bool, +} + +impl<'a> SModel<'a> { + pub fn new(name: String, uuid: Uuid) -> Self { + SModel { + name, + uuid, + root_nodes: vec![], + path_to_model_file: "".to_string(), + is_do_not_generate: false, + is_file_per_root_persistency: true, + } + } + + pub fn get_nodes(&self) -> Vec<&SNode> { + let mut nodes: Vec<&SNode> = Vec::new(); + for root in &self.root_nodes { + nodes.push(&root); + nodes.extend(root.get_descendants(false)); + } + return nodes; + } + + pub fn get_node_by_uuid(&self, uuid: &Uuid) -> Option<&SNode> { + self.get_nodes().iter().find(|&node| node.uuid.eq(uuid)).copied() + } +} diff --git a/mps-cli-rs/src/model/snode.rs b/mps-cli-rs/src/model/snode.rs new file mode 100644 index 0000000..0edb891 --- /dev/null +++ b/mps-cli-rs/src/model/snode.rs @@ -0,0 +1,74 @@ +use std::collections::HashMap; + +use uuid::Uuid; + +use crate::model::sconcept::{SConcept, SContainmentLink, SProperty, SReferenceLink}; + +pub struct SNode<'a> { + pub(crate) uuid: Uuid, + concept: &'a SConcept, + role_in_parent: Option, + properties: HashMap<&'a SProperty, String>, + children: HashMap<&'a SContainmentLink, Vec>>, + references: HashMap<&'a SReferenceLink, &'a SNode<'a>>, + parent: Option<&'a SNode<'a>>, +} + +impl<'a> SNode<'a> { + pub fn new(uuid: Uuid, concept: &'a SConcept, role_in_parent: Option) -> Self { + SNode { + uuid, + concept, + role_in_parent, + properties: HashMap::new(), + children: HashMap::new(), + references: HashMap::new(), + parent: None, + } + } + + pub fn get_property(&self, property_name: &String) -> Option<&String> { + return match self.properties.keys().find(|&&key| key.name.eq(property_name)) { + Some(property) => self.properties.get(property), + None => None + }; + } + + pub fn add_property(&mut self, property: &'a SProperty, value: String) { + self.properties.insert(property, value); + } + + pub fn add_reference(&mut self, reference: &'a SReferenceLink, referenced_node: &'a SNode<'_>) { + self.references.insert(reference, referenced_node); + } + + pub fn get_reference(&self, name: &String) -> Option<&&SNode> { + return match self.references.keys().find(|&&refLink| refLink.name.eq(name)) { + None => None, + Some(reference_link) => self.references.get(reference_link) + }; + } + + pub fn get_children(&self, name: &String) -> Option<&Vec> { + return match self.children.keys().find(|&&containmetd_link| containmetd_link.name.eq(name)) { + None => None, + Some(containment_link) => self.children.get(containment_link) + }; + } + + pub fn get_descendants(&self, include_self: bool) -> Vec<&'a SNode> { + let mut descendants: Vec<&SNode> = Vec::new(); + if include_self { descendants.push(self) } + self.get_descendants_internal(&mut descendants); + return descendants; + } + + fn get_descendants_internal(&'a self, descendants: &mut Vec<&'a SNode<'a>>) { + for children in self.children.values() { + descendants.extend(children); + for child in children { + child.get_descendants_internal(descendants); + } + } + } +} \ No newline at end of file diff --git a/mps-cli-rs/src/model/snoderef.rs b/mps-cli-rs/src/model/snoderef.rs new file mode 100644 index 0000000..23a62fe --- /dev/null +++ b/mps-cli-rs/src/model/snoderef.rs @@ -0,0 +1,25 @@ +use uuid::Uuid; + +use crate::model::snode::SNode; +use crate::model::srepository::SRepository; + +struct SNodeRef { + model_uuid: Uuid, + node_uuid: Uuid, +} + +impl SNodeRef { + pub fn new(model_uuid: Uuid, node_uuid: Uuid) -> Self { + SNodeRef { + model_uuid, + node_uuid, + } + } + + pub fn resolve<'a>(&'a self, repository: &'a SRepository) -> Option<&SNode> { + return match repository.get_model_by_uuid(&self.model_uuid) { + None => None, + Some(model) => model.get_node_by_uuid(&self.node_uuid) + }; + } +} \ No newline at end of file diff --git a/mps-cli-rs/src/model/srepository.rs b/mps-cli-rs/src/model/srepository.rs new file mode 100644 index 0000000..0ebedca --- /dev/null +++ b/mps-cli-rs/src/model/srepository.rs @@ -0,0 +1,44 @@ +use std::collections::HashMap; + +use uuid::Uuid; + +use crate::model::slanguage::SLanguage; +use crate::model::smodel::SModel; +use crate::model::snode::SNode; +use crate::model::ssolution::SSolution; + +pub struct SRepository<'a> { + solutions: Vec>, + languages: Vec, + + models: Vec<&'a SModel<'a>>, + nodes: Vec<&'a SNode<'a>>, + id_2_models_cache: HashMap>, + id_2_nodes_cache: HashMap>, +} + +impl<'a> SRepository<'a> { + pub fn new(solutions: Vec>, languages: Vec) -> Self { + SRepository { + solutions, + languages, + models: vec![], + nodes: vec![], + id_2_models_cache: HashMap::new(), + id_2_nodes_cache: HashMap::new(), + } + } + + fn find_solution_by_name(&self, name: &String) -> Option<&SSolution> { + let found_solution = self.solutions.iter().find(|&ssolution| ssolution.name.eq(name)); + return found_solution; + } + + pub fn get_model_by_uuid(&self, uuid: &Uuid) -> Option<&SModel> { + None + } + + fn find_model_by_name(&self, name: &String) -> Option<&SModel> { + None + } +} \ No newline at end of file diff --git a/mps-cli-rs/src/model/ssolution.rs b/mps-cli-rs/src/model/ssolution.rs new file mode 100644 index 0000000..8284b5b --- /dev/null +++ b/mps-cli-rs/src/model/ssolution.rs @@ -0,0 +1,9 @@ +use uuid::Uuid; +use crate::model::smodel::SModel; + +pub struct SSolution<'a> { + pub name: String, + uuid: Uuid, + path_to_module_file: String, + models: Vec> +} \ No newline at end of file From 4f2e012e90e6a05fb868264225be47a3404d1ab3 Mon Sep 17 00:00:00 2001 From: Michael Langhammer Date: Sat, 23 Mar 2024 19:42:13 +0100 Subject: [PATCH 03/43] add rust builder for mpsr files --- mps-cli-py/.idea/workspace.xml | 10 +- mps-cli-rs/Cargo.lock | 130 ++++++++- mps-cli-rs/Cargo.toml | 6 +- mps-cli-rs/src/builder/builder_helper.rs | 60 ++++ mps-cli-rs/src/builder/mod.rs | 7 + .../root_node_from_mpsr_file_builder.rs | 1 + mps-cli-rs/src/builder/slanguage_builder.rs | 43 +++ ...model_builder_file_per_root_persistency.rs | 266 ++++++++++++++++++ .../builder/smodules_repository_builder.rs | 96 +++++++ mps-cli-rs/src/builder/ssolution_builder.rs | 107 +++++++ mps-cli-rs/src/builder/test_helper.rs | 36 +++ mps-cli-rs/src/main.rs | 1 + mps-cli-rs/src/model/mod.rs | 10 +- mps-cli-rs/src/model/sconcept.rs | 8 +- mps-cli-rs/src/model/slanguage.rs | 16 +- mps-cli-rs/src/model/smodel.rs | 24 +- mps-cli-rs/src/model/snode.rs | 8 +- mps-cli-rs/src/model/snoderef.rs | 8 +- mps-cli-rs/src/model/srepository.rs | 6 +- mps-cli-rs/src/model/ssolution.rs | 16 +- .../.model | 1 + 21 files changed, 807 insertions(+), 53 deletions(-) create mode 100644 mps-cli-rs/src/builder/builder_helper.rs create mode 100644 mps-cli-rs/src/builder/mod.rs create mode 100644 mps-cli-rs/src/builder/root_node_from_mpsr_file_builder.rs create mode 100644 mps-cli-rs/src/builder/slanguage_builder.rs create mode 100644 mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs create mode 100644 mps-cli-rs/src/builder/smodules_repository_builder.rs create mode 100644 mps-cli-rs/src/builder/ssolution_builder.rs create mode 100644 mps-cli-rs/src/builder/test_helper.rs diff --git a/mps-cli-py/.idea/workspace.xml b/mps-cli-py/.idea/workspace.xml index 120ee78..9f35e92 100644 --- a/mps-cli-py/.idea/workspace.xml +++ b/mps-cli-py/.idea/workspace.xml @@ -1,5 +1,8 @@ + + @@ -50,6 +53,7 @@ + + + + + + - diff --git a/mps-cli-rs/Cargo.lock b/mps-cli-rs/Cargo.lock index 0adf37d..c7f5dd7 100644 --- a/mps-cli-rs/Cargo.lock +++ b/mps-cli-rs/Cargo.lock @@ -2,10 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "builder" -version = "0.1.0" - [[package]] name = "cfg-if" version = "1.0.0" @@ -30,12 +26,95 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] -name = "mps-cli-rs" +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "mps_cli_rs" version = "0.1.0" dependencies = [ + "quick-xml", + "serde", "uuid", + "walkdir", ] +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-xml" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "2.0.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + [[package]] name = "uuid" version = "1.8.0" @@ -45,8 +124,49 @@ dependencies = [ "getrandom", ] +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/mps-cli-rs/Cargo.toml b/mps-cli-rs/Cargo.toml index 80867f1..a26d635 100644 --- a/mps-cli-rs/Cargo.toml +++ b/mps-cli-rs/Cargo.toml @@ -1,6 +1,5 @@ -workspace = { members = ["src/builder"] } [package] -name = "mps-cli-rs" +name = "mps_cli_rs" version = "0.1.0" edition = "2021" @@ -8,3 +7,6 @@ edition = "2021" [dependencies] uuid = { version = "1.8.0", features = ["v4"] } +quick-xml = { version = "0.31.0", features = ["serialize"] } +serde = { version = "1.0.197", features = ["derive"] } +walkdir = "2.5.0" \ No newline at end of file diff --git a/mps-cli-rs/src/builder/builder_helper.rs b/mps-cli-rs/src/builder/builder_helper.rs new file mode 100644 index 0000000..d8e2561 --- /dev/null +++ b/mps-cli-rs/src/builder/builder_helper.rs @@ -0,0 +1,60 @@ +use std::collections::{HashMap, HashSet}; +use std::fs::File; +use std::io::BufReader; +use std::path::PathBuf; + +use quick_xml::{Error, Reader}; +use quick_xml::events::attributes::Attributes; +use quick_xml::name::QName; + +pub(crate) fn panic_read_file(msd_file_reader: &mut Reader>, e: Error) { + panic!("Error at position {}: {:?}", msd_file_reader.buffer_position(), e) +} + +pub(crate) fn panic_unexpected_eof_read_file(msd_file_reader: &mut Reader>) { + panic!("Error at position {}: Unexpected EOF!", msd_file_reader.buffer_position()) +} + +pub(crate) fn convert_to_string(path_buf_to_msd_file: &PathBuf) -> String { + path_buf_to_msd_file.to_str().unwrap().to_string() +} + +pub(crate) fn get_value_of_attribute_with_key(attributes: Attributes, attribute_name: &str) -> Option { + get_values_of_attributes_with_keys(attributes, vec![attribute_name]).remove(attribute_name) +} + +pub(crate) fn get_values_of_attributes_with_keys(attributes: Attributes, attribute_names: Vec<&str>) -> HashMap { + let attribute_names_set: HashSet<&str> = attribute_names.into_iter().collect(); + let mut key_value_map = HashMap::new(); + for attribute in attributes { + let unwrapped_attribute = attribute.unwrap(); + let key = convert_qname_to_string(&unwrapped_attribute.key); + if attribute_names_set.contains(&key.as_str()) { + key_value_map.insert(key, unwrapped_attribute.unescape_value().unwrap().to_string()); + } + } + return key_value_map; +} + +pub(crate) fn convert_qname_to_string(qname: &QName) -> String { + String::from_utf8(qname.as_ref().to_vec()).unwrap() +} + +#[cfg(test)] +mod tests { + use quick_xml::name::QName; + + use crate::builder::builder_helper::convert_qname_to_string; + + #[test] + fn test_convert_qname_to_string() { + // given + let qname = QName("test_q_name".as_bytes()); + + //when + let converted_string = convert_qname_to_string(&qname); + + //assert + assert_eq!(converted_string, "test_q_name"); + } +} diff --git a/mps-cli-rs/src/builder/mod.rs b/mps-cli-rs/src/builder/mod.rs new file mode 100644 index 0000000..fa730ce --- /dev/null +++ b/mps-cli-rs/src/builder/mod.rs @@ -0,0 +1,7 @@ +pub mod smodules_repository_builder; +mod ssolution_builder; +mod smodel_builder_file_per_root_persistency; +mod builder_helper; +mod root_node_from_mpsr_file_builder; +mod test_helper; +mod slanguage_builder; diff --git a/mps-cli-rs/src/builder/root_node_from_mpsr_file_builder.rs b/mps-cli-rs/src/builder/root_node_from_mpsr_file_builder.rs new file mode 100644 index 0000000..fbe7048 --- /dev/null +++ b/mps-cli-rs/src/builder/root_node_from_mpsr_file_builder.rs @@ -0,0 +1 @@ +//fn parse_node(x: &Reader>, e: &BytesStart, buf: &mut Vec) -> SNode {} \ No newline at end of file diff --git a/mps-cli-rs/src/builder/slanguage_builder.rs b/mps-cli-rs/src/builder/slanguage_builder.rs new file mode 100644 index 0000000..1fdefbc --- /dev/null +++ b/mps-cli-rs/src/builder/slanguage_builder.rs @@ -0,0 +1,43 @@ +use std::collections::HashMap; +use std::sync::Mutex; + +use crate::model::sconcept::SConcept; +use crate::model::slanguage::SLanguage; + +pub(crate) static SLANGUAGE_BUILDER: Mutex = Mutex::new(SLanguageBuilder::new()); + +pub(crate) struct SLanguageBuilder { + language_id_to_slanguage: Option>, +} + +impl<'a> SLanguageBuilder { + pub(crate) const fn new() -> Self { + SLanguageBuilder { + language_id_to_slanguage: None, + } + } + + fn ensure_initialized(&mut self) -> &mut HashMap { + self.language_id_to_slanguage.get_or_insert(HashMap::new()) + } + + pub(crate) fn get_or_build_language(&mut self, language_id: &String, language_name: &String) -> &mut SLanguage { + let language_id_to_slanguage = self.ensure_initialized(); + language_id_to_slanguage.entry(language_id.to_string()).or_insert(SLanguage::new(language_name.to_string(), language_id.to_string())); + language_id_to_slanguage.get_mut(language_id).unwrap() + } + + pub(crate) fn get_or_create_concept_in_language(&mut self, language_id: &String, language_name: &String, concept_id: String, concept_name: String) -> &SConcept { + self.ensure_initialized(); + let language: &mut SLanguage = self.get_or_build_language(language_id, language_name); + if language.find_concept_by_name(&concept_name).is_none() { + language.add_concept(SConcept::new(&concept_name, concept_id)); + } + return language.find_concept_by_name(&concept_name).unwrap(); + } +} + + + + + diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs new file mode 100644 index 0000000..e678c26 --- /dev/null +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -0,0 +1,266 @@ +use std::collections::HashMap; +use std::fs::File; +use std::io::BufReader; +use std::path::PathBuf; +use std::sync::Mutex; + +use quick_xml::events::Event; +use quick_xml::Reader; +use walkdir::{DirEntry, WalkDir}; + +use crate::builder::builder_helper::{convert_to_string, get_value_of_attribute_with_key, get_values_of_attributes_with_keys, panic_read_file, panic_unexpected_eof_read_file}; +use crate::builder::slanguage_builder::SLANGUAGE_BUILDER; +use crate::model::sconcept::{SConcept, SProperty}; +use crate::model::smodel::SModel; +use crate::model::snode::SNode; + +static SMODEL_BUILDER_CACHE: Mutex = Mutex::new(SModelBuilderCache::new()); + +pub struct SModelBuilderCache<'a> { + pub index_2_concept: Option>, + pub index_2_property: Option>, + pub index_2_imported_model_uuid: Option>, +} + +impl<'a> SModelBuilderCache<'a> { + const fn new() -> Self { + SModelBuilderCache { + index_2_concept: None, + index_2_property: None, + index_2_imported_model_uuid: None, + } + } + + fn get_index_2_concept(&mut self) -> &mut HashMap { + self.index_2_concept.get_or_insert(HashMap::new()) + } + + fn get_index_2_property(&mut self) -> &mut HashMap { + self.index_2_property.get_or_insert(HashMap::new()) + } + + fn get_index_2_imported_model_uuid(&mut self) -> &mut HashMap { + self.index_2_imported_model_uuid.get_or_insert(HashMap::new()) + } +} + +pub struct SModelBuilderFilePerRootPersistency {} + +impl SModelBuilderFilePerRootPersistency { + pub(crate) fn new() -> Self { + SModelBuilderFilePerRootPersistency {} + } + pub(crate) fn build_model(&mut self, path_to_model: PathBuf) -> SModel { + let mut model_file = path_to_model.clone(); + model_file.push(".model"); + let mut model: SModel = Self::extract_model_core_info(model_file); + + let mpsr_file_walker = WalkDir::new(path_to_model).min_depth(1).max_depth(1); + let mpsr_files = mpsr_file_walker.into_iter().filter(|entry| { + if entry.is_ok() { + let dir_entry = entry.as_ref().unwrap(); + let extension = dir_entry.path().extension(); + return dir_entry.file_type().is_file() && extension.is_some_and(|e| e.eq("mpsr")); + } + return false; + }); + mpsr_files.into_iter().for_each(|mpsr_file| { + let root_node = self.build_root_node_from_file(mpsr_file.unwrap()); + model.root_nodes.push(root_node); + }); + + return model; + } + + fn extract_model_core_info<'a>(path_to_model: PathBuf) -> SModel<'a> { + let mut model_file_reader = Reader::from_file(path_to_model.clone()).unwrap(); + let mut name = String::new(); + let mut uuid = String::new(); + let mut is_do_not_generate = false; + let mut buf = vec![]; + let mut model_found = false; + let mut do_not_gen_found = false; + while !(do_not_gen_found && model_found) { + match model_file_reader.read_event_into(&mut buf) { + Ok(Event::Start(ref e)) => { + match e.name().as_ref() { + b"model" => { + let value = get_value_of_attribute_with_key(e.attributes(), "ref").unwrap(); + let index = value.find("(").unwrap(); + uuid = value[..index].to_string(); + name = value[index + 1..value.len() - 1].to_string(); + model_found = true; + } + _ => {} + } + } + Ok(Event::Empty(ref e)) => { + if e.name().as_ref() == b"attribute" { + let attribute_name = get_value_of_attribute_with_key(e.attributes(), "name"); + if attribute_name.is_some() && attribute_name.unwrap().eq("doNotGenerate") { + let value = get_value_of_attribute_with_key(e.attributes(), "value").unwrap(); + is_do_not_generate = value.eq("true"); + do_not_gen_found = true; + } + } + } + Ok(Event::Eof) => break, + Err(e) => panic_read_file(&mut model_file_reader, e), + _ => {} + } + } + return SModel::new(name, uuid, convert_to_string(&path_to_model), is_do_not_generate, true); + } + + fn build_root_node_from_file(&mut self, dir_entry: DirEntry) -> SNode { + let mut mpsr_reader = Reader::from_file(dir_entry.path()).unwrap(); + let mut buf = vec![]; + let mut root_node = None; + loop { + match mpsr_reader.read_event_into(&mut buf) { + Ok(Event::Start(ref e)) => match e.name().as_ref() { + b"imports" => self.parse_imports(&mut mpsr_reader), + b"registry" => self.parse_registry(&mut mpsr_reader), + b"node" => { + //root_node = Some(parse_node(&mpsr_reader, e, &mut buf)) + } + _ => {} + }, + Ok(Event::Eof) => break, + Err(e) => panic_read_file(&mut mpsr_reader, e), + _ => {} + } + } + return root_node.unwrap(); + } + + fn parse_imports(&mut self, mpsr_reader: &mut Reader>) { + let mut child_buf = vec![]; + loop { + match mpsr_reader.read_event_into(&mut child_buf) { + Ok(Event::Empty(e)) => { + let key_values = get_values_of_attributes_with_keys(e.attributes(), vec!["index", "ref"]); + if let Some(imported_model_ref) = key_values.get("ref") { + let index = imported_model_ref.find("(").unwrap(); + let imported_model_uuid = imported_model_ref[..index].to_string(); + if let Some(index_value) = key_values.get("index") { + SMODEL_BUILDER_CACHE.lock().unwrap().get_index_2_imported_model_uuid().insert(index_value.to_string(), imported_model_uuid); + } + } + } + Ok(Event::End(e)) => { + match e.name().as_ref() { + b"imports" => break, + _ => {} + } + } + Ok(Event::Eof) => panic_unexpected_eof_read_file(mpsr_reader), + Err(e) => panic_read_file(mpsr_reader, e), + _ => {} + } + } + } + + fn parse_registry(&mut self, mpsr_reader: &mut Reader>) { + let mut child_buf = vec![]; + loop { + match mpsr_reader.read_event_into(&mut child_buf) { + Ok(Event::Empty(e)) => { + match e.name().as_ref() { + b"language" => { + let id_name_attributes = get_values_of_attributes_with_keys(e.attributes(), vec!["id", "name"]); + let id = id_name_attributes.get("id").unwrap(); + let name = id_name_attributes.get("name").unwrap(); + self.parse_concept(mpsr_reader, id, name); + } + + _ => {} + } + } + Ok(Event::End(e)) => { + match e.name().as_ref() { + b"registry" => break, + _ => {} + } + } + Ok(Event::Eof) => panic_unexpected_eof_read_file(mpsr_reader), + Err(e) => panic_read_file(mpsr_reader, e), + _ => {} + } + } + } + + fn parse_concept(&mut self, mpsr_reader: &mut Reader>, language_id: &String, language_name: &String) { + let mut concept_buf = vec![]; + + loop { + match mpsr_reader.read_event_into(&mut concept_buf) { + Ok(Event::Empty(e)) => { + match e.name().as_ref() { + b"concept" => { + let mut id_map_index_map = get_values_of_attributes_with_keys(e.attributes(), vec!["id", "name", "index"]); + let concept_id = id_map_index_map.remove("id").unwrap(); + let concept_name = id_map_index_map.remove("name").unwrap(); + let mut language_builder = SLANGUAGE_BUILDER.lock().unwrap(); + let concept: &SConcept = language_builder.get_or_create_concept_in_language(language_id, language_name, concept_id, concept_name); + SMODEL_BUILDER_CACHE.lock().unwrap().get_index_2_concept().insert(id_map_index_map.remove("index").unwrap(), concept); + } + + _ => {} + } + } + Ok(Event::End(e)) => { + match e.name().as_ref() { + b"concept" => break, + _ => {} + } + } + Ok(Event::Eof) => panic_unexpected_eof_read_file(mpsr_reader), + Err(e) => panic_read_file(mpsr_reader, e), + _ => {} + } + } + } +} + +#[cfg(test)] +mod tests { + use std::path::PathBuf; + + use crate::builder::smodel_builder_file_per_root_persistency::{SMODEL_BUILDER_CACHE, SModelBuilderFilePerRootPersistency}; + use crate::builder::test_helper::{get_path_to_model_mpsr_example_lib_file, get_path_to_mpsr_example_lib_file}; + use crate::builder::test_helper::get_path_to_example_mpsr_model_files; + + #[test] + fn test_model_extract_core_info() { + // given + let path_to_model_file = PathBuf::from(get_path_to_mpsr_example_lib_file()); + + //when + let model = SModelBuilderFilePerRootPersistency::extract_model_core_info(path_to_model_file); + + //assert + assert_eq!(model.name, "mps.cli.lanuse.library_top.library_top"); + assert_eq!(model.uuid, "r:a96b23f6-56db-490c-a218-d40d11be7f1e"); + assert_eq!(model.path_to_model_file, get_path_to_model_mpsr_example_lib_file()); + assert_eq!(model.is_do_not_generate, true); + assert!(model.is_file_per_root_persistency); + } + + #[test] + fn test_build_model() { + // given + let path_to_mpsr_file = PathBuf::from(get_path_to_example_mpsr_model_files()); + + //when + let mut smodel_builder = SModelBuilderFilePerRootPersistency::new(); + smodel_builder.build_model(path_to_mpsr_file); + + //assert + assert_eq!(SMODEL_BUILDER_CACHE.lock().unwrap().get_index_2_imported_model_uuid().len(), 1); + assert!(SMODEL_BUILDER_CACHE.lock().unwrap().get_index_2_imported_model_uuid().contains_key(&"q0v6".to_string())); + let mut binding = SMODEL_BUILDER_CACHE.lock().unwrap(); + let imported_model_uuid = binding.get_index_2_imported_model_uuid().get(&"q0v6".to_string()).unwrap(); + assert_eq!(**imported_model_uuid, "ec5f093b-9d83-43a1-9b41-b5952da8b1ed".to_string()); + } +} diff --git a/mps-cli-rs/src/builder/smodules_repository_builder.rs b/mps-cli-rs/src/builder/smodules_repository_builder.rs new file mode 100644 index 0000000..fd8466f --- /dev/null +++ b/mps-cli-rs/src/builder/smodules_repository_builder.rs @@ -0,0 +1,96 @@ +use std::path::PathBuf; +use std::time::Instant; + +use walkdir::WalkDir; + +use crate::builder::ssolution_builder::build_solution; +use crate::model::srepository::SRepository; +use crate::model::ssolution::SSolution; + +pub fn build_repo_from_all<'a>(source_dirs: Vec) -> SRepository<'a> { + let mut all_solutions = Vec::new(); + for source_dir in source_dirs { + println!("loading models from directory: {}", source_dir); + let solutions = build_solutions_from(source_dir); + all_solutions.extend(solutions); + } + return SRepository::new(all_solutions, vec![]); +} + + +pub fn build_repo_from<'a>(source_dir: String) -> SRepository<'a> { + let solutions = build_solutions_from(source_dir); + return SRepository::new(solutions, vec![]); +} + +fn build_solutions_from<'a>(source_dir: String) -> Vec> { + let now = Instant::now(); + + let solutions = collect_modules_from_sources(source_dir.clone()); + + let elapsed = now.elapsed(); + println!("{} milli seconds for handling {}", elapsed.as_millis(), source_dir); + + return solutions; +} + +pub fn collect_modules_from_sources<'a>(source_dir: String) -> Vec> { + let msd_files = find_msd_files(&source_dir, 3); + let solutions: Vec = msd_files.iter().map(|msd_file| build_solution(msd_file)).collect(); + return solutions; +} + +pub fn find_msd_files(source_dir: &String, start_depth: usize) -> Vec { + let walk_dir: WalkDir = WalkDir::new(source_dir).max_depth(start_depth); + let mut msd_files = Vec::new(); + for entry in walk_dir.into_iter() { + let dir_entry = entry.unwrap(); + let path_buf = dir_entry.into_path(); + if let Some(ext) = path_buf.extension() { + if ext == "msd" { + msd_files.push(path_buf) + } + } + } + return msd_files; +} + + +#[cfg(test)] +mod tests { + use crate::builder::smodules_repository_builder::{build_repo_from, find_msd_files}; + use crate::builder::test_helper::get_path_to_mps_cli_lanuse_file_per_root; + use crate::model::smodel::SModel; + + #[test] + fn test_find_msd_files() { + //given + let src_dir = get_path_to_mps_cli_lanuse_file_per_root(); + + //when + let msd_files = find_msd_files(&src_dir, 3); + + //then + assert_eq!(msd_files.len(), 2); + } + + #[test] + fn smoke_test_build_repo_from() { + //given + let src_dir = get_path_to_mps_cli_lanuse_file_per_root(); + + use std::time::Instant; + let now = Instant::now(); + //when + let repository = build_repo_from(src_dir); + + //then + let required_time = now.elapsed().as_millis(); + let models: Vec<&SModel> = repository.solutions.iter().flat_map(|solution| &solution.models).collect(); + let do_not_gen_models: Vec<&&SModel> = models.iter().filter(|&model| model.is_do_not_generate).collect(); + println!("Found {} solutions with {} models (out of which {} are set to do not generate) in {} ms", repository.solutions.len(), models.len(), do_not_gen_models.len(), required_time); + assert!(repository.solutions.len() > 1); + assert!(models.len() > 1); + assert_eq!(do_not_gen_models.len(), 1); + } +} \ No newline at end of file diff --git a/mps-cli-rs/src/builder/ssolution_builder.rs b/mps-cli-rs/src/builder/ssolution_builder.rs new file mode 100644 index 0000000..2f7379d --- /dev/null +++ b/mps-cli-rs/src/builder/ssolution_builder.rs @@ -0,0 +1,107 @@ +use std::path::PathBuf; + +use quick_xml::events::Event; +use quick_xml::name::QName; +use quick_xml::Reader; +use walkdir::WalkDir; + +use crate::builder::builder_helper::convert_to_string; +use crate::builder::builder_helper::panic_read_file; +use crate::builder::smodel_builder_file_per_root_persistency::SModelBuilderFilePerRootPersistency; +use crate::model::ssolution::SSolution; + +pub fn build_solution<'a>(path_buf_to_msd_file: &PathBuf) -> SSolution<'a> { + let path_to_msd_file = convert_to_string(&path_buf_to_msd_file); + let mut solution: SSolution = extract_solution_core_info(path_to_msd_file); + println!("Building from solution {}", solution.name); + + let solution_dir = path_buf_to_msd_file.parent().unwrap(); + let model_dir = convert_to_string(&solution_dir.to_path_buf()) + "/models"; + + let model_dir = WalkDir::new(model_dir).min_depth(1).max_depth(1); + for model_entry in model_dir.into_iter() { + let path = model_entry.unwrap().into_path(); + if path.is_dir() { + let mut smodel_builder = SModelBuilderFilePerRootPersistency::new(); + let model = smodel_builder.build_model(path); + //solution.models.push(model) + } else { + println!("ERROR: model entry {} is a file not a directory. Cannot be parsed as only file per root persistency is supported.", path.to_str().unwrap().to_string()) + } + } + + return solution; +} + +fn extract_solution_core_info<'a>(path_to_msd_file: String) -> SSolution<'a> { + //let solution_file = SolutionFile::new(&path_to_msd_file); + let mut msd_file_reader = Reader::from_file(&path_to_msd_file).unwrap(); + let mut buf = Vec::new(); + let mut name: String = "".to_string(); + let mut uuid: String = "".to_string(); + loop { + match msd_file_reader.read_event_into(&mut buf) { + Ok(Event::Start(e)) => { + match e.name().as_ref() { + b"solution" => { + for attribute in e.attributes() { + let attribute = attribute.unwrap(); + match attribute.key { + QName(b"name") => { name = attribute.unescape_value().unwrap().to_string() } + QName(b"uuid") => { uuid = attribute.unescape_value().unwrap().to_string() } + QName(_) => {} + } + } + break; + } + _ => {} + } + } + Err(e) => panic_read_file(&mut msd_file_reader, e), + _ => {} + } + } + return SSolution::new(name, uuid, path_to_msd_file.clone()); +} + +#[cfg(test)] +mod tests { + use crate::builder::builder_helper::convert_to_string; + use crate::builder::smodules_repository_builder::find_msd_files; + use crate::builder::ssolution_builder::extract_solution_core_info; + use crate::builder::test_helper::{get_path_to_mps_cli_lanuse_file_per_root, get_path_to_mps_cli_lanuse_library_top_msd_file}; + + #[test] + fn test_extract_core_info() { + // given + let path_to_msd_file = get_path_to_mps_cli_lanuse_library_top_msd_file(); + + //when + let solution = extract_solution_core_info(path_to_msd_file); + + //assert + assert_eq!(solution.name, "mps.cli.lanuse.library_top"); + assert_eq!(solution.uuid, "f1017d72-b2a4-4f19-9b27-1327f37f5b09"); + } + + #[test] + fn smoke_test_extract_core_info_for_solutions() { + //given + let path_to_test_project = get_path_to_mps_cli_lanuse_file_per_root(); + + use std::time::Instant; + let now = Instant::now(); + //when + let msd_files = find_msd_files(&path_to_test_project, 3); + let mut solutions = vec![]; + for msd_file in &msd_files { + let solution = extract_solution_core_info(convert_to_string(&msd_file)); + solutions.push(solution); + } + + //then + println!("Found {} msd files and parsed them in {} solutions in {} ms", msd_files.len(), solutions.len(), now.elapsed().as_millis()); + assert!(msd_files.len() > 1); + assert!(solutions.len() > 1); + } +} \ No newline at end of file diff --git a/mps-cli-rs/src/builder/test_helper.rs b/mps-cli-rs/src/builder/test_helper.rs new file mode 100644 index 0000000..0312882 --- /dev/null +++ b/mps-cli-rs/src/builder/test_helper.rs @@ -0,0 +1,36 @@ +const MPSR_TOP_MODEL_PATH: &'static str = "/models/mps.cli.lanuse.library_top.library_top"; +const MPSR_SOLUTION_MPS_CLI_LANUSE_LIBRARY_TOP_: &'static str = "/solutions/mps.cli.lanuse.library_top"; +const MPSR_FILE_PATH: &'static str = "/munich_library.mpsr"; +const PATH_TO_MPS_TEST_PROJECTS: &'static str = "../mps_test_projects"; +const PATH_TO_FILE_PER_ROOT_PROJECT: &'static str = "/mps_cli_lanuse_file_per_root"; +const MPSR_MODEL_FILE_NAME: &'static str = "/.model"; +const MPS_CLI_LANUSE_LIBRARY_TOP_MSD: &'static str = "/mps.cli.lanuse.library_top.msd"; + +fn get_path_to_test_projects() -> String { + String::from(PATH_TO_MPS_TEST_PROJECTS) +} + + +pub fn get_path_to_mps_cli_lanuse_file_per_root() -> String { + get_path_to_test_projects() + PATH_TO_FILE_PER_ROOT_PROJECT +} + +fn get_path_to_mpsr_solution() -> String { + get_path_to_mps_cli_lanuse_file_per_root() + MPSR_SOLUTION_MPS_CLI_LANUSE_LIBRARY_TOP_ +} + +pub fn get_path_to_mpsr_example_lib_file() -> String { + get_path_to_example_mpsr_model_files() + MPSR_FILE_PATH +} + +pub fn get_path_to_example_mpsr_model_files() -> String { + get_path_to_mpsr_solution() + MPSR_TOP_MODEL_PATH +} + +pub fn get_path_to_model_mpsr_example_lib_file() -> String { + get_path_to_mpsr_solution() + MPSR_TOP_MODEL_PATH + MPSR_MODEL_FILE_NAME +} + +pub fn get_path_to_mps_cli_lanuse_library_top_msd_file() -> String { + get_path_to_mpsr_solution() + MPS_CLI_LANUSE_LIBRARY_TOP_MSD +} \ No newline at end of file diff --git a/mps-cli-rs/src/main.rs b/mps-cli-rs/src/main.rs index ccdc71c..e1a7927 100644 --- a/mps-cli-rs/src/main.rs +++ b/mps-cli-rs/src/main.rs @@ -1,4 +1,5 @@ mod model; +mod builder; fn main() { println!("Hello, world!"); diff --git a/mps-cli-rs/src/model/mod.rs b/mps-cli-rs/src/model/mod.rs index 5092e45..6d24907 100644 --- a/mps-cli-rs/src/model/mod.rs +++ b/mps-cli-rs/src/model/mod.rs @@ -1,7 +1,7 @@ pub mod sconcept; -mod slanguage; -mod smodel; -mod snode; +pub mod slanguage; +pub mod smodel; +pub mod snode; mod snoderef; -mod ssolution; -mod srepository; \ No newline at end of file +pub mod ssolution; +pub mod srepository; \ No newline at end of file diff --git a/mps-cli-rs/src/model/sconcept.rs b/mps-cli-rs/src/model/sconcept.rs index 844baa6..792b583 100644 --- a/mps-cli-rs/src/model/sconcept.rs +++ b/mps-cli-rs/src/model/sconcept.rs @@ -5,7 +5,7 @@ use uuid::Uuid; #[derive(Debug, PartialEq)] pub struct SConcept { pub(crate) name: String, - uuid: Uuid, + uuid: String, pub(crate) properties: HashMap, containment_links: HashMap, reference_links: HashMap, @@ -30,9 +30,9 @@ pub struct SReferenceLink { } impl SConcept { - pub fn new(name: String, uuid: Uuid) -> Self { + pub fn new(name: &String, uuid: String) -> Self { SConcept { - name, + name: name.to_string(), uuid, properties: HashMap::new(), containment_links: HashMap::new(), @@ -92,7 +92,7 @@ mod tests { #[test] fn test_sconcept() { // given - let mut sconcept: SConcept = SConcept::new("FirstConcept".to_string(), Uuid::new_v4()); + let mut sconcept: SConcept = SConcept::new(&"FirstConcept".to_string(), Uuid::new_v4().to_string()); let sproperty = SProperty::new("FirstProperty".to_string(), Uuid::new_v4()); let reference_link = SReferenceLink::new("FirstLink".to_string(), Uuid::new_v4()); let containment_link_1 = SContainmentLink::new("FirstContainment".to_string(), Uuid::new_v4()); diff --git a/mps-cli-rs/src/model/slanguage.rs b/mps-cli-rs/src/model/slanguage.rs index 3c3c897..36a4f76 100644 --- a/mps-cli-rs/src/model/slanguage.rs +++ b/mps-cli-rs/src/model/slanguage.rs @@ -1,15 +1,13 @@ -use uuid::Uuid; - use crate::model::sconcept::SConcept; pub struct SLanguage { name: String, - uuid: Uuid, + uuid: String, concepts: Vec, } impl SLanguage { - pub fn new(name: String, uuid: Uuid) -> Self { + pub fn new(name: String, uuid: String) -> Self { SLanguage { name, uuid, @@ -20,6 +18,10 @@ impl SLanguage { pub fn find_concept_by_name(&self, concept_name: &str) -> Option<&SConcept> { self.concepts.iter().find(|&concept| concept.name.eq(concept_name)) } + + pub fn add_concept(&mut self, concept: SConcept) { + self.concepts.push(concept); + } } #[cfg(test)] @@ -32,11 +34,11 @@ mod tests { #[test] fn test_find_concept_by_name() { // given - let mut slanguage = SLanguage::new("FirstLanguage".to_string(), Uuid::new_v4()); + let mut slanguage = SLanguage::new("FirstLanguage".to_string(), Uuid::new_v4().to_string()); let first_concept_name = "FirstConcept"; - let first_concept: SConcept = SConcept::new(first_concept_name.to_string(), Uuid::new_v4()); + let first_concept: SConcept = SConcept::new(&first_concept_name.to_string(), Uuid::new_v4().to_string()); let second_concept_name = "SecondConcept"; - let second_concept = SConcept::new(second_concept_name.to_string(), Uuid::new_v4()); + let second_concept = SConcept::new(&second_concept_name.to_string(), Uuid::new_v4().to_string()); slanguage.concepts.push(first_concept); slanguage.concepts.push(second_concept); diff --git a/mps-cli-rs/src/model/smodel.rs b/mps-cli-rs/src/model/smodel.rs index e30726e..fa781fa 100644 --- a/mps-cli-rs/src/model/smodel.rs +++ b/mps-cli-rs/src/model/smodel.rs @@ -1,25 +1,23 @@ -use uuid::Uuid; - use crate::model::snode::SNode; pub struct SModel<'a> { - name: String, - uuid: Uuid, - root_nodes: Vec>, - path_to_model_file: String, - is_do_not_generate: bool, - is_file_per_root_persistency: bool, + pub name: String, + pub uuid: String, + pub root_nodes: Vec>, + pub path_to_model_file: String, + pub is_do_not_generate: bool, + pub is_file_per_root_persistency: bool, } impl<'a> SModel<'a> { - pub fn new(name: String, uuid: Uuid) -> Self { + pub fn new(name: String, uuid: String, path_to_model_file: String, is_do_not_generate: bool, is_file_per_root_persistency: bool) -> Self { SModel { name, uuid, root_nodes: vec![], - path_to_model_file: "".to_string(), - is_do_not_generate: false, - is_file_per_root_persistency: true, + path_to_model_file, + is_do_not_generate, + is_file_per_root_persistency, } } @@ -32,7 +30,7 @@ impl<'a> SModel<'a> { return nodes; } - pub fn get_node_by_uuid(&self, uuid: &Uuid) -> Option<&SNode> { + pub fn get_node_by_uuid(&self, uuid: &String) -> Option<&SNode> { self.get_nodes().iter().find(|&node| node.uuid.eq(uuid)).copied() } } diff --git a/mps-cli-rs/src/model/snode.rs b/mps-cli-rs/src/model/snode.rs index 0edb891..d1051ff 100644 --- a/mps-cli-rs/src/model/snode.rs +++ b/mps-cli-rs/src/model/snode.rs @@ -1,11 +1,9 @@ use std::collections::HashMap; -use uuid::Uuid; - use crate::model::sconcept::{SConcept, SContainmentLink, SProperty, SReferenceLink}; pub struct SNode<'a> { - pub(crate) uuid: Uuid, + pub(crate) uuid: String, concept: &'a SConcept, role_in_parent: Option, properties: HashMap<&'a SProperty, String>, @@ -15,7 +13,7 @@ pub struct SNode<'a> { } impl<'a> SNode<'a> { - pub fn new(uuid: Uuid, concept: &'a SConcept, role_in_parent: Option) -> Self { + pub fn new(uuid: String, concept: &'a SConcept, role_in_parent: Option) -> Self { SNode { uuid, concept, @@ -43,7 +41,7 @@ impl<'a> SNode<'a> { } pub fn get_reference(&self, name: &String) -> Option<&&SNode> { - return match self.references.keys().find(|&&refLink| refLink.name.eq(name)) { + return match self.references.keys().find(|&&ref_link| ref_link.name.eq(name)) { None => None, Some(reference_link) => self.references.get(reference_link) }; diff --git a/mps-cli-rs/src/model/snoderef.rs b/mps-cli-rs/src/model/snoderef.rs index 23a62fe..754d084 100644 --- a/mps-cli-rs/src/model/snoderef.rs +++ b/mps-cli-rs/src/model/snoderef.rs @@ -1,15 +1,13 @@ -use uuid::Uuid; - use crate::model::snode::SNode; use crate::model::srepository::SRepository; struct SNodeRef { - model_uuid: Uuid, - node_uuid: Uuid, + model_uuid: String, + node_uuid: String, } impl SNodeRef { - pub fn new(model_uuid: Uuid, node_uuid: Uuid) -> Self { + pub fn new(model_uuid: String, node_uuid: String) -> Self { SNodeRef { model_uuid, node_uuid, diff --git a/mps-cli-rs/src/model/srepository.rs b/mps-cli-rs/src/model/srepository.rs index 0ebedca..b8a4794 100644 --- a/mps-cli-rs/src/model/srepository.rs +++ b/mps-cli-rs/src/model/srepository.rs @@ -8,7 +8,7 @@ use crate::model::snode::SNode; use crate::model::ssolution::SSolution; pub struct SRepository<'a> { - solutions: Vec>, + pub solutions: Vec>, languages: Vec, models: Vec<&'a SModel<'a>>, @@ -34,8 +34,8 @@ impl<'a> SRepository<'a> { return found_solution; } - pub fn get_model_by_uuid(&self, uuid: &Uuid) -> Option<&SModel> { - None + pub fn get_model_by_uuid(&self, uuid: &String) -> Option<&&SModel> { + self.models.iter().find(|&model| model.uuid.eq(uuid)) } fn find_model_by_name(&self, name: &String) -> Option<&SModel> { diff --git a/mps-cli-rs/src/model/ssolution.rs b/mps-cli-rs/src/model/ssolution.rs index 8284b5b..41d441a 100644 --- a/mps-cli-rs/src/model/ssolution.rs +++ b/mps-cli-rs/src/model/ssolution.rs @@ -1,9 +1,19 @@ -use uuid::Uuid; use crate::model::smodel::SModel; pub struct SSolution<'a> { pub name: String, - uuid: Uuid, + pub uuid: String, path_to_module_file: String, - models: Vec> + pub models: Vec>, +} + +impl<'a> SSolution<'a> { + pub fn new(name: String, uuid: String, path_to_module_file: String) -> Self { + SSolution { + name, + uuid, + path_to_module_file, + models: vec![], + } + } } \ No newline at end of file diff --git a/mps_test_projects/mps_cli_lanuse_file_per_root/solutions/mps.cli.lanuse.library_top/models/mps.cli.lanuse.library_top.library_top/.model b/mps_test_projects/mps_cli_lanuse_file_per_root/solutions/mps.cli.lanuse.library_top/models/mps.cli.lanuse.library_top.library_top/.model index 5ecb8bf..4266157 100644 --- a/mps_test_projects/mps_cli_lanuse_file_per_root/solutions/mps.cli.lanuse.library_top/models/mps.cli.lanuse.library_top.library_top/.model +++ b/mps_test_projects/mps_cli_lanuse_file_per_root/solutions/mps.cli.lanuse.library_top/models/mps.cli.lanuse.library_top.library_top/.model @@ -2,6 +2,7 @@ + From bda80a42b79a03da2596baab83db9727e1e6f853 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Fri, 10 May 2024 10:15:53 +0200 Subject: [PATCH 04/43] mps-cli-rs: slight improvements --- .../smodel_builder_file_per_root_persistency.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index e678c26..ddb7945 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -50,6 +50,7 @@ impl SModelBuilderFilePerRootPersistency { pub(crate) fn new() -> Self { SModelBuilderFilePerRootPersistency {} } + pub(crate) fn build_model(&mut self, path_to_model: PathBuf) -> SModel { let mut model_file = path_to_model.clone(); model_file.push(".model"); @@ -64,10 +65,12 @@ impl SModelBuilderFilePerRootPersistency { } return false; }); - mpsr_files.into_iter().for_each(|mpsr_file| { - let root_node = self.build_root_node_from_file(mpsr_file.unwrap()); - model.root_nodes.push(root_node); + + let roots = mpsr_files.into_iter().map(|mpsr_file| { + let file = mpsr_file.unwrap(); + self.build_root_node_from_file(file) }); + model.root_nodes.extend(roots); return model; } @@ -112,7 +115,7 @@ impl SModelBuilderFilePerRootPersistency { return SModel::new(name, uuid, convert_to_string(&path_to_model), is_do_not_generate, true); } - fn build_root_node_from_file(&mut self, dir_entry: DirEntry) -> SNode { + fn build_root_node_from_file(&self, dir_entry: DirEntry) -> SNode { let mut mpsr_reader = Reader::from_file(dir_entry.path()).unwrap(); let mut buf = vec![]; let mut root_node = None; @@ -134,7 +137,7 @@ impl SModelBuilderFilePerRootPersistency { return root_node.unwrap(); } - fn parse_imports(&mut self, mpsr_reader: &mut Reader>) { + fn parse_imports(&self, mpsr_reader: &mut Reader>) { let mut child_buf = vec![]; loop { match mpsr_reader.read_event_into(&mut child_buf) { @@ -161,7 +164,7 @@ impl SModelBuilderFilePerRootPersistency { } } - fn parse_registry(&mut self, mpsr_reader: &mut Reader>) { + fn parse_registry(&self, mpsr_reader: &mut Reader>) { let mut child_buf = vec![]; loop { match mpsr_reader.read_event_into(&mut child_buf) { @@ -190,7 +193,7 @@ impl SModelBuilderFilePerRootPersistency { } } - fn parse_concept(&mut self, mpsr_reader: &mut Reader>, language_id: &String, language_name: &String) { + fn parse_concept(&self, mpsr_reader: &mut Reader>, language_id: &String, language_name: &String) { let mut concept_buf = vec![]; loop { From 084c2097409e59ea02cd0b7ddb86b3d463065437 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Fri, 17 May 2024 08:14:32 +0200 Subject: [PATCH 05/43] first working version --- mps-cli-rs/Cargo.lock | 7 + mps-cli-rs/Cargo.toml | 3 +- mps-cli-rs/src/builder/mod.rs | 4 +- mps-cli-rs/src/builder/slanguage_builder.rs | 58 ++- ...model_builder_file_per_root_persistency.rs | 384 ++++++++++-------- .../builder/smodules_repository_builder.rs | 56 ++- mps-cli-rs/src/builder/ssolution_builder.rs | 13 +- mps-cli-rs/src/main.rs | 11 +- mps-cli-rs/src/model/sconcept.rs | 66 ++- mps-cli-rs/src/model/slanguage.rs | 37 +- mps-cli-rs/src/model/smodel.rs | 14 +- mps-cli-rs/src/model/snode.rs | 83 ++-- mps-cli-rs/src/model/snoderef.rs | 17 +- mps-cli-rs/src/model/srepository.rs | 49 +-- 14 files changed, 447 insertions(+), 355 deletions(-) diff --git a/mps-cli-rs/Cargo.lock b/mps-cli-rs/Cargo.lock index c7f5dd7..28a3b12 100644 --- a/mps-cli-rs/Cargo.lock +++ b/mps-cli-rs/Cargo.lock @@ -36,6 +36,7 @@ name = "mps_cli_rs" version = "0.1.0" dependencies = [ "quick-xml", + "roxmltree", "serde", "uuid", "walkdir", @@ -69,6 +70,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "roxmltree" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cd14fd5e3b777a7422cca79358c57a8f6e3a703d9ac187448d0daf220c2407f" + [[package]] name = "same-file" version = "1.0.6" diff --git a/mps-cli-rs/Cargo.toml b/mps-cli-rs/Cargo.toml index a26d635..1d2cd85 100644 --- a/mps-cli-rs/Cargo.toml +++ b/mps-cli-rs/Cargo.toml @@ -9,4 +9,5 @@ edition = "2021" uuid = { version = "1.8.0", features = ["v4"] } quick-xml = { version = "0.31.0", features = ["serialize"] } serde = { version = "1.0.197", features = ["derive"] } -walkdir = "2.5.0" \ No newline at end of file +walkdir = "2.5.0" +roxmltree = "0.19.0" \ No newline at end of file diff --git a/mps-cli-rs/src/builder/mod.rs b/mps-cli-rs/src/builder/mod.rs index fa730ce..96a38af 100644 --- a/mps-cli-rs/src/builder/mod.rs +++ b/mps-cli-rs/src/builder/mod.rs @@ -1,7 +1,7 @@ pub mod smodules_repository_builder; mod ssolution_builder; -mod smodel_builder_file_per_root_persistency; +pub mod smodel_builder_file_per_root_persistency; mod builder_helper; mod root_node_from_mpsr_file_builder; mod test_helper; -mod slanguage_builder; +pub mod slanguage_builder; diff --git a/mps-cli-rs/src/builder/slanguage_builder.rs b/mps-cli-rs/src/builder/slanguage_builder.rs index 1fdefbc..7a01db6 100644 --- a/mps-cli-rs/src/builder/slanguage_builder.rs +++ b/mps-cli-rs/src/builder/slanguage_builder.rs @@ -1,40 +1,62 @@ +use std::borrow::BorrowMut; +use std::cell::RefCell; use std::collections::HashMap; use std::sync::Mutex; +use std::rc::Rc; -use crate::model::sconcept::SConcept; +use crate::model::sconcept::{SConcept, SContainmentLink, SProperty, SReferenceLink}; use crate::model::slanguage::SLanguage; -pub(crate) static SLANGUAGE_BUILDER: Mutex = Mutex::new(SLanguageBuilder::new()); pub(crate) struct SLanguageBuilder { - language_id_to_slanguage: Option>, + pub language_id_to_slanguage: RefCell>>, + pub concept_id_to_concept : RefCell>>, } impl<'a> SLanguageBuilder { - pub(crate) const fn new() -> Self { + pub(crate) fn new() -> Self { SLanguageBuilder { - language_id_to_slanguage: None, + language_id_to_slanguage: RefCell::new(HashMap::new()), + concept_id_to_concept: RefCell::new(HashMap::new()), } } - fn ensure_initialized(&mut self) -> &mut HashMap { - self.language_id_to_slanguage.get_or_insert(HashMap::new()) + pub(crate) fn get_or_build_language(&self, language_id: &String, language_name: &String) -> Rc { + let mut l = self.language_id_to_slanguage.borrow_mut(); + let res = l.entry(language_id.to_string()).or_insert_with(|| Rc::new(SLanguage::new(language_name.to_string(), language_id.to_string()))); + Rc::clone(res) } - pub(crate) fn get_or_build_language(&mut self, language_id: &String, language_name: &String) -> &mut SLanguage { - let language_id_to_slanguage = self.ensure_initialized(); - language_id_to_slanguage.entry(language_id.to_string()).or_insert(SLanguage::new(language_name.to_string(), language_id.to_string())); - language_id_to_slanguage.get_mut(language_id).unwrap() + pub(crate) fn get_or_create_concept(&'a self, language: Rc, concept_id: String, concept_name: String) -> Rc { + let mut concepts = language.concepts.borrow_mut(); + if let Some(i) = concepts.iter().position(|c| c.name == concept_name) { + let c = &concepts[i]; + Rc::clone(c) + } else { + concepts.push(Rc::new(SConcept::new(concept_name.clone(), concept_id.clone()))); + Rc::clone(concepts.last().unwrap()) + } } - pub(crate) fn get_or_create_concept_in_language(&mut self, language_id: &String, language_name: &String, concept_id: String, concept_name: String) -> &SConcept { - self.ensure_initialized(); - let language: &mut SLanguage = self.get_or_build_language(language_id, language_name); - if language.find_concept_by_name(&concept_name).is_none() { - language.add_concept(SConcept::new(&concept_name, concept_id)); - } - return language.find_concept_by_name(&concept_name).unwrap(); + + pub(crate) fn get_or_create_property(&'a self, concept: Rc, property_id: String, property_name: String) -> Rc { + let mut props = concept.properties.borrow_mut(); + let property = props.entry(property_id.clone()).or_insert(Rc::new(SProperty::new(property_name, property_id))); + Rc::clone(property) + } + + pub(crate) fn get_or_create_child(&'a self, concept: Rc, child_id: String, child_name: String) -> Rc { + let mut links = concept.containment_links.borrow_mut(); + let containment_link = links.entry(child_id.clone()).or_insert(Rc::new(SContainmentLink::new(child_name, child_id))); + Rc::clone(containment_link) + } + + pub(crate) fn get_or_create_reference(&'a self, concept: Rc, reference_id: String, reference_name: String) -> Rc { + let mut refs = concept.reference_links.borrow_mut(); + let reference_link = refs.entry(reference_id.clone()).or_insert(Rc::new(SReferenceLink::new(reference_name, reference_id))); + Rc::clone(reference_link) } + } diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index ddb7945..e20e94f 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -1,47 +1,46 @@ +use std::borrow::{Borrow, BorrowMut}; use std::collections::HashMap; use std::fs::File; use std::io::BufReader; +use std::ops::DerefMut; use std::path::PathBuf; use std::sync::Mutex; +use std::io::Read; +use roxmltree::{Document, Node}; +use std::rc::Rc; +use std::cell::RefCell; -use quick_xml::events::Event; +use quick_xml::events::{attributes, Event}; use quick_xml::Reader; use walkdir::{DirEntry, WalkDir}; use crate::builder::builder_helper::{convert_to_string, get_value_of_attribute_with_key, get_values_of_attributes_with_keys, panic_read_file, panic_unexpected_eof_read_file}; -use crate::builder::slanguage_builder::SLANGUAGE_BUILDER; -use crate::model::sconcept::{SConcept, SProperty}; +use crate::model::sconcept::{SConcept, SContainmentLink, SProperty, SReferenceLink}; use crate::model::smodel::SModel; use crate::model::snode::SNode; +use roxmltree::ParsingOptions; +use super::slanguage_builder::SLanguageBuilder; -static SMODEL_BUILDER_CACHE: Mutex = Mutex::new(SModelBuilderCache::new()); -pub struct SModelBuilderCache<'a> { - pub index_2_concept: Option>, - pub index_2_property: Option>, - pub index_2_imported_model_uuid: Option>, +#[derive(Clone)] +pub struct SModelBuilderCache { + pub index_2_concept: RefCell>>, + pub index_2_property: RefCell>>, + pub index_2_containment_link: RefCell>>, + pub index_2_reference_link: RefCell>>, + pub index_2_imported_model_uuid: RefCell>, } -impl<'a> SModelBuilderCache<'a> { - const fn new() -> Self { +impl SModelBuilderCache { + pub fn new() -> Self { SModelBuilderCache { - index_2_concept: None, - index_2_property: None, - index_2_imported_model_uuid: None, + index_2_concept: RefCell::new(HashMap::new()), + index_2_property: RefCell::new(HashMap::new()), + index_2_containment_link : RefCell::new(HashMap::new()), + index_2_reference_link : RefCell::new(HashMap::new()), + index_2_imported_model_uuid: RefCell::new(HashMap::new()), } } - - fn get_index_2_concept(&mut self) -> &mut HashMap { - self.index_2_concept.get_or_insert(HashMap::new()) - } - - fn get_index_2_property(&mut self) -> &mut HashMap { - self.index_2_property.get_or_insert(HashMap::new()) - } - - fn get_index_2_imported_model_uuid(&mut self) -> &mut HashMap { - self.index_2_imported_model_uuid.get_or_insert(HashMap::new()) - } } pub struct SModelBuilderFilePerRootPersistency {} @@ -50,11 +49,19 @@ impl SModelBuilderFilePerRootPersistency { pub(crate) fn new() -> Self { SModelBuilderFilePerRootPersistency {} } - - pub(crate) fn build_model(&mut self, path_to_model: PathBuf) -> SModel { + + pub(crate) fn build_model<'a>(path_to_model: PathBuf, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> SModel<'a> { + let opt = roxmltree::ParsingOptions { + allow_dtd: true, + ..roxmltree::ParsingOptions::default() + }; + let mut model_file = path_to_model.clone(); model_file.push(".model"); - let mut model: SModel = Self::extract_model_core_info(model_file); + + let path_to_model_file = model_file.to_str().unwrap().to_string(); + + let mut model: SModel = Self::extract_model_core_info(model_file, &opt); let mpsr_file_walker = WalkDir::new(path_to_model).min_depth(1).max_depth(1); let mpsr_files = mpsr_file_walker.into_iter().filter(|entry| { @@ -66,181 +73,209 @@ impl SModelBuilderFilePerRootPersistency { return false; }); - let roots = mpsr_files.into_iter().map(|mpsr_file| { + let mut roots = vec!(); + for mpsr_file in mpsr_files.into_iter() { let file = mpsr_file.unwrap(); - self.build_root_node_from_file(file) - }); + let r = Self::build_root_node_from_file(file, &opt, language_builder, model_builder_cache); + roots.push(r.unwrap()); + }; model.root_nodes.extend(roots); return model; } - fn extract_model_core_info<'a>(path_to_model: PathBuf) -> SModel<'a> { - let mut model_file_reader = Reader::from_file(path_to_model.clone()).unwrap(); - let mut name = String::new(); - let mut uuid = String::new(); + fn extract_model_core_info<'a>(path_to_model: PathBuf, opt : &ParsingOptions) -> SModel<'a> { + let path_to_model_file = path_to_model.to_str().unwrap().to_string(); + + let file = std::fs::File::open(path_to_model_file.clone()); + let mut s = String::new(); + file.unwrap().read_to_string(&mut s); + let parse_res = roxmltree::Document::parse_with_options(&s, *opt); + let document = parse_res.unwrap(); + + let model_element = document.root_element(); + let uuid_and_name = model_element.attributes().find(|a| a.name() == "ref").unwrap().value().to_string(); + + let left_parens_pos = uuid_and_name.find('(').unwrap(); + let right_parens_pos = uuid_and_name.find(')').unwrap(); + let uuid = uuid_and_name[0..left_parens_pos].to_string(); + let name = uuid_and_name[left_parens_pos + 1..right_parens_pos].to_string(); + let mut is_do_not_generate = false; - let mut buf = vec![]; - let mut model_found = false; - let mut do_not_gen_found = false; - while !(do_not_gen_found && model_found) { - match model_file_reader.read_event_into(&mut buf) { - Ok(Event::Start(ref e)) => { - match e.name().as_ref() { - b"model" => { - let value = get_value_of_attribute_with_key(e.attributes(), "ref").unwrap(); - let index = value.find("(").unwrap(); - uuid = value[..index].to_string(); - name = value[index + 1..value.len() - 1].to_string(); - model_found = true; - } - _ => {} - } - } - Ok(Event::Empty(ref e)) => { - if e.name().as_ref() == b"attribute" { - let attribute_name = get_value_of_attribute_with_key(e.attributes(), "name"); - if attribute_name.is_some() && attribute_name.unwrap().eq("doNotGenerate") { - let value = get_value_of_attribute_with_key(e.attributes(), "value").unwrap(); - is_do_not_generate = value.eq("true"); - do_not_gen_found = true; - } - } - } - Ok(Event::Eof) => break, - Err(e) => panic_read_file(&mut model_file_reader, e), - _ => {} - } + let model_attributes_elements = model_element.children().filter(|c| (c.tag_name().name().to_string() == "attribute")); + let do_not_generate_attribute = (model_attributes_elements.clone()).find(|a| a.attributes().find(|aa| aa.value() == "doNotGenerate").is_some()); + if let Some(do_not_generate_attribute) = do_not_generate_attribute { + let do_not_generate_str = do_not_generate_attribute.attributes().find(|aa| aa.name() == "value").unwrap().value(); + if do_not_generate_str == "true" { is_do_not_generate = true; } } - return SModel::new(name, uuid, convert_to_string(&path_to_model), is_do_not_generate, true); + + + return SModel::new(name, uuid, path_to_model_file, is_do_not_generate, true); } - fn build_root_node_from_file(&self, dir_entry: DirEntry) -> SNode { - let mut mpsr_reader = Reader::from_file(dir_entry.path()).unwrap(); - let mut buf = vec![]; - let mut root_node = None; - loop { - match mpsr_reader.read_event_into(&mut buf) { - Ok(Event::Start(ref e)) => match e.name().as_ref() { - b"imports" => self.parse_imports(&mut mpsr_reader), - b"registry" => self.parse_registry(&mut mpsr_reader), - b"node" => { - //root_node = Some(parse_node(&mpsr_reader, e, &mut buf)) - } - _ => {} - }, - Ok(Event::Eof) => break, - Err(e) => panic_read_file(&mut mpsr_reader, e), - _ => {} - } - } - return root_node.unwrap(); + fn build_root_node_from_file<'a>(dir_entry: DirEntry, opt : &ParsingOptions, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> Option>> { + println!("building root node from {}", dir_entry.path().as_os_str().to_str().unwrap()); + let file = std::fs::File::open(dir_entry.path().as_os_str()); + + let mut s = String::new(); + file.unwrap().read_to_string(&mut s); + let parse_res = roxmltree::Document::parse_with_options(&s, *opt); + let document = parse_res.unwrap(); + Self::parse_imports(&document, model_builder_cache); + Self::parse_registry(&document, language_builder, model_builder_cache); + + let node = document.root_element().children().find(|it| it.tag_name().name() == "node"); + let mut parent: Option> = None; + Some(Self::parse_node(&mut parent, &node.unwrap(), language_builder, &model_builder_cache)) } - fn parse_imports(&self, mpsr_reader: &mut Reader>) { - let mut child_buf = vec![]; - loop { - match mpsr_reader.read_event_into(&mut child_buf) { - Ok(Event::Empty(e)) => { - let key_values = get_values_of_attributes_with_keys(e.attributes(), vec!["index", "ref"]); - if let Some(imported_model_ref) = key_values.get("ref") { - let index = imported_model_ref.find("(").unwrap(); - let imported_model_uuid = imported_model_ref[..index].to_string(); - if let Some(index_value) = key_values.get("index") { - SMODEL_BUILDER_CACHE.lock().unwrap().get_index_2_imported_model_uuid().insert(index_value.to_string(), imported_model_uuid); - } - } - } - Ok(Event::End(e)) => { - match e.name().as_ref() { - b"imports" => break, - _ => {} + fn parse_imports(document: &Document, model_builder_cache : &SModelBuilderCache) { + let model_element = document.root_element(); + let imports_element = model_element.children().find(|c| c.tag_name().name() == "imports"); + match imports_element { + Some(imports) => { + for import in imports.children() { + let tag_name = import.tag_name(); + if tag_name.name() == "import" { + let index = import.attributes().find(|a| a.name() == "index").unwrap().value(); + let uuid = import.attributes().find(|a| a.name() == "ref").unwrap().value(); + + let uuid = uuid.to_string()[0..uuid.find('(').unwrap()].to_string(); + model_builder_cache.index_2_imported_model_uuid.borrow_mut().insert(index.to_string(), uuid); } } - Ok(Event::Eof) => panic_unexpected_eof_read_file(mpsr_reader), - Err(e) => panic_read_file(mpsr_reader, e), - _ => {} - } + }, + _ => () } } - fn parse_registry(&self, mpsr_reader: &mut Reader>) { - let mut child_buf = vec![]; - loop { - match mpsr_reader.read_event_into(&mut child_buf) { - Ok(Event::Empty(e)) => { - match e.name().as_ref() { - b"language" => { - let id_name_attributes = get_values_of_attributes_with_keys(e.attributes(), vec!["id", "name"]); - let id = id_name_attributes.get("id").unwrap(); - let name = id_name_attributes.get("name").unwrap(); - self.parse_concept(mpsr_reader, id, name); - } - - _ => {} - } - } - Ok(Event::End(e)) => { - match e.name().as_ref() { - b"registry" => break, - _ => {} + fn parse_registry<'a>(document: &Document, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) { + let model_element = document.root_element(); + let registry_element = model_element.children().find(|c| c.tag_name().name() == "registry"); + match registry_element { + Some(registry) => { + for language in registry.children() { + if language.tag_name().name() != "language" { continue; } + + let language_id = language.attributes().find(|a| a.name() == "id").unwrap().value(); + let language_name = language.attributes().find(|a| a.name() == "name").unwrap().value(); + + let lang = language_builder.get_or_build_language(&language_id.to_string(), &language_name.to_string()); + for concept in language.children() { + if concept.tag_name().name() != "concept" { continue; } + + let concept_id = concept.attributes().find(|a| a.name() == "id").unwrap().value(); + let concept_name = concept.attributes().find(|a| a.name() == "name").unwrap().value(); + let concept_index = concept.attributes().find(|a| a.name() == "index").unwrap().value(); + let conc = language_builder.get_or_create_concept(Rc::clone(&lang), concept_id.to_string(), concept_name.to_string()); + model_builder_cache.index_2_concept.borrow_mut().insert(concept_index.to_string(), Rc::clone(&conc)); + + for properties_links_references in concept.children() { + if properties_links_references.tag_name().name() == "" { continue; } + + let tag_name = properties_links_references.tag_name().name(); + let id = properties_links_references.attributes().find(|a| a.name() == "id").unwrap().value(); + let name = properties_links_references.attributes().find(|a| a.name() == "name").unwrap().value(); + let index = properties_links_references.attributes().find(|a| a.name() == "index").unwrap().value(); + + if tag_name == "property" { + let prop = language_builder.get_or_create_property(Rc::clone(&conc),id.to_string(), name.to_string()); + model_builder_cache.index_2_property.borrow_mut().insert(index.to_string(), Rc::clone(&prop)); + } else if tag_name == "child" { + let child_link = language_builder.get_or_create_child(Rc::clone(&conc),id.to_string(), name.to_string()); + model_builder_cache.index_2_containment_link.borrow_mut().insert(index.to_string(), Rc::clone(&child_link)); + } else if tag_name == "reference" { + let ref_link = language_builder.get_or_create_reference(Rc::clone(&conc),id.to_string(), name.to_string()); + model_builder_cache.index_2_reference_link.borrow_mut().insert(index.to_string(), Rc::clone(&ref_link)); + } + } } - } - Ok(Event::Eof) => panic_unexpected_eof_read_file(mpsr_reader), - Err(e) => panic_read_file(mpsr_reader, e), - _ => {} - } + }; + }, + _ => () } } - fn parse_concept(&self, mpsr_reader: &mut Reader>, language_id: &String, language_name: &String) { - let mut concept_buf = vec![]; - - loop { - match mpsr_reader.read_event_into(&mut concept_buf) { - Ok(Event::Empty(e)) => { - match e.name().as_ref() { - b"concept" => { - let mut id_map_index_map = get_values_of_attributes_with_keys(e.attributes(), vec!["id", "name", "index"]); - let concept_id = id_map_index_map.remove("id").unwrap(); - let concept_name = id_map_index_map.remove("name").unwrap(); - let mut language_builder = SLANGUAGE_BUILDER.lock().unwrap(); - let concept: &SConcept = language_builder.get_or_create_concept_in_language(language_id, language_name, concept_id, concept_name); - SMODEL_BUILDER_CACHE.lock().unwrap().get_index_2_concept().insert(id_map_index_map.remove("index").unwrap(), concept); - } - - _ => {} - } - } - Ok(Event::End(e)) => { - match e.name().as_ref() { - b"concept" => break, - _ => {} - } - } - Ok(Event::Eof) => panic_unexpected_eof_read_file(mpsr_reader), - Err(e) => panic_read_file(mpsr_reader, e), - _ => {} - } - } + + fn parse_node<'a>(parent_node : &mut Option>>, node: &Node, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> Rc> { + let node_attrs = node.attributes(); + let concept_index = (node_attrs.clone()).into_iter().find(|a| a.name() == "concept").unwrap().value(); + let node_id = (node_attrs.clone()).into_iter().find(|a| a.name() == "id").unwrap().value(); + let role = (node_attrs.clone()).into_iter().find(|a| a.name() == "role"); + let role = if role.is_none() { None } else { Some(role.unwrap().value().to_string()) }; + + let index_2_concept = model_builder_cache.index_2_concept.borrow(); + + let my_concept = index_2_concept.get(concept_index).unwrap(); + let mut current_node : Rc = Rc::new(SNode::new(node_id.to_string(), Rc::clone(my_concept), role.clone())); + + if let Some(parent) = parent_node { + let index_2_containment_link = model_builder_cache.index_2_containment_link.borrow(); + let cl = index_2_containment_link.get(&role.unwrap()); + parent.borrow_mut().add_child(Rc::clone(cl.unwrap()), Rc::clone(¤t_node)); + }; + + let properties = node.children().filter(|it| it.tag_name().name() == "property"); + for property in properties { + let role = property.attributes().find(|a| a.name() == "role").unwrap().value(); + let value = property.attributes().find(|a| a.name() == "value").unwrap().value(); + let index_2_properties = model_builder_cache.index_2_property.borrow(); + let prop = index_2_properties.get(role).unwrap(); + current_node.add_property(prop, value.to_string()); + }; + + let refs = node.children().filter(|it| it.tag_name().name() == "ref"); + for ref_ in refs { + let role = ref_.attributes().find(|a| a.name() == "role").unwrap().value(); + let to = ref_.attributes().find(|a| a.name() == "to"); + let to = if let Some(t) = to { + t.value() + } else { + ref_.attributes().find(|a| a.name() == "node").unwrap().value() + }; + let resolve = if let Some(r) = ref_.attributes().find(|a| a.name() == "resolve") { + Some(String::from(r.value())) + } else { + None + }; + + let index_2_reference_links = model_builder_cache.index_2_reference_link.borrow(); + let reference_link = index_2_reference_links.get(&role.to_string()).unwrap(); + current_node.add_reference(reference_link, to.to_string(), resolve); + }; + + let nodes = node.children().filter(|it| it.tag_name().name() == "node"); + for node in nodes { + Self::parse_node(&mut Some(Rc::clone(¤t_node)), &node, language_builder, model_builder_cache); + }; + + Rc::clone(¤t_node) } + + } #[cfg(test)] mod tests { use std::path::PathBuf; - use crate::builder::smodel_builder_file_per_root_persistency::{SMODEL_BUILDER_CACHE, SModelBuilderFilePerRootPersistency}; + use crate::builder::slanguage_builder::SLanguageBuilder; + use crate::builder::smodel_builder_file_per_root_persistency::{SModelBuilderCache, SModelBuilderFilePerRootPersistency}; use crate::builder::test_helper::{get_path_to_model_mpsr_example_lib_file, get_path_to_mpsr_example_lib_file}; use crate::builder::test_helper::get_path_to_example_mpsr_model_files; #[test] fn test_model_extract_core_info() { + let opt = roxmltree::ParsingOptions { + allow_dtd: true, + ..roxmltree::ParsingOptions::default() + }; + // given - let path_to_model_file = PathBuf::from(get_path_to_mpsr_example_lib_file()); + let path_to_model_file = PathBuf::from(get_path_to_model_mpsr_example_lib_file()); //when - let model = SModelBuilderFilePerRootPersistency::extract_model_core_info(path_to_model_file); + let model = SModelBuilderFilePerRootPersistency::extract_model_core_info(path_to_model_file, &opt); //assert assert_eq!(model.name, "mps.cli.lanuse.library_top.library_top"); @@ -256,14 +291,15 @@ mod tests { let path_to_mpsr_file = PathBuf::from(get_path_to_example_mpsr_model_files()); //when - let mut smodel_builder = SModelBuilderFilePerRootPersistency::new(); - smodel_builder.build_model(path_to_mpsr_file); + let mut language_builder = SLanguageBuilder::new(); + let mut model_builder_cache = SModelBuilderCache::new(); + SModelBuilderFilePerRootPersistency::build_model(path_to_mpsr_file, &mut language_builder, &model_builder_cache); //assert - assert_eq!(SMODEL_BUILDER_CACHE.lock().unwrap().get_index_2_imported_model_uuid().len(), 1); - assert!(SMODEL_BUILDER_CACHE.lock().unwrap().get_index_2_imported_model_uuid().contains_key(&"q0v6".to_string())); - let mut binding = SMODEL_BUILDER_CACHE.lock().unwrap(); - let imported_model_uuid = binding.get_index_2_imported_model_uuid().get(&"q0v6".to_string()).unwrap(); - assert_eq!(**imported_model_uuid, "ec5f093b-9d83-43a1-9b41-b5952da8b1ed".to_string()); + let index_2_imported_model_uuid = model_builder_cache.index_2_imported_model_uuid.borrow(); + assert_eq!(index_2_imported_model_uuid.len(), 1); + assert!(index_2_imported_model_uuid.contains_key(&"q0v6".to_string())); + let imported_model_uuid = index_2_imported_model_uuid.get(&"q0v6".to_string()).unwrap(); + assert_eq!(**imported_model_uuid, "r:ec5f093b-9d83-43a1-9b41-b5952da8b1ed".to_string()); } } diff --git a/mps-cli-rs/src/builder/smodules_repository_builder.rs b/mps-cli-rs/src/builder/smodules_repository_builder.rs index fd8466f..aad9cad 100644 --- a/mps-cli-rs/src/builder/smodules_repository_builder.rs +++ b/mps-cli-rs/src/builder/smodules_repository_builder.rs @@ -2,41 +2,51 @@ use std::path::PathBuf; use std::time::Instant; use walkdir::WalkDir; +use std::rc::Rc; +use crate::builder::slanguage_builder::SLanguageBuilder; +use crate::builder::smodel_builder_file_per_root_persistency::SModelBuilderCache; use crate::builder::ssolution_builder::build_solution; use crate::model::srepository::SRepository; use crate::model::ssolution::SSolution; +use crate::model::slanguage::SLanguage; + +pub fn build_repo_from_directories<'a>(source_dirs: Vec, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> SRepository<'a> { + let mut all_solutions : Vec> = Vec::new(); -pub fn build_repo_from_all<'a>(source_dirs: Vec) -> SRepository<'a> { - let mut all_solutions = Vec::new(); for source_dir in source_dirs { println!("loading models from directory: {}", source_dir); - let solutions = build_solutions_from(source_dir); - all_solutions.extend(solutions); + let solutions = build_solutions_from(source_dir, &language_builder, model_builder_cache); + solutions.into_iter().for_each(|s| all_solutions.push(Rc::new(s))); } - return SRepository::new(all_solutions, vec![]); + let mut languages: Vec> = Vec::new(); + language_builder.language_id_to_slanguage.borrow().values().for_each(|v| languages.push(Rc::clone(v))); + SRepository::new(all_solutions, languages) } -pub fn build_repo_from<'a>(source_dir: String) -> SRepository<'a> { - let solutions = build_solutions_from(source_dir); - return SRepository::new(solutions, vec![]); +pub fn build_repo_from_directory<'a>(source_dir: String, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> SRepository<'a> { + let mut all_solutions : Vec> = Vec::new(); + let solutions = build_solutions_from(source_dir, language_builder, model_builder_cache); + solutions.into_iter().for_each(|s| all_solutions.push(Rc::new(s))); + + let mut languages: Vec> = Vec::new(); + language_builder.language_id_to_slanguage.borrow().values().for_each(|v| languages.push(Rc::clone(v))); + SRepository::new(all_solutions, languages) } -fn build_solutions_from<'a>(source_dir: String) -> Vec> { +fn build_solutions_from<'a>(source_dir: String, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> Vec> { let now = Instant::now(); - - let solutions = collect_modules_from_sources(source_dir.clone()); - + let solutions = collect_modules_from_sources(source_dir.clone(), language_builder, model_builder_cache); let elapsed = now.elapsed(); println!("{} milli seconds for handling {}", elapsed.as_millis(), source_dir); return solutions; } -pub fn collect_modules_from_sources<'a>(source_dir: String) -> Vec> { +pub fn collect_modules_from_sources<'a>(source_dir: String, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> Vec> { let msd_files = find_msd_files(&source_dir, 3); - let solutions: Vec = msd_files.iter().map(|msd_file| build_solution(msd_file)).collect(); + let solutions: Vec = msd_files.iter().map(|msd_file| build_solution(msd_file, language_builder, &model_builder_cache)).collect(); return solutions; } @@ -58,7 +68,11 @@ pub fn find_msd_files(source_dir: &String, start_depth: usize) -> Vec { #[cfg(test)] mod tests { - use crate::builder::smodules_repository_builder::{build_repo_from, find_msd_files}; + use core::num; + + use crate::builder::slanguage_builder::SLanguageBuilder; + use crate::builder::smodel_builder_file_per_root_persistency::SModelBuilderCache; + use crate::builder::smodules_repository_builder::{build_repo_from_directory, find_msd_files}; use crate::builder::test_helper::get_path_to_mps_cli_lanuse_file_per_root; use crate::model::smodel::SModel; @@ -82,14 +96,18 @@ mod tests { use std::time::Instant; let now = Instant::now(); //when - let repository = build_repo_from(src_dir); + let language_builder = SLanguageBuilder::new(); + let model_builder_cache = SModelBuilderCache::new(); + let repository = build_repo_from_directory(src_dir, &language_builder, &model_builder_cache); //then let required_time = now.elapsed().as_millis(); - let models: Vec<&SModel> = repository.solutions.iter().flat_map(|solution| &solution.models).collect(); + let solutions = repository.solutions.borrow(); + let models: Vec<&SModel> = solutions.iter().flat_map(|solution| &solution.models).collect(); let do_not_gen_models: Vec<&&SModel> = models.iter().filter(|&model| model.is_do_not_generate).collect(); - println!("Found {} solutions with {} models (out of which {} are set to do not generate) in {} ms", repository.solutions.len(), models.len(), do_not_gen_models.len(), required_time); - assert!(repository.solutions.len() > 1); + let number_of_solutions = repository.solutions.borrow().len(); + println!("Found {} solutions with {} models (out of which {} are set to do not generate) in {} ms", number_of_solutions, models.len(), do_not_gen_models.len(), required_time); + assert!(number_of_solutions > 1); assert!(models.len() > 1); assert_eq!(do_not_gen_models.len(), 1); } diff --git a/mps-cli-rs/src/builder/ssolution_builder.rs b/mps-cli-rs/src/builder/ssolution_builder.rs index 2f7379d..eada634 100644 --- a/mps-cli-rs/src/builder/ssolution_builder.rs +++ b/mps-cli-rs/src/builder/ssolution_builder.rs @@ -1,3 +1,4 @@ +use std::borrow::BorrowMut; use std::path::PathBuf; use quick_xml::events::Event; @@ -8,9 +9,12 @@ use walkdir::WalkDir; use crate::builder::builder_helper::convert_to_string; use crate::builder::builder_helper::panic_read_file; use crate::builder::smodel_builder_file_per_root_persistency::SModelBuilderFilePerRootPersistency; +use crate::builder::slanguage_builder::SLanguageBuilder; use crate::model::ssolution::SSolution; -pub fn build_solution<'a>(path_buf_to_msd_file: &PathBuf) -> SSolution<'a> { +use super::smodel_builder_file_per_root_persistency::SModelBuilderCache; + +pub fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> SSolution<'a> { let path_to_msd_file = convert_to_string(&path_buf_to_msd_file); let mut solution: SSolution = extract_solution_core_info(path_to_msd_file); println!("Building from solution {}", solution.name); @@ -19,17 +23,18 @@ pub fn build_solution<'a>(path_buf_to_msd_file: &PathBuf) -> SSolution<'a> { let model_dir = convert_to_string(&solution_dir.to_path_buf()) + "/models"; let model_dir = WalkDir::new(model_dir).min_depth(1).max_depth(1); + let mut models = vec![]; for model_entry in model_dir.into_iter() { let path = model_entry.unwrap().into_path(); if path.is_dir() { - let mut smodel_builder = SModelBuilderFilePerRootPersistency::new(); - let model = smodel_builder.build_model(path); - //solution.models.push(model) + let model = SModelBuilderFilePerRootPersistency::build_model(path, language_builder, model_builder_cache); + models.push(model) } else { println!("ERROR: model entry {} is a file not a directory. Cannot be parsed as only file per root persistency is supported.", path.to_str().unwrap().to_string()) } } + solution.models.extend(models); return solution; } diff --git a/mps-cli-rs/src/main.rs b/mps-cli-rs/src/main.rs index e1a7927..6c62bd6 100644 --- a/mps-cli-rs/src/main.rs +++ b/mps-cli-rs/src/main.rs @@ -1,6 +1,15 @@ mod model; mod builder; +use crate::builder::smodules_repository_builder::build_repo_from_directory; +use crate::builder::slanguage_builder::SLanguageBuilder; +use crate::builder::smodel_builder_file_per_root_persistency::SModelBuilderCache; + fn main() { - println!("Hello, world!"); + let language_builder = SLanguageBuilder::new(); + let model_builder_cache = SModelBuilderCache::new(); + let repository = build_repo_from_directory(String::from("C:\\work\\E3_2.0_Solution\\solutions"), &language_builder, &model_builder_cache); + println!("number of solutions: {}", repository.solutions.borrow().len()); } + +//160523 milli seconds \ No newline at end of file diff --git a/mps-cli-rs/src/model/sconcept.rs b/mps-cli-rs/src/model/sconcept.rs index 792b583..7efc773 100644 --- a/mps-cli-rs/src/model/sconcept.rs +++ b/mps-cli-rs/src/model/sconcept.rs @@ -1,50 +1,52 @@ use std::collections::HashMap; use uuid::Uuid; +use std::cell::RefCell; +use std::rc::Rc; -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone)] pub struct SConcept { pub(crate) name: String, uuid: String, - pub(crate) properties: HashMap, - containment_links: HashMap, - reference_links: HashMap, + pub(crate) properties: RefCell>>, + pub containment_links: RefCell>>, + pub reference_links: RefCell>>, } -#[derive(PartialEq, Eq, Hash, Debug)] +#[derive(PartialEq, Eq, Hash, Debug, Clone)] pub struct SProperty { pub(crate) name: String, - uuid: Uuid, + pub id: String, } -#[derive(PartialEq, Eq, Hash, Debug)] +#[derive(PartialEq, Eq, Hash, Debug, Clone)] pub struct SContainmentLink { pub(crate) name: String, - uuid: Uuid, + id: String, } -#[derive(PartialEq, Eq, Hash, Debug)] +#[derive(PartialEq, Eq, Hash, Debug, Clone)] pub struct SReferenceLink { pub(crate) name: String, - uuid: Uuid, + id: String, } impl SConcept { - pub fn new(name: &String, uuid: String) -> Self { + pub fn new(name: String, uuid: String) -> Self { SConcept { name: name.to_string(), uuid, - properties: HashMap::new(), - containment_links: HashMap::new(), - reference_links: HashMap::new(), + properties: RefCell::new(HashMap::new()), + containment_links: RefCell::new(HashMap::new()), + reference_links: RefCell::new(HashMap::new()), } } pub fn print_concept_details(&self) { - let properties_string_vector: Vec = self.properties.iter().map(|prop| format!("{} {}", prop.0, prop.1.name)).collect(); + let properties_string_vector: Vec = self.properties.borrow().iter().map(|prop| format!("{} {}", prop.0, prop.1.name)).collect(); let properties_info = properties_string_vector.join(", "); - let children_info = self.containment_links.iter().map(|child| { format!("{} {}", child.0, child.1.name) }).collect::>().join(", "); - let reference_info = self.reference_links.iter().map(|reference| format!("{} {}", reference.0, reference.1.name)).collect::>().join(", "); + let children_info = self.containment_links.borrow().iter().map(|child| { format!("{} {}", child.0, child.1.name) }).collect::>().join(", "); + let reference_info = self.reference_links.borrow().iter().map(|reference| format!("{} {}", reference.0, reference.1.name)).collect::>().join(", "); println!("concept {}\n\ properties: \n\ \t\t{}\n\ @@ -57,28 +59,28 @@ impl SConcept { } impl SProperty { - pub fn new(name: String, uuid: Uuid) -> Self { + pub fn new(name: String, id: String) -> Self { SProperty { name, - uuid, + id, } } } impl SContainmentLink { - pub fn new(name: String, uuid: Uuid) -> Self { + pub fn new(name: String, id: String) -> Self { SContainmentLink { name, - uuid, + id, } } } impl SReferenceLink { - pub fn new(name: String, uuid: Uuid) -> Self { + pub fn new(name: String, id: String) -> Self { SReferenceLink { name, - uuid, + id, } } } @@ -91,22 +93,6 @@ mod tests { #[test] fn test_sconcept() { - // given - let mut sconcept: SConcept = SConcept::new(&"FirstConcept".to_string(), Uuid::new_v4().to_string()); - let sproperty = SProperty::new("FirstProperty".to_string(), Uuid::new_v4()); - let reference_link = SReferenceLink::new("FirstLink".to_string(), Uuid::new_v4()); - let containment_link_1 = SContainmentLink::new("FirstContainment".to_string(), Uuid::new_v4()); - let containment_link_2 = SContainmentLink::new("SecondContainment".to_string(), Uuid::new_v4()); - - //when - sconcept.properties.insert("property".to_string(), sproperty); - sconcept.reference_links.insert("ref".to_string(), reference_link); - sconcept.containment_links.insert("child1".to_string(), containment_link_1); - sconcept.containment_links.insert("child2".to_string(), containment_link_2); - - //assert - assert_eq!(sconcept.properties.len(), 1); - assert_eq!(sconcept.reference_links.len(), 1); - assert_eq!(sconcept.containment_links.len(), 2); + } } \ No newline at end of file diff --git a/mps-cli-rs/src/model/slanguage.rs b/mps-cli-rs/src/model/slanguage.rs index 36a4f76..502a519 100644 --- a/mps-cli-rs/src/model/slanguage.rs +++ b/mps-cli-rs/src/model/slanguage.rs @@ -1,9 +1,12 @@ use crate::model::sconcept::SConcept; +use std::cell::RefCell; +use std::rc::Rc; +#[derive(Clone)] pub struct SLanguage { - name: String, - uuid: String, - concepts: Vec, + pub name: String, + pub uuid: String, + pub concepts: RefCell>>, } impl SLanguage { @@ -11,17 +14,9 @@ impl SLanguage { SLanguage { name, uuid, - concepts: vec![], + concepts: RefCell::new(vec![]), } } - - pub fn find_concept_by_name(&self, concept_name: &str) -> Option<&SConcept> { - self.concepts.iter().find(|&concept| concept.name.eq(concept_name)) - } - - pub fn add_concept(&mut self, concept: SConcept) { - self.concepts.push(concept); - } } #[cfg(test)] @@ -33,24 +28,6 @@ mod tests { #[test] fn test_find_concept_by_name() { - // given - let mut slanguage = SLanguage::new("FirstLanguage".to_string(), Uuid::new_v4().to_string()); - let first_concept_name = "FirstConcept"; - let first_concept: SConcept = SConcept::new(&first_concept_name.to_string(), Uuid::new_v4().to_string()); - let second_concept_name = "SecondConcept"; - let second_concept = SConcept::new(&second_concept_name.to_string(), Uuid::new_v4().to_string()); - slanguage.concepts.push(first_concept); - slanguage.concepts.push(second_concept); - - //when - let found_first_concept = slanguage.find_concept_by_name(first_concept_name); - let found_second_concept = slanguage.find_concept_by_name(second_concept_name); - let non_found_concept = slanguage.find_concept_by_name("ThirdConcept"); - //assert - assert_eq!(slanguage.concepts.len(), 2); - assert_eq!(found_first_concept, slanguage.concepts.get(0), "First concept not found"); - assert_eq!(found_second_concept, slanguage.concepts.get(1), "Second concept not found"); - assert_eq!(non_found_concept, None); } } \ No newline at end of file diff --git a/mps-cli-rs/src/model/smodel.rs b/mps-cli-rs/src/model/smodel.rs index fa781fa..834233b 100644 --- a/mps-cli-rs/src/model/smodel.rs +++ b/mps-cli-rs/src/model/smodel.rs @@ -1,9 +1,10 @@ use crate::model::snode::SNode; +use std::rc::Rc; pub struct SModel<'a> { pub name: String, pub uuid: String, - pub root_nodes: Vec>, + pub root_nodes: Vec>>, pub path_to_model_file: String, pub is_do_not_generate: bool, pub is_file_per_root_persistency: bool, @@ -21,16 +22,19 @@ impl<'a> SModel<'a> { } } - pub fn get_nodes(&self) -> Vec<&SNode> { + pub fn get_nodes(&'a self) -> Vec<&SNode<'a>> { let mut nodes: Vec<&SNode> = Vec::new(); for root in &self.root_nodes { - nodes.push(&root); + nodes.push(root); nodes.extend(root.get_descendants(false)); } return nodes; } - pub fn get_node_by_uuid(&self, uuid: &String) -> Option<&SNode> { - self.get_nodes().iter().find(|&node| node.uuid.eq(uuid)).copied() + pub fn get_node_by_uuid(&'a self, uuid: &'a String) -> Option>> { + /*let nodes = self.get_nodes(); + let n = nodes.iter().find(|&node| node.id.eq(uuid)); + if let Some(nn) = n { return Some(Rc::new(**nn)); }*/ + None } } diff --git a/mps-cli-rs/src/model/snode.rs b/mps-cli-rs/src/model/snode.rs index d1051ff..f95e122 100644 --- a/mps-cli-rs/src/model/snode.rs +++ b/mps-cli-rs/src/model/snode.rs @@ -1,72 +1,89 @@ -use std::collections::HashMap; +use std::{borrow::BorrowMut, collections::HashMap}; use crate::model::sconcept::{SConcept, SContainmentLink, SProperty, SReferenceLink}; +use std::rc::Rc; +use std::cell::RefCell; + +pub struct SNodeRef { + to : String, + resolve : Option, +} pub struct SNode<'a> { - pub(crate) uuid: String, - concept: &'a SConcept, + pub(crate) id: String, + concept: Rc, role_in_parent: Option, - properties: HashMap<&'a SProperty, String>, - children: HashMap<&'a SContainmentLink, Vec>>, - references: HashMap<&'a SReferenceLink, &'a SNode<'a>>, + properties: RefCell, String>>, + children: RefCell, Rc>>>>>, + references: RefCell, Rc>>, parent: Option<&'a SNode<'a>>, } impl<'a> SNode<'a> { - pub fn new(uuid: String, concept: &'a SConcept, role_in_parent: Option) -> Self { + pub fn new(id: String, concept: Rc, role_in_parent: Option) -> Self { SNode { - uuid, + id, concept, role_in_parent, - properties: HashMap::new(), - children: HashMap::new(), - references: HashMap::new(), + properties: RefCell::new(HashMap::new()), + children: RefCell::new(HashMap::new()), + references: RefCell::new(HashMap::new()), parent: None, } } - pub fn get_property(&self, property_name: &String) -> Option<&String> { - return match self.properties.keys().find(|&&key| key.name.eq(property_name)) { - Some(property) => self.properties.get(property), + pub fn get_property(&self, property_name: &String) -> Option { + let properties = self.properties.borrow(); + return match properties.keys().find(|&key| key.name.eq(property_name)) { + Some(property) => { let p = properties.get(property).unwrap().clone(); Some(p) } None => None }; } - pub fn add_property(&mut self, property: &'a SProperty, value: String) { - self.properties.insert(property, value); + pub fn add_property(&self, property: &Rc, value: String) { + let mut props = self.concept.properties.borrow_mut(); + self.properties.borrow_mut().insert(Rc::clone(property), value); } - pub fn add_reference(&mut self, reference: &'a SReferenceLink, referenced_node: &'a SNode<'_>) { - self.references.insert(reference, referenced_node); + pub fn add_reference(&self, reference_link: &Rc, to: String, resolve : Option) { + self.references.borrow_mut().insert(Rc::clone(reference_link), Rc::new(SNodeRef { + to : to, + resolve : resolve, + })); } - pub fn get_reference(&self, name: &String) -> Option<&&SNode> { - return match self.references.keys().find(|&&ref_link| ref_link.name.eq(name)) { - None => None, - Some(reference_link) => self.references.get(reference_link) - }; + pub fn add_child(&self, cl: Rc, node: Rc>) { + let mut children = self.children.borrow_mut(); + let vec = children.entry(Rc::clone(&cl)).or_insert(Rc::new(Vec::new())); + Rc::get_mut(vec).unwrap().push(Rc::clone(&node)); } - pub fn get_children(&self, name: &String) -> Option<&Vec> { + /*pub fn get_children(&self, name: &String) -> Option<&Vec> { return match self.children.keys().find(|&&containmetd_link| containmetd_link.name.eq(name)) { None => None, Some(containment_link) => self.children.get(containment_link) }; - } + }*/ - pub fn get_descendants(&self, include_self: bool) -> Vec<&'a SNode> { - let mut descendants: Vec<&SNode> = Vec::new(); + pub fn get_descendants(&'a self, include_self: bool) -> Vec<&SNode> { + let mut descendants: Vec<&SNode<'a>> = Vec::new(); if include_self { descendants.push(self) } self.get_descendants_internal(&mut descendants); return descendants; } - fn get_descendants_internal(&'a self, descendants: &mut Vec<&'a SNode<'a>>) { - for children in self.children.values() { - descendants.extend(children); - for child in children { - child.get_descendants_internal(descendants); + fn get_descendants_internal(&'a self, descendants: &mut Vec<&SNode<'a>>) { + /*let all_children_entries = self.children.borrow(); + let containment_links = all_children_entries.keys(); + + for containment_link in containment_links { + for children in all_children_entries.get(containment_link) { + for child in children { + descendants.push(child.as_ref()); + child.get_descendants_internal(descendants); + } } - } + }*/ + } } \ No newline at end of file diff --git a/mps-cli-rs/src/model/snoderef.rs b/mps-cli-rs/src/model/snoderef.rs index 754d084..c069b8e 100644 --- a/mps-cli-rs/src/model/snoderef.rs +++ b/mps-cli-rs/src/model/snoderef.rs @@ -1,5 +1,6 @@ use crate::model::snode::SNode; use crate::model::srepository::SRepository; +use std::rc::Rc; struct SNodeRef { model_uuid: String, @@ -14,10 +15,18 @@ impl SNodeRef { } } - pub fn resolve<'a>(&'a self, repository: &'a SRepository) -> Option<&SNode> { - return match repository.get_model_by_uuid(&self.model_uuid) { + pub fn resolve<'a>(&'a self, repository: &'a SRepository<'a>) -> Option>> { + /*return match repository.get_model_by_uuid(&self.model_uuid) { None => None, - Some(model) => model.get_node_by_uuid(&self.node_uuid) - }; + Some(model) => + if let Some(n) = model.get_node_by_uuid(&self.node_uuid) { + return Some(n); + } else { + return None; + } + };*/ + //let model = repository.get_model_by_uuid(&self.model_uuid).unwrap(); + //model.get_node_by_uuid(&self.node_uuid); + None } } \ No newline at end of file diff --git a/mps-cli-rs/src/model/srepository.rs b/mps-cli-rs/src/model/srepository.rs index b8a4794..3e6f10e 100644 --- a/mps-cli-rs/src/model/srepository.rs +++ b/mps-cli-rs/src/model/srepository.rs @@ -1,44 +1,45 @@ use std::collections::HashMap; -use uuid::Uuid; - use crate::model::slanguage::SLanguage; use crate::model::smodel::SModel; use crate::model::snode::SNode; use crate::model::ssolution::SSolution; +use std::rc::Rc; +use std::cell::RefCell; pub struct SRepository<'a> { - pub solutions: Vec>, - languages: Vec, + pub solutions: RefCell>>>, + languages: RefCell>>, - models: Vec<&'a SModel<'a>>, - nodes: Vec<&'a SNode<'a>>, - id_2_models_cache: HashMap>, - id_2_nodes_cache: HashMap>, + models: RefCell>>>, + nodes: RefCell>>>, } impl<'a> SRepository<'a> { - pub fn new(solutions: Vec>, languages: Vec) -> Self { + pub fn new(solutions: Vec>>, languages: Vec>) -> Self { SRepository { - solutions, - languages, - models: vec![], - nodes: vec![], - id_2_models_cache: HashMap::new(), - id_2_nodes_cache: HashMap::new(), + solutions : RefCell::new(solutions), + languages : RefCell::new(languages), + models: RefCell::new(vec![]), + nodes: RefCell::new(vec![]), } } - fn find_solution_by_name(&self, name: &String) -> Option<&SSolution> { - let found_solution = self.solutions.iter().find(|&ssolution| ssolution.name.eq(name)); - return found_solution; - } - - pub fn get_model_by_uuid(&self, uuid: &String) -> Option<&&SModel> { - self.models.iter().find(|&model| model.uuid.eq(uuid)) + pub fn find_solution_by_name(&self, name: &String) -> Option>> { + let solutions = self.solutions.borrow(); + let found_solution = solutions.iter().find(|&ssolution| ssolution.name.eq(name)); + if let Some(found_solution) = found_solution { + return Some(Rc::clone(found_solution)); + } + None } - fn find_model_by_name(&self, name: &String) -> Option<&SModel> { + pub fn get_model_by_uuid(&self, uuid: &'a String) -> Option>> { + let models = self.models.borrow(); + let res = models.iter().find(|&model| model.uuid.eq(uuid)); + if let Some(res) = res { + return Some(Rc::clone(res)); + } None - } + } } \ No newline at end of file From 18f17a53245f2c872b3f089d39649d127bbea942 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Fri, 17 May 2024 22:49:19 +0200 Subject: [PATCH 06/43] mini improvement --- .../smodel_builder_file_per_root_persistency.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index e20e94f..496baef 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -76,8 +76,9 @@ impl SModelBuilderFilePerRootPersistency { let mut roots = vec!(); for mpsr_file in mpsr_files.into_iter() { let file = mpsr_file.unwrap(); - let r = Self::build_root_node_from_file(file, &opt, language_builder, model_builder_cache); - roots.push(r.unwrap()); + if let Some(r) = Self::build_root_node_from_file(file, &opt, language_builder, model_builder_cache) { + roots.push(r); + } }; model.root_nodes.extend(roots); @@ -90,7 +91,7 @@ impl SModelBuilderFilePerRootPersistency { let file = std::fs::File::open(path_to_model_file.clone()); let mut s = String::new(); file.unwrap().read_to_string(&mut s); - let parse_res = roxmltree::Document::parse_with_options(&s, *opt); + let parse_res = roxmltree::Document::parse(&s); let document = parse_res.unwrap(); let model_element = document.root_element(); @@ -114,19 +115,20 @@ impl SModelBuilderFilePerRootPersistency { } fn build_root_node_from_file<'a>(dir_entry: DirEntry, opt : &ParsingOptions, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> Option>> { - println!("building root node from {}", dir_entry.path().as_os_str().to_str().unwrap()); + //println!("building root node from {}", dir_entry.path().as_os_str().to_str().unwrap()); let file = std::fs::File::open(dir_entry.path().as_os_str()); let mut s = String::new(); file.unwrap().read_to_string(&mut s); let parse_res = roxmltree::Document::parse_with_options(&s, *opt); + let document = parse_res.unwrap(); Self::parse_imports(&document, model_builder_cache); Self::parse_registry(&document, language_builder, model_builder_cache); let node = document.root_element().children().find(|it| it.tag_name().name() == "node"); let mut parent: Option> = None; - Some(Self::parse_node(&mut parent, &node.unwrap(), language_builder, &model_builder_cache)) + Some(Self::parse_node(&mut parent, &node.unwrap(), language_builder, &model_builder_cache)) } fn parse_imports(document: &Document, model_builder_cache : &SModelBuilderCache) { @@ -228,7 +230,7 @@ impl SModelBuilderFilePerRootPersistency { for ref_ in refs { let role = ref_.attributes().find(|a| a.name() == "role").unwrap().value(); let to = ref_.attributes().find(|a| a.name() == "to"); - let to = if let Some(t) = to { + let to: &str = if let Some(t) = to { t.value() } else { ref_.attributes().find(|a| a.name() == "node").unwrap().value() From 416d109b8c81cc3a9a58983d193872bc2c09c79a Mon Sep 17 00:00:00 2001 From: danielratiu Date: Sat, 18 May 2024 00:12:53 +0200 Subject: [PATCH 07/43] added profiling --- mps-cli-rs/src/builder/ssolution_builder.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mps-cli-rs/src/builder/ssolution_builder.rs b/mps-cli-rs/src/builder/ssolution_builder.rs index eada634..d535c9f 100644 --- a/mps-cli-rs/src/builder/ssolution_builder.rs +++ b/mps-cli-rs/src/builder/ssolution_builder.rs @@ -1,5 +1,6 @@ use std::borrow::BorrowMut; use std::path::PathBuf; +use std::time::Instant; use quick_xml::events::Event; use quick_xml::name::QName; @@ -15,10 +16,10 @@ use crate::model::ssolution::SSolution; use super::smodel_builder_file_per_root_persistency::SModelBuilderCache; pub fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> SSolution<'a> { + let now = Instant::now(); + let path_to_msd_file = convert_to_string(&path_buf_to_msd_file); let mut solution: SSolution = extract_solution_core_info(path_to_msd_file); - println!("Building from solution {}", solution.name); - let solution_dir = path_buf_to_msd_file.parent().unwrap(); let model_dir = convert_to_string(&solution_dir.to_path_buf()) + "/models"; @@ -35,6 +36,8 @@ pub fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_builder : &'a } solution.models.extend(models); + println!("Building from solution {} - {}ms", solution.name, now.elapsed().as_millis); + return solution; } From 6868e855513c2e63eb19d1981c18e61255d57181 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Sat, 18 May 2024 23:27:15 +0200 Subject: [PATCH 08/43] rs: cleanup --- mps-cli-rs/Cargo.toml | 6 +++- ...model_builder_file_per_root_persistency.rs | 30 +++++-------------- mps-cli-rs/src/builder/ssolution_builder.rs | 2 +- mps-cli-rs/src/model/sconcept.rs | 13 -------- mps-cli-rs/src/model/slanguage.rs | 19 ++---------- mps-cli-rs/src/model/smodel.rs | 12 ++++---- mps-cli-rs/src/model/snode.rs | 25 ++++++---------- 7 files changed, 31 insertions(+), 76 deletions(-) diff --git a/mps-cli-rs/Cargo.toml b/mps-cli-rs/Cargo.toml index 1d2cd85..8831e6f 100644 --- a/mps-cli-rs/Cargo.toml +++ b/mps-cli-rs/Cargo.toml @@ -10,4 +10,8 @@ uuid = { version = "1.8.0", features = ["v4"] } quick-xml = { version = "0.31.0", features = ["serialize"] } serde = { version = "1.0.197", features = ["derive"] } walkdir = "2.5.0" -roxmltree = "0.19.0" \ No newline at end of file +roxmltree = "0.19.0" + +[profile.release] +lto = "fat" +codegen-units = 1 \ No newline at end of file diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index 496baef..74a8fab 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -10,15 +10,12 @@ use roxmltree::{Document, Node}; use std::rc::Rc; use std::cell::RefCell; -use quick_xml::events::{attributes, Event}; -use quick_xml::Reader; use walkdir::{DirEntry, WalkDir}; use crate::builder::builder_helper::{convert_to_string, get_value_of_attribute_with_key, get_values_of_attributes_with_keys, panic_read_file, panic_unexpected_eof_read_file}; use crate::model::sconcept::{SConcept, SContainmentLink, SProperty, SReferenceLink}; use crate::model::smodel::SModel; use crate::model::snode::SNode; -use roxmltree::ParsingOptions; use super::slanguage_builder::SLanguageBuilder; @@ -51,17 +48,9 @@ impl SModelBuilderFilePerRootPersistency { } pub(crate) fn build_model<'a>(path_to_model: PathBuf, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> SModel<'a> { - let opt = roxmltree::ParsingOptions { - allow_dtd: true, - ..roxmltree::ParsingOptions::default() - }; - let mut model_file = path_to_model.clone(); model_file.push(".model"); - - let path_to_model_file = model_file.to_str().unwrap().to_string(); - - let mut model: SModel = Self::extract_model_core_info(model_file, &opt); + let mut model: SModel = Self::extract_model_core_info(model_file); let mpsr_file_walker = WalkDir::new(path_to_model).min_depth(1).max_depth(1); let mpsr_files = mpsr_file_walker.into_iter().filter(|entry| { @@ -76,7 +65,7 @@ impl SModelBuilderFilePerRootPersistency { let mut roots = vec!(); for mpsr_file in mpsr_files.into_iter() { let file = mpsr_file.unwrap(); - if let Some(r) = Self::build_root_node_from_file(file, &opt, language_builder, model_builder_cache) { + if let Some(r) = Self::build_root_node_from_file(file, language_builder, model_builder_cache) { roots.push(r); } }; @@ -85,7 +74,7 @@ impl SModelBuilderFilePerRootPersistency { return model; } - fn extract_model_core_info<'a>(path_to_model: PathBuf, opt : &ParsingOptions) -> SModel<'a> { + fn extract_model_core_info<'a>(path_to_model: PathBuf) -> SModel<'a> { let path_to_model_file = path_to_model.to_str().unwrap().to_string(); let file = std::fs::File::open(path_to_model_file.clone()); @@ -114,13 +103,13 @@ impl SModelBuilderFilePerRootPersistency { return SModel::new(name, uuid, path_to_model_file, is_do_not_generate, true); } - fn build_root_node_from_file<'a>(dir_entry: DirEntry, opt : &ParsingOptions, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> Option>> { + fn build_root_node_from_file<'a>(dir_entry: DirEntry, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> Option>> { //println!("building root node from {}", dir_entry.path().as_os_str().to_str().unwrap()); let file = std::fs::File::open(dir_entry.path().as_os_str()); let mut s = String::new(); file.unwrap().read_to_string(&mut s); - let parse_res = roxmltree::Document::parse_with_options(&s, *opt); + let parse_res = roxmltree::Document::parse_with_options(&s, roxmltree::ParsingOptions::default()); let document = parse_res.unwrap(); Self::parse_imports(&document, model_builder_cache); @@ -209,7 +198,7 @@ impl SModelBuilderFilePerRootPersistency { let index_2_concept = model_builder_cache.index_2_concept.borrow(); let my_concept = index_2_concept.get(concept_index).unwrap(); - let mut current_node : Rc = Rc::new(SNode::new(node_id.to_string(), Rc::clone(my_concept), role.clone())); + let current_node : Rc = Rc::new(SNode::new(node_id.to_string(), Rc::clone(my_concept), role.clone())); if let Some(parent) = parent_node { let index_2_containment_link = model_builder_cache.index_2_containment_link.borrow(); @@ -268,16 +257,11 @@ mod tests { #[test] fn test_model_extract_core_info() { - let opt = roxmltree::ParsingOptions { - allow_dtd: true, - ..roxmltree::ParsingOptions::default() - }; - // given let path_to_model_file = PathBuf::from(get_path_to_model_mpsr_example_lib_file()); //when - let model = SModelBuilderFilePerRootPersistency::extract_model_core_info(path_to_model_file, &opt); + let model = SModelBuilderFilePerRootPersistency::extract_model_core_info(path_to_model_file); //assert assert_eq!(model.name, "mps.cli.lanuse.library_top.library_top"); diff --git a/mps-cli-rs/src/builder/ssolution_builder.rs b/mps-cli-rs/src/builder/ssolution_builder.rs index d535c9f..8915cd0 100644 --- a/mps-cli-rs/src/builder/ssolution_builder.rs +++ b/mps-cli-rs/src/builder/ssolution_builder.rs @@ -36,7 +36,7 @@ pub fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_builder : &'a } solution.models.extend(models); - println!("Building from solution {} - {}ms", solution.name, now.elapsed().as_millis); + println!("Building from solution {} - {}ms", solution.name, now.elapsed().as_millis()); return solution; } diff --git a/mps-cli-rs/src/model/sconcept.rs b/mps-cli-rs/src/model/sconcept.rs index 7efc773..ca655ee 100644 --- a/mps-cli-rs/src/model/sconcept.rs +++ b/mps-cli-rs/src/model/sconcept.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; -use uuid::Uuid; use std::cell::RefCell; use std::rc::Rc; @@ -83,16 +82,4 @@ impl SReferenceLink { id, } } -} - -#[cfg(test)] -mod tests { - use uuid::Uuid; - - use crate::model::sconcept::{SConcept, SContainmentLink, SProperty, SReferenceLink}; - - #[test] - fn test_sconcept() { - - } } \ No newline at end of file diff --git a/mps-cli-rs/src/model/slanguage.rs b/mps-cli-rs/src/model/slanguage.rs index 502a519..f2fdf75 100644 --- a/mps-cli-rs/src/model/slanguage.rs +++ b/mps-cli-rs/src/model/slanguage.rs @@ -5,29 +5,16 @@ use std::rc::Rc; #[derive(Clone)] pub struct SLanguage { pub name: String, - pub uuid: String, + pub id: String, pub concepts: RefCell>>, } impl SLanguage { - pub fn new(name: String, uuid: String) -> Self { + pub fn new(name: String, id: String) -> Self { SLanguage { name, - uuid, + id, concepts: RefCell::new(vec![]), } } } - -#[cfg(test)] -mod tests { - use uuid::Uuid; - - use crate::model::sconcept::SConcept; - use crate::model::slanguage::SLanguage; - - #[test] - fn test_find_concept_by_name() { - - } -} \ No newline at end of file diff --git a/mps-cli-rs/src/model/smodel.rs b/mps-cli-rs/src/model/smodel.rs index 834233b..3006be1 100644 --- a/mps-cli-rs/src/model/smodel.rs +++ b/mps-cli-rs/src/model/smodel.rs @@ -24,17 +24,17 @@ impl<'a> SModel<'a> { pub fn get_nodes(&'a self) -> Vec<&SNode<'a>> { let mut nodes: Vec<&SNode> = Vec::new(); - for root in &self.root_nodes { + /*for root in &self.root_nodes { nodes.push(root); nodes.extend(root.get_descendants(false)); - } + }*/ return nodes; } - pub fn get_node_by_uuid(&'a self, uuid: &'a String) -> Option>> { + pub fn get_node_by_id(&'a self, id: &'a String) -> Option>> { /*let nodes = self.get_nodes(); - let n = nodes.iter().find(|&node| node.id.eq(uuid)); - if let Some(nn) = n { return Some(Rc::new(**nn)); }*/ - None + let n = nodes.iter().find(|node| node.id.eq(id)); + if let Some(nn) = n { return Some(Rc::new(**nn)); } + */None } } diff --git a/mps-cli-rs/src/model/snode.rs b/mps-cli-rs/src/model/snode.rs index f95e122..baf1bf1 100644 --- a/mps-cli-rs/src/model/snode.rs +++ b/mps-cli-rs/src/model/snode.rs @@ -65,25 +65,18 @@ impl<'a> SNode<'a> { }; }*/ - pub fn get_descendants(&'a self, include_self: bool) -> Vec<&SNode> { - let mut descendants: Vec<&SNode<'a>> = Vec::new(); - if include_self { descendants.push(self) } - self.get_descendants_internal(&mut descendants); + pub fn get_descendants(&'a self, include_self: bool) -> Vec>> { + let mut descendants: Vec>> = Vec::new(); + //if include_self { descendants.push(Rc::new(self)) } + //self.get_descendants_internal(&mut descendants); return descendants; } - fn get_descendants_internal(&'a self, descendants: &mut Vec<&SNode<'a>>) { - /*let all_children_entries = self.children.borrow(); - let containment_links = all_children_entries.keys(); - - for containment_link in containment_links { - for children in all_children_entries.get(containment_link) { - for child in children { - descendants.push(child.as_ref()); - child.get_descendants_internal(descendants); - } - } + fn get_descendants_internal(self, descendants: &mut Vec>>) { + /*let vectors_of_children = self.children.borrow().values().flatten().collect::>>; + for child in ..flatten() { + descendants.push(child.as_ref()); + child.get_descendants_internal(descendants); }*/ - } } \ No newline at end of file From 69b1c9ac756d5ec4f1a8a8cfaef29608a1f40769 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Sat, 18 May 2024 23:47:23 +0200 Subject: [PATCH 09/43] rs: simplify the code --- .../smodel_builder_file_per_root_persistency.rs | 1 + mps-cli-rs/src/model/snode.rs | 16 ++++++++++------ mps-cli-rs/src/model/srepository.rs | 2 -- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index 74a8fab..84a000f 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -204,6 +204,7 @@ impl SModelBuilderFilePerRootPersistency { let index_2_containment_link = model_builder_cache.index_2_containment_link.borrow(); let cl = index_2_containment_link.get(&role.unwrap()); parent.borrow_mut().add_child(Rc::clone(cl.unwrap()), Rc::clone(¤t_node)); + current_node.set_parent(Rc::clone(parent)); }; let properties = node.children().filter(|it| it.tag_name().name() == "property"); diff --git a/mps-cli-rs/src/model/snode.rs b/mps-cli-rs/src/model/snode.rs index baf1bf1..ca26acc 100644 --- a/mps-cli-rs/src/model/snode.rs +++ b/mps-cli-rs/src/model/snode.rs @@ -1,4 +1,4 @@ -use std::{borrow::BorrowMut, collections::HashMap}; +use std::collections::HashMap; use crate::model::sconcept::{SConcept, SContainmentLink, SProperty, SReferenceLink}; use std::rc::Rc; @@ -14,9 +14,9 @@ pub struct SNode<'a> { concept: Rc, role_in_parent: Option, properties: RefCell, String>>, - children: RefCell, Rc>>>>>, + children: RefCell, Vec>>>>, references: RefCell, Rc>>, - parent: Option<&'a SNode<'a>>, + parent: RefCell>>>, } impl<'a> SNode<'a> { @@ -28,7 +28,7 @@ impl<'a> SNode<'a> { properties: RefCell::new(HashMap::new()), children: RefCell::new(HashMap::new()), references: RefCell::new(HashMap::new()), - parent: None, + parent: RefCell::new(None), } } @@ -54,8 +54,12 @@ impl<'a> SNode<'a> { pub fn add_child(&self, cl: Rc, node: Rc>) { let mut children = self.children.borrow_mut(); - let vec = children.entry(Rc::clone(&cl)).or_insert(Rc::new(Vec::new())); - Rc::get_mut(vec).unwrap().push(Rc::clone(&node)); + let vec = children.entry(Rc::clone(&cl)).or_insert(Vec::new()); + vec.push(Rc::clone(&node)); + } + + pub fn set_parent(&self, parent : Rc>) { + self.parent.replace(Some(parent)); } /*pub fn get_children(&self, name: &String) -> Option<&Vec> { diff --git a/mps-cli-rs/src/model/srepository.rs b/mps-cli-rs/src/model/srepository.rs index 3e6f10e..7cf6299 100644 --- a/mps-cli-rs/src/model/srepository.rs +++ b/mps-cli-rs/src/model/srepository.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use crate::model::slanguage::SLanguage; use crate::model::smodel::SModel; use crate::model::snode::SNode; From 8ae3f91b8515dbea25b93ae6f226d9992312573e Mon Sep 17 00:00:00 2001 From: danielratiu Date: Mon, 20 May 2024 21:14:22 +0200 Subject: [PATCH 10/43] mps-cli.rs: cleanup --- mps-cli-rs/src/builder/slanguage_builder.rs | 2 - ...model_builder_file_per_root_persistency.rs | 40 ++++++++++++++----- mps-cli-rs/src/model/mod.rs | 2 +- mps-cli-rs/src/model/sconcept.rs | 6 +-- mps-cli-rs/src/model/smodel.rs | 4 +- mps-cli-rs/src/model/snode.rs | 35 ++++++++++------ 6 files changed, 59 insertions(+), 30 deletions(-) diff --git a/mps-cli-rs/src/builder/slanguage_builder.rs b/mps-cli-rs/src/builder/slanguage_builder.rs index 7a01db6..0b625fc 100644 --- a/mps-cli-rs/src/builder/slanguage_builder.rs +++ b/mps-cli-rs/src/builder/slanguage_builder.rs @@ -1,7 +1,5 @@ -use std::borrow::BorrowMut; use std::cell::RefCell; use std::collections::HashMap; -use std::sync::Mutex; use std::rc::Rc; use crate::model::sconcept::{SConcept, SContainmentLink, SProperty, SReferenceLink}; diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index 84a000f..bc985f2 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -99,8 +99,9 @@ impl SModelBuilderFilePerRootPersistency { if do_not_generate_str == "true" { is_do_not_generate = true; } } - - return SModel::new(name, uuid, path_to_model_file, is_do_not_generate, true); + let imports_element = model_element.children().find(|c| c.tag_name().name() == "imports"); + + return SModel::new(name, uuid, path_to_model_file, Vec::new(), is_do_not_generate, true); } fn build_root_node_from_file<'a>(dir_entry: DirEntry, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> Option>> { @@ -198,7 +199,15 @@ impl SModelBuilderFilePerRootPersistency { let index_2_concept = model_builder_cache.index_2_concept.borrow(); let my_concept = index_2_concept.get(concept_index).unwrap(); - let current_node : Rc = Rc::new(SNode::new(node_id.to_string(), Rc::clone(my_concept), role.clone())); + let role_human_readable = match role.clone() { + Some(role_string) => { + let index_2_containment_link = model_builder_cache.index_2_containment_link.borrow(); + let r = index_2_containment_link.get(&role_string).unwrap(); + Some(String::from(&r.name)) + }, + None => None, + }; + let current_node : Rc = Rc::new(SNode::new(node_id.to_string(), Rc::clone(my_concept), role_human_readable)); if let Some(parent) = parent_node { let index_2_containment_link = model_builder_cache.index_2_containment_link.borrow(); @@ -275,18 +284,29 @@ mod tests { #[test] fn test_build_model() { // given - let path_to_mpsr_file = PathBuf::from(get_path_to_example_mpsr_model_files()); + let path = "../mps_test_projects/mps_cli_lanuse_file_per_root/solutions/mps.cli.lanuse.library_top/models/mps.cli.lanuse.library_top.library_top"; + let path_to_mpsr_file = PathBuf::from(path); //when let mut language_builder = SLanguageBuilder::new(); let mut model_builder_cache = SModelBuilderCache::new(); - SModelBuilderFilePerRootPersistency::build_model(path_to_mpsr_file, &mut language_builder, &model_builder_cache); + let model = SModelBuilderFilePerRootPersistency::build_model(path_to_mpsr_file, &mut language_builder, &model_builder_cache); //assert - let index_2_imported_model_uuid = model_builder_cache.index_2_imported_model_uuid.borrow(); - assert_eq!(index_2_imported_model_uuid.len(), 1); - assert!(index_2_imported_model_uuid.contains_key(&"q0v6".to_string())); - let imported_model_uuid = index_2_imported_model_uuid.get(&"q0v6".to_string()).unwrap(); - assert_eq!(**imported_model_uuid, "r:ec5f093b-9d83-43a1-9b41-b5952da8b1ed".to_string()); + assert_eq!(model.root_nodes.len(), 2); + let munich_library = model.root_nodes.first().unwrap(); + assert_eq!(munich_library.get_property("name"), Some(String::from("munich_library"))); + + let munich_library_entities = munich_library.get_children("entities"); + assert_eq!(munich_library_entities.len(), 4); + let tom_sawyer = munich_library_entities.first().unwrap(); + assert_eq!(tom_sawyer.get_property("name"), Some(String::from("Tom Sawyer"))); + assert_eq!(tom_sawyer.role_in_parent, Some(String::from("entities"))); + assert_eq!(tom_sawyer.get_property("publicationDate"), Some(String::from("1876"))); + assert_eq!(tom_sawyer.get_property("isbn"), Some(String::from("4323r2"))); + assert_eq!(tom_sawyer.get_property("available"), Some(String::from("true"))); + assert_eq!(tom_sawyer.concept.name, String::from("mps.cli.landefs.library.structure.Book")); + + } } diff --git a/mps-cli-rs/src/model/mod.rs b/mps-cli-rs/src/model/mod.rs index 6d24907..e03e1b8 100644 --- a/mps-cli-rs/src/model/mod.rs +++ b/mps-cli-rs/src/model/mod.rs @@ -2,6 +2,6 @@ pub mod sconcept; pub mod slanguage; pub mod smodel; pub mod snode; -mod snoderef; +pub mod snoderef; pub mod ssolution; pub mod srepository; \ No newline at end of file diff --git a/mps-cli-rs/src/model/sconcept.rs b/mps-cli-rs/src/model/sconcept.rs index ca655ee..61b17bf 100644 --- a/mps-cli-rs/src/model/sconcept.rs +++ b/mps-cli-rs/src/model/sconcept.rs @@ -6,7 +6,7 @@ use std::rc::Rc; #[derive(Debug, PartialEq, Clone)] pub struct SConcept { pub(crate) name: String, - uuid: String, + id: String, pub(crate) properties: RefCell>>, pub containment_links: RefCell>>, pub reference_links: RefCell>>, @@ -31,10 +31,10 @@ pub struct SReferenceLink { } impl SConcept { - pub fn new(name: String, uuid: String) -> Self { + pub fn new(name: String, id: String) -> Self { SConcept { name: name.to_string(), - uuid, + id, properties: RefCell::new(HashMap::new()), containment_links: RefCell::new(HashMap::new()), reference_links: RefCell::new(HashMap::new()), diff --git a/mps-cli-rs/src/model/smodel.rs b/mps-cli-rs/src/model/smodel.rs index 3006be1..cd12229 100644 --- a/mps-cli-rs/src/model/smodel.rs +++ b/mps-cli-rs/src/model/smodel.rs @@ -8,15 +8,17 @@ pub struct SModel<'a> { pub path_to_model_file: String, pub is_do_not_generate: bool, pub is_file_per_root_persistency: bool, + pub imported_models: Vec>> } impl<'a> SModel<'a> { - pub fn new(name: String, uuid: String, path_to_model_file: String, is_do_not_generate: bool, is_file_per_root_persistency: bool) -> Self { + pub fn new(name: String, uuid: String, path_to_model_file: String, imported_models : Vec>>, is_do_not_generate: bool, is_file_per_root_persistency: bool) -> Self { SModel { name, uuid, root_nodes: vec![], path_to_model_file, + imported_models, is_do_not_generate, is_file_per_root_persistency, } diff --git a/mps-cli-rs/src/model/snode.rs b/mps-cli-rs/src/model/snode.rs index ca26acc..2074f20 100644 --- a/mps-cli-rs/src/model/snode.rs +++ b/mps-cli-rs/src/model/snode.rs @@ -10,13 +10,13 @@ pub struct SNodeRef { } pub struct SNode<'a> { - pub(crate) id: String, - concept: Rc, - role_in_parent: Option, + pub id: String, + pub concept: Rc, + pub role_in_parent: Option, properties: RefCell, String>>, children: RefCell, Vec>>>>, references: RefCell, Rc>>, - parent: RefCell>>>, + pub parent: RefCell>>>, } impl<'a> SNode<'a> { @@ -32,19 +32,19 @@ impl<'a> SNode<'a> { } } - pub fn get_property(&self, property_name: &String) -> Option { - let properties = self.properties.borrow(); - return match properties.keys().find(|&key| key.name.eq(property_name)) { - Some(property) => { let p = properties.get(property).unwrap().clone(); Some(p) } - None => None - }; - } - pub fn add_property(&self, property: &Rc, value: String) { - let mut props = self.concept.properties.borrow_mut(); self.properties.borrow_mut().insert(Rc::clone(property), value); } + pub fn get_property(&self, property_name: &str) -> Option { + let properties = self.properties.borrow(); + let entry = properties.iter().find(|it| it.0.name.eq(property_name)); + return match entry { + Some(key_val) => { Some(String::clone(key_val.1)) } + None => None + } + } + pub fn add_reference(&self, reference_link: &Rc, to: String, resolve : Option) { self.references.borrow_mut().insert(Rc::clone(reference_link), Rc::new(SNodeRef { to : to, @@ -58,6 +58,15 @@ impl<'a> SNode<'a> { vec.push(Rc::clone(&node)); } + pub fn get_children(&self, child_role_name: &str) -> Vec>> { + let children = self.children.borrow(); + let entry = children.iter().find(|it| it.0.name.eq(child_role_name)); + match entry { + Some(e) => e.1.clone(), + None => Vec::new() + } + } + pub fn set_parent(&self, parent : Rc>) { self.parent.replace(Some(parent)); } From 87f6f21af81280b94df82a9d8a549228577cef84 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Mon, 20 May 2024 22:59:03 +0200 Subject: [PATCH 11/43] mps-cli.rs: support for imported models --- ...model_builder_file_per_root_persistency.rs | 57 +++++++++++++++---- .../builder/smodules_repository_builder.rs | 14 +++-- mps-cli-rs/src/builder/ssolution_builder.rs | 2 +- mps-cli-rs/src/model/smodel.rs | 14 ++--- mps-cli-rs/src/model/ssolution.rs | 4 +- 5 files changed, 66 insertions(+), 25 deletions(-) diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index bc985f2..fd45c24 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -20,15 +20,16 @@ use super::slanguage_builder::SLanguageBuilder; #[derive(Clone)] -pub struct SModelBuilderCache { +pub struct SModelBuilderCache<'a> { pub index_2_concept: RefCell>>, pub index_2_property: RefCell>>, pub index_2_containment_link: RefCell>>, pub index_2_reference_link: RefCell>>, pub index_2_imported_model_uuid: RefCell>, + pub index_2_model : RefCell>>>>, } -impl SModelBuilderCache { +impl<'a> SModelBuilderCache<'a> { pub fn new() -> Self { SModelBuilderCache { index_2_concept: RefCell::new(HashMap::new()), @@ -36,8 +37,21 @@ impl SModelBuilderCache { index_2_containment_link : RefCell::new(HashMap::new()), index_2_reference_link : RefCell::new(HashMap::new()), index_2_imported_model_uuid: RefCell::new(HashMap::new()), + index_2_model: RefCell::new(HashMap::new()), } } + + pub fn get_model(&'a self, name : String, uuid : String) -> Rc>> { + let mut i2m = self.index_2_model.borrow_mut(); + if let Some(model) = i2m.get(&uuid) { + Rc::clone(&model) + } else { + let temp = Rc::new(RefCell::new(SModel::new(name.clone(), uuid.clone()))); + i2m.insert(uuid, temp.clone()); + temp + } + } + } pub struct SModelBuilderFilePerRootPersistency {} @@ -47,10 +61,10 @@ impl SModelBuilderFilePerRootPersistency { SModelBuilderFilePerRootPersistency {} } - pub(crate) fn build_model<'a>(path_to_model: PathBuf, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> SModel<'a> { + pub(crate) fn build_model<'a>(path_to_model: PathBuf, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache<'a>) -> Rc>> { let mut model_file = path_to_model.clone(); model_file.push(".model"); - let mut model: SModel = Self::extract_model_core_info(model_file); + let mut model: Rc>> = Self::extract_model_core_info(model_file, &model_builder_cache); let mpsr_file_walker = WalkDir::new(path_to_model).min_depth(1).max_depth(1); let mpsr_files = mpsr_file_walker.into_iter().filter(|entry| { @@ -69,12 +83,12 @@ impl SModelBuilderFilePerRootPersistency { roots.push(r); } }; - model.root_nodes.extend(roots); + model.as_ref().borrow_mut().root_nodes.extend(roots); return model; } - fn extract_model_core_info<'a>(path_to_model: PathBuf) -> SModel<'a> { + fn extract_model_core_info<'a>(path_to_model: PathBuf, model_builder_cache : &'a SModelBuilderCache<'a>) -> Rc>> { let path_to_model_file = path_to_model.to_str().unwrap().to_string(); let file = std::fs::File::open(path_to_model_file.clone()); @@ -99,9 +113,25 @@ impl SModelBuilderFilePerRootPersistency { if do_not_generate_str == "true" { is_do_not_generate = true; } } - let imports_element = model_element.children().find(|c| c.tag_name().name() == "imports"); + let mut my_model = model_builder_cache.get_model(name, uuid); + my_model.as_ref().borrow_mut().path_to_model_file = path_to_model_file; + my_model.as_ref().borrow_mut().is_do_not_generate = is_do_not_generate; + my_model.as_ref().borrow_mut().is_file_per_root_persistency = true; + + let imports = model_element.children().find(|c| c.tag_name().name() == "imports").unwrap(); + for import in imports.children() { + let tag_name = import.tag_name(); + if tag_name.name() == "import" { + let uuid_att = import.attributes().find(|a| a.name() == "ref").unwrap().value(); + + let uuid = uuid_att.to_string()[0..uuid_att.find('(').unwrap()].to_string(); + let name = uuid_att.to_string()[uuid_att.find('(').unwrap()+1..uuid_att.find(')').unwrap()].to_string(); + let imported_model = model_builder_cache.get_model(name, uuid); + my_model.as_ref().borrow_mut().imported_models.push(imported_model); + } + } - return SModel::new(name, uuid, path_to_model_file, Vec::new(), is_do_not_generate, true); + my_model.clone() } fn build_root_node_from_file<'a>(dir_entry: DirEntry, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> Option>> { @@ -271,7 +301,9 @@ mod tests { let path_to_model_file = PathBuf::from(get_path_to_model_mpsr_example_lib_file()); //when - let model = SModelBuilderFilePerRootPersistency::extract_model_core_info(path_to_model_file); + let mut model_builder_cache = SModelBuilderCache::new(); + let temp = SModelBuilderFilePerRootPersistency::extract_model_core_info(path_to_model_file, &model_builder_cache); + let model = temp.borrow(); //assert assert_eq!(model.name, "mps.cli.lanuse.library_top.library_top"); @@ -279,6 +311,10 @@ mod tests { assert_eq!(model.path_to_model_file, get_path_to_model_mpsr_example_lib_file()); assert_eq!(model.is_do_not_generate, true); assert!(model.is_file_per_root_persistency); + assert_eq!(model.imported_models.len(), 1); + let import = model.imported_models.first().unwrap(); + assert_eq!(import.borrow_mut().name, "mps.cli.lanuse.library_top.authors_top"); + assert_eq!(import.borrow_mut().uuid, "r:ec5f093b-9d83-43a1-9b41-b5952da8b1ed"); } #[test] @@ -290,7 +326,8 @@ mod tests { //when let mut language_builder = SLanguageBuilder::new(); let mut model_builder_cache = SModelBuilderCache::new(); - let model = SModelBuilderFilePerRootPersistency::build_model(path_to_mpsr_file, &mut language_builder, &model_builder_cache); + let temp = SModelBuilderFilePerRootPersistency::build_model(path_to_mpsr_file, &mut language_builder, &model_builder_cache); + let model = temp.as_ref().borrow(); //assert assert_eq!(model.root_nodes.len(), 2); diff --git a/mps-cli-rs/src/builder/smodules_repository_builder.rs b/mps-cli-rs/src/builder/smodules_repository_builder.rs index aad9cad..be45f11 100644 --- a/mps-cli-rs/src/builder/smodules_repository_builder.rs +++ b/mps-cli-rs/src/builder/smodules_repository_builder.rs @@ -11,7 +11,7 @@ use crate::model::srepository::SRepository; use crate::model::ssolution::SSolution; use crate::model::slanguage::SLanguage; -pub fn build_repo_from_directories<'a>(source_dirs: Vec, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> SRepository<'a> { +pub fn build_repo_from_directories<'a>(source_dirs: Vec, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache<'a>) -> SRepository<'a> { let mut all_solutions : Vec> = Vec::new(); for source_dir in source_dirs { @@ -25,7 +25,7 @@ pub fn build_repo_from_directories<'a>(source_dirs: Vec, language_builde } -pub fn build_repo_from_directory<'a>(source_dir: String, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> SRepository<'a> { +pub fn build_repo_from_directory<'a>(source_dir: String, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache<'a>) -> SRepository<'a> { let mut all_solutions : Vec> = Vec::new(); let solutions = build_solutions_from(source_dir, language_builder, model_builder_cache); solutions.into_iter().for_each(|s| all_solutions.push(Rc::new(s))); @@ -35,7 +35,7 @@ pub fn build_repo_from_directory<'a>(source_dir: String, language_builder : &'a SRepository::new(all_solutions, languages) } -fn build_solutions_from<'a>(source_dir: String, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> Vec> { +fn build_solutions_from<'a>(source_dir: String, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache<'a>) -> Vec> { let now = Instant::now(); let solutions = collect_modules_from_sources(source_dir.clone(), language_builder, model_builder_cache); let elapsed = now.elapsed(); @@ -44,7 +44,7 @@ fn build_solutions_from<'a>(source_dir: String, language_builder : &'a SLanguage return solutions; } -pub fn collect_modules_from_sources<'a>(source_dir: String, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> Vec> { +pub fn collect_modules_from_sources<'a>(source_dir: String, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache<'a>) -> Vec> { let msd_files = find_msd_files(&source_dir, 3); let solutions: Vec = msd_files.iter().map(|msd_file| build_solution(msd_file, language_builder, &model_builder_cache)).collect(); return solutions; @@ -69,6 +69,8 @@ pub fn find_msd_files(source_dir: &String, start_depth: usize) -> Vec { #[cfg(test)] mod tests { use core::num; + use std::cell::RefCell; + use std::rc::Rc; use crate::builder::slanguage_builder::SLanguageBuilder; use crate::builder::smodel_builder_file_per_root_persistency::SModelBuilderCache; @@ -103,8 +105,8 @@ mod tests { //then let required_time = now.elapsed().as_millis(); let solutions = repository.solutions.borrow(); - let models: Vec<&SModel> = solutions.iter().flat_map(|solution| &solution.models).collect(); - let do_not_gen_models: Vec<&&SModel> = models.iter().filter(|&model| model.is_do_not_generate).collect(); + let models: Vec<&Rc>> = solutions.iter().flat_map(|solution| &solution.models).collect(); + let do_not_gen_models: Vec<&&Rc>> = models.iter().filter(|&model| model.as_ref().borrow().is_do_not_generate).collect(); let number_of_solutions = repository.solutions.borrow().len(); println!("Found {} solutions with {} models (out of which {} are set to do not generate) in {} ms", number_of_solutions, models.len(), do_not_gen_models.len(), required_time); assert!(number_of_solutions > 1); diff --git a/mps-cli-rs/src/builder/ssolution_builder.rs b/mps-cli-rs/src/builder/ssolution_builder.rs index 8915cd0..58285ee 100644 --- a/mps-cli-rs/src/builder/ssolution_builder.rs +++ b/mps-cli-rs/src/builder/ssolution_builder.rs @@ -15,7 +15,7 @@ use crate::model::ssolution::SSolution; use super::smodel_builder_file_per_root_persistency::SModelBuilderCache; -pub fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> SSolution<'a> { +pub fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache<'a>) -> SSolution<'a> { let now = Instant::now(); let path_to_msd_file = convert_to_string(&path_buf_to_msd_file); diff --git a/mps-cli-rs/src/model/smodel.rs b/mps-cli-rs/src/model/smodel.rs index cd12229..7f83ce8 100644 --- a/mps-cli-rs/src/model/smodel.rs +++ b/mps-cli-rs/src/model/smodel.rs @@ -1,5 +1,5 @@ use crate::model::snode::SNode; -use std::rc::Rc; +use std::{cell::RefCell, rc::Rc}; pub struct SModel<'a> { pub name: String, @@ -8,19 +8,19 @@ pub struct SModel<'a> { pub path_to_model_file: String, pub is_do_not_generate: bool, pub is_file_per_root_persistency: bool, - pub imported_models: Vec>> + pub imported_models: Vec>>> } impl<'a> SModel<'a> { - pub fn new(name: String, uuid: String, path_to_model_file: String, imported_models : Vec>>, is_do_not_generate: bool, is_file_per_root_persistency: bool) -> Self { + pub fn new(name: String, uuid: String) -> Self { SModel { name, uuid, root_nodes: vec![], - path_to_model_file, - imported_models, - is_do_not_generate, - is_file_per_root_persistency, + path_to_model_file : String::from(""), + imported_models : vec![], + is_do_not_generate : false, + is_file_per_root_persistency : false, } } diff --git a/mps-cli-rs/src/model/ssolution.rs b/mps-cli-rs/src/model/ssolution.rs index 41d441a..60729c1 100644 --- a/mps-cli-rs/src/model/ssolution.rs +++ b/mps-cli-rs/src/model/ssolution.rs @@ -1,10 +1,12 @@ +use std::{cell::RefCell, rc::Rc}; + use crate::model::smodel::SModel; pub struct SSolution<'a> { pub name: String, pub uuid: String, path_to_module_file: String, - pub models: Vec>, + pub models: Vec>>>, } impl<'a> SSolution<'a> { From 56d857e0ecf9cc0e2d42967c027362280424fb77 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Tue, 21 May 2024 14:00:25 +0200 Subject: [PATCH 12/43] mps-cli.rs: get_descendants of nodes, get_nodes of a model - new tests --- ...model_builder_file_per_root_persistency.rs | 27 +++++++++++++++--- .../builder/smodules_repository_builder.rs | 3 +- mps-cli-rs/src/model/smodel.rs | 12 ++++---- mps-cli-rs/src/model/snode.rs | 28 ++++++++----------- 4 files changed, 41 insertions(+), 29 deletions(-) diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index fd45c24..4d200d0 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -289,11 +289,12 @@ impl SModelBuilderFilePerRootPersistency { #[cfg(test)] mod tests { use std::path::PathBuf; + use std::rc::Rc; use crate::builder::slanguage_builder::SLanguageBuilder; use crate::builder::smodel_builder_file_per_root_persistency::{SModelBuilderCache, SModelBuilderFilePerRootPersistency}; - use crate::builder::test_helper::{get_path_to_model_mpsr_example_lib_file, get_path_to_mpsr_example_lib_file}; - use crate::builder::test_helper::get_path_to_example_mpsr_model_files; + use crate::builder::test_helper::get_path_to_model_mpsr_example_lib_file; + use crate::model::snode::SNode; #[test] fn test_model_extract_core_info() { @@ -301,7 +302,7 @@ mod tests { let path_to_model_file = PathBuf::from(get_path_to_model_mpsr_example_lib_file()); //when - let mut model_builder_cache = SModelBuilderCache::new(); + let model_builder_cache = SModelBuilderCache::new(); let temp = SModelBuilderFilePerRootPersistency::extract_model_core_info(path_to_model_file, &model_builder_cache); let model = temp.borrow(); @@ -325,7 +326,7 @@ mod tests { //when let mut language_builder = SLanguageBuilder::new(); - let mut model_builder_cache = SModelBuilderCache::new(); + let model_builder_cache = SModelBuilderCache::new(); let temp = SModelBuilderFilePerRootPersistency::build_model(path_to_mpsr_file, &mut language_builder, &model_builder_cache); let model = temp.as_ref().borrow(); @@ -343,7 +344,25 @@ mod tests { assert_eq!(tom_sawyer.get_property("isbn"), Some(String::from("4323r2"))); assert_eq!(tom_sawyer.get_property("available"), Some(String::from("true"))); assert_eq!(tom_sawyer.concept.name, String::from("mps.cli.landefs.library.structure.Book")); + } + #[test] + fn test_navigate_model() { + // given + let path = "../mps_test_projects/mps_cli_lanuse_file_per_root/solutions/mps.cli.lanuse.library_top/models/mps.cli.lanuse.library_top.library_top"; + let path_to_mpsr_file = PathBuf::from(path); + //when + let mut language_builder = SLanguageBuilder::new(); + let model_builder_cache = SModelBuilderCache::new(); + let temp = SModelBuilderFilePerRootPersistency::build_model(path_to_mpsr_file, &mut language_builder, &model_builder_cache); + let m = temp.as_ref().borrow(); + + //assert + let munich_library_root = m.root_nodes.first().unwrap(); + assert_eq!(munich_library_root.get_property("name"), Some(String::from("munich_library"))); + assert_eq!(SNode::get_descendants(Rc::clone(munich_library_root), true).len(), 8); + assert_eq!(munich_library_root.get_children("entities").len(), 4); } + } diff --git a/mps-cli-rs/src/builder/smodules_repository_builder.rs b/mps-cli-rs/src/builder/smodules_repository_builder.rs index be45f11..14d56bd 100644 --- a/mps-cli-rs/src/builder/smodules_repository_builder.rs +++ b/mps-cli-rs/src/builder/smodules_repository_builder.rs @@ -67,8 +67,7 @@ pub fn find_msd_files(source_dir: &String, start_depth: usize) -> Vec { #[cfg(test)] -mod tests { - use core::num; +mod tests { use std::cell::RefCell; use std::rc::Rc; diff --git a/mps-cli-rs/src/model/smodel.rs b/mps-cli-rs/src/model/smodel.rs index 7f83ce8..d4a3080 100644 --- a/mps-cli-rs/src/model/smodel.rs +++ b/mps-cli-rs/src/model/smodel.rs @@ -24,12 +24,11 @@ impl<'a> SModel<'a> { } } - pub fn get_nodes(&'a self) -> Vec<&SNode<'a>> { - let mut nodes: Vec<&SNode> = Vec::new(); - /*for root in &self.root_nodes { - nodes.push(root); - nodes.extend(root.get_descendants(false)); - }*/ + pub fn get_nodes(&'a self) -> Vec>> { + let mut nodes = Vec::new(); + for root in self.root_nodes.iter() { + nodes.extend(SNode::get_descendants(Rc::clone(root), true)); + } return nodes; } @@ -40,3 +39,4 @@ impl<'a> SModel<'a> { */None } } + diff --git a/mps-cli-rs/src/model/snode.rs b/mps-cli-rs/src/model/snode.rs index 2074f20..e8bd5d7 100644 --- a/mps-cli-rs/src/model/snode.rs +++ b/mps-cli-rs/src/model/snode.rs @@ -69,27 +69,21 @@ impl<'a> SNode<'a> { pub fn set_parent(&self, parent : Rc>) { self.parent.replace(Some(parent)); - } - - /*pub fn get_children(&self, name: &String) -> Option<&Vec> { - return match self.children.keys().find(|&&containmetd_link| containmetd_link.name.eq(name)) { - None => None, - Some(containment_link) => self.children.get(containment_link) - }; - }*/ + } - pub fn get_descendants(&'a self, include_self: bool) -> Vec>> { + pub fn get_descendants(node : Rc>, include_self: bool) -> Vec>> { let mut descendants: Vec>> = Vec::new(); - //if include_self { descendants.push(Rc::new(self)) } - //self.get_descendants_internal(&mut descendants); + if include_self { descendants.push(Rc::clone(&node)) } + Self::get_descendants_internal(node, &mut descendants); return descendants; } - fn get_descendants_internal(self, descendants: &mut Vec>>) { - /*let vectors_of_children = self.children.borrow().values().flatten().collect::>>; - for child in ..flatten() { - descendants.push(child.as_ref()); - child.get_descendants_internal(descendants); - }*/ + fn get_descendants_internal(node : Rc>, descendants: &mut Vec>>) { + let children = node.children.borrow(); + let vectors_of_children : Vec<&Rc>> = children.values().flatten().collect(); + for child in vectors_of_children { + descendants.push(Rc::clone(child)); + Self::get_descendants_internal(Rc::clone(child), descendants); + } } } \ No newline at end of file From 58b3d767f94b846bcb0be4f18ee35843ca41b58a Mon Sep 17 00:00:00 2001 From: danielratiu Date: Tue, 21 May 2024 23:28:58 +0200 Subject: [PATCH 13/43] mps-cli.rs: cleanup code --- mps-cli-rs/src/builder/mod.rs | 1 - mps-cli-rs/src/builder/slanguage_builder.rs | 20 ++++++----- ...model_builder_file_per_root_persistency.rs | 15 ++++---- .../builder/smodules_repository_builder.rs | 6 ++-- mps-cli-rs/src/builder/ssolution_builder.rs | 7 ++-- mps-cli-rs/src/builder/test_helper.rs | 36 ------------------- mps-cli-rs/src/model/smodel.rs | 10 +++--- 7 files changed, 31 insertions(+), 64 deletions(-) delete mode 100644 mps-cli-rs/src/builder/test_helper.rs diff --git a/mps-cli-rs/src/builder/mod.rs b/mps-cli-rs/src/builder/mod.rs index 96a38af..32a9c22 100644 --- a/mps-cli-rs/src/builder/mod.rs +++ b/mps-cli-rs/src/builder/mod.rs @@ -3,5 +3,4 @@ mod ssolution_builder; pub mod smodel_builder_file_per_root_persistency; mod builder_helper; mod root_node_from_mpsr_file_builder; -mod test_helper; pub mod slanguage_builder; diff --git a/mps-cli-rs/src/builder/slanguage_builder.rs b/mps-cli-rs/src/builder/slanguage_builder.rs index 0b625fc..7064469 100644 --- a/mps-cli-rs/src/builder/slanguage_builder.rs +++ b/mps-cli-rs/src/builder/slanguage_builder.rs @@ -25,15 +25,19 @@ impl<'a> SLanguageBuilder { Rc::clone(res) } - pub(crate) fn get_or_create_concept(&'a self, language: Rc, concept_id: String, concept_name: String) -> Rc { - let mut concepts = language.concepts.borrow_mut(); - if let Some(i) = concepts.iter().position(|c| c.name == concept_name) { - let c = &concepts[i]; - Rc::clone(c) - } else { - concepts.push(Rc::new(SConcept::new(concept_name.clone(), concept_id.clone()))); - Rc::clone(concepts.last().unwrap()) + pub(crate) fn get_or_create_concept(&'a self, language: Rc, concept_id: &str, concept_name: &str) -> Rc { + let mut concept_id_to_concept = self.concept_id_to_concept.borrow_mut(); + let concept = concept_id_to_concept.get(concept_id); + if let Some(c) = concept { + return Rc::clone(c); } + + let mut concepts = language.concepts.borrow_mut(); + let concept = SConcept::new(concept_name.to_string(), concept_id.to_string()); + let rc = Rc::new(concept); + concept_id_to_concept.insert(concept_id.to_string(), rc.clone()); + concepts.push(rc.clone()); + rc } diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index 4d200d0..9a55e8d 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -189,7 +189,7 @@ impl SModelBuilderFilePerRootPersistency { let concept_id = concept.attributes().find(|a| a.name() == "id").unwrap().value(); let concept_name = concept.attributes().find(|a| a.name() == "name").unwrap().value(); let concept_index = concept.attributes().find(|a| a.name() == "index").unwrap().value(); - let conc = language_builder.get_or_create_concept(Rc::clone(&lang), concept_id.to_string(), concept_name.to_string()); + let conc = language_builder.get_or_create_concept(Rc::clone(&lang), concept_id, concept_name); model_builder_cache.index_2_concept.borrow_mut().insert(concept_index.to_string(), Rc::clone(&conc)); for properties_links_references in concept.children() { @@ -293,13 +293,13 @@ mod tests { use crate::builder::slanguage_builder::SLanguageBuilder; use crate::builder::smodel_builder_file_per_root_persistency::{SModelBuilderCache, SModelBuilderFilePerRootPersistency}; - use crate::builder::test_helper::get_path_to_model_mpsr_example_lib_file; use crate::model::snode::SNode; #[test] fn test_model_extract_core_info() { // given - let path_to_model_file = PathBuf::from(get_path_to_model_mpsr_example_lib_file()); + let path = "../mps_test_projects/mps_cli_lanuse_file_per_root/solutions/mps.cli.lanuse.library_top/models/mps.cli.lanuse.library_top.library_top/.model"; + let path_to_model_file = PathBuf::from(path); //when let model_builder_cache = SModelBuilderCache::new(); @@ -309,7 +309,7 @@ mod tests { //assert assert_eq!(model.name, "mps.cli.lanuse.library_top.library_top"); assert_eq!(model.uuid, "r:a96b23f6-56db-490c-a218-d40d11be7f1e"); - assert_eq!(model.path_to_model_file, get_path_to_model_mpsr_example_lib_file()); + assert_eq!(model.path_to_model_file, path); assert_eq!(model.is_do_not_generate, true); assert!(model.is_file_per_root_persistency); assert_eq!(model.imported_models.len(), 1); @@ -356,13 +356,16 @@ mod tests { let mut language_builder = SLanguageBuilder::new(); let model_builder_cache = SModelBuilderCache::new(); let temp = SModelBuilderFilePerRootPersistency::build_model(path_to_mpsr_file, &mut language_builder, &model_builder_cache); - let m = temp.as_ref().borrow(); + let model = temp.as_ref().borrow(); //assert - let munich_library_root = m.root_nodes.first().unwrap(); + let munich_library_root = model.root_nodes.first().unwrap(); assert_eq!(munich_library_root.get_property("name"), Some(String::from("munich_library"))); assert_eq!(SNode::get_descendants(Rc::clone(munich_library_root), true).len(), 8); assert_eq!(munich_library_root.get_children("entities").len(), 4); + + assert_eq!(model.get_nodes().len(), 9); + assert_eq!(model.get_node_by_id("4Yb5JA31NUC").unwrap().get_property("name").unwrap(), "munich_library"); } } diff --git a/mps-cli-rs/src/builder/smodules_repository_builder.rs b/mps-cli-rs/src/builder/smodules_repository_builder.rs index 14d56bd..4abdd8b 100644 --- a/mps-cli-rs/src/builder/smodules_repository_builder.rs +++ b/mps-cli-rs/src/builder/smodules_repository_builder.rs @@ -74,14 +74,12 @@ mod tests { use crate::builder::slanguage_builder::SLanguageBuilder; use crate::builder::smodel_builder_file_per_root_persistency::SModelBuilderCache; use crate::builder::smodules_repository_builder::{build_repo_from_directory, find_msd_files}; - use crate::builder::test_helper::get_path_to_mps_cli_lanuse_file_per_root; use crate::model::smodel::SModel; #[test] fn test_find_msd_files() { //given - let src_dir = get_path_to_mps_cli_lanuse_file_per_root(); - + let src_dir = "../mps_test_projects/mps_cli_lanuse_file_per_root/".to_string(); //when let msd_files = find_msd_files(&src_dir, 3); @@ -92,7 +90,7 @@ mod tests { #[test] fn smoke_test_build_repo_from() { //given - let src_dir = get_path_to_mps_cli_lanuse_file_per_root(); + let src_dir = "../mps_test_projects/mps_cli_lanuse_file_per_root/".to_string(); use std::time::Instant; let now = Instant::now(); diff --git a/mps-cli-rs/src/builder/ssolution_builder.rs b/mps-cli-rs/src/builder/ssolution_builder.rs index 58285ee..2e10db2 100644 --- a/mps-cli-rs/src/builder/ssolution_builder.rs +++ b/mps-cli-rs/src/builder/ssolution_builder.rs @@ -77,12 +77,11 @@ mod tests { use crate::builder::builder_helper::convert_to_string; use crate::builder::smodules_repository_builder::find_msd_files; use crate::builder::ssolution_builder::extract_solution_core_info; - use crate::builder::test_helper::{get_path_to_mps_cli_lanuse_file_per_root, get_path_to_mps_cli_lanuse_library_top_msd_file}; - + #[test] fn test_extract_core_info() { // given - let path_to_msd_file = get_path_to_mps_cli_lanuse_library_top_msd_file(); + let path_to_msd_file = "../mps_test_projects/mps_cli_lanuse_file_per_root/solutions/mps.cli.lanuse.library_top/mps.cli.lanuse.library_top.msd".to_string(); //when let solution = extract_solution_core_info(path_to_msd_file); @@ -95,7 +94,7 @@ mod tests { #[test] fn smoke_test_extract_core_info_for_solutions() { //given - let path_to_test_project = get_path_to_mps_cli_lanuse_file_per_root(); + let path_to_test_project = "../mps_test_projects/mps_cli_lanuse_file_per_root".to_string(); use std::time::Instant; let now = Instant::now(); diff --git a/mps-cli-rs/src/builder/test_helper.rs b/mps-cli-rs/src/builder/test_helper.rs deleted file mode 100644 index 0312882..0000000 --- a/mps-cli-rs/src/builder/test_helper.rs +++ /dev/null @@ -1,36 +0,0 @@ -const MPSR_TOP_MODEL_PATH: &'static str = "/models/mps.cli.lanuse.library_top.library_top"; -const MPSR_SOLUTION_MPS_CLI_LANUSE_LIBRARY_TOP_: &'static str = "/solutions/mps.cli.lanuse.library_top"; -const MPSR_FILE_PATH: &'static str = "/munich_library.mpsr"; -const PATH_TO_MPS_TEST_PROJECTS: &'static str = "../mps_test_projects"; -const PATH_TO_FILE_PER_ROOT_PROJECT: &'static str = "/mps_cli_lanuse_file_per_root"; -const MPSR_MODEL_FILE_NAME: &'static str = "/.model"; -const MPS_CLI_LANUSE_LIBRARY_TOP_MSD: &'static str = "/mps.cli.lanuse.library_top.msd"; - -fn get_path_to_test_projects() -> String { - String::from(PATH_TO_MPS_TEST_PROJECTS) -} - - -pub fn get_path_to_mps_cli_lanuse_file_per_root() -> String { - get_path_to_test_projects() + PATH_TO_FILE_PER_ROOT_PROJECT -} - -fn get_path_to_mpsr_solution() -> String { - get_path_to_mps_cli_lanuse_file_per_root() + MPSR_SOLUTION_MPS_CLI_LANUSE_LIBRARY_TOP_ -} - -pub fn get_path_to_mpsr_example_lib_file() -> String { - get_path_to_example_mpsr_model_files() + MPSR_FILE_PATH -} - -pub fn get_path_to_example_mpsr_model_files() -> String { - get_path_to_mpsr_solution() + MPSR_TOP_MODEL_PATH -} - -pub fn get_path_to_model_mpsr_example_lib_file() -> String { - get_path_to_mpsr_solution() + MPSR_TOP_MODEL_PATH + MPSR_MODEL_FILE_NAME -} - -pub fn get_path_to_mps_cli_lanuse_library_top_msd_file() -> String { - get_path_to_mpsr_solution() + MPS_CLI_LANUSE_LIBRARY_TOP_MSD -} \ No newline at end of file diff --git a/mps-cli-rs/src/model/smodel.rs b/mps-cli-rs/src/model/smodel.rs index d4a3080..8360acc 100644 --- a/mps-cli-rs/src/model/smodel.rs +++ b/mps-cli-rs/src/model/smodel.rs @@ -24,7 +24,7 @@ impl<'a> SModel<'a> { } } - pub fn get_nodes(&'a self) -> Vec>> { + pub fn get_nodes(&self) -> Vec>> { let mut nodes = Vec::new(); for root in self.root_nodes.iter() { nodes.extend(SNode::get_descendants(Rc::clone(root), true)); @@ -32,11 +32,11 @@ impl<'a> SModel<'a> { return nodes; } - pub fn get_node_by_id(&'a self, id: &'a String) -> Option>> { - /*let nodes = self.get_nodes(); + pub fn get_node_by_id(&self, id: &str) -> Option>> { + let nodes = self.get_nodes(); let n = nodes.iter().find(|node| node.id.eq(id)); - if let Some(nn) = n { return Some(Rc::new(**nn)); } - */None + if let Some(nn) = n { return Some(Rc::clone(nn)); } + None } } From 0a8204547fe440586b84b2fbf32c0b60ab734845 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Wed, 22 May 2024 08:30:52 +0200 Subject: [PATCH 14/43] mps-cli.rst: cleanup --- mps-cli-rs/Cargo.toml | 5 +- mps-cli-rs/src/builder/builder_helper.rs | 60 ------------------- mps-cli-rs/src/builder/mod.rs | 1 - ...model_builder_file_per_root_persistency.rs | 20 ++----- .../builder/smodules_repository_builder.rs | 9 ++- mps-cli-rs/src/builder/ssolution_builder.rs | 50 +++++----------- mps-cli-rs/src/model/srepository.rs | 25 ++++---- 7 files changed, 41 insertions(+), 129 deletions(-) delete mode 100644 mps-cli-rs/src/builder/builder_helper.rs diff --git a/mps-cli-rs/Cargo.toml b/mps-cli-rs/Cargo.toml index 8831e6f..83457d7 100644 --- a/mps-cli-rs/Cargo.toml +++ b/mps-cli-rs/Cargo.toml @@ -6,12 +6,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -uuid = { version = "1.8.0", features = ["v4"] } -quick-xml = { version = "0.31.0", features = ["serialize"] } -serde = { version = "1.0.197", features = ["derive"] } walkdir = "2.5.0" roxmltree = "0.19.0" [profile.release] -lto = "fat" +lto = "thin" codegen-units = 1 \ No newline at end of file diff --git a/mps-cli-rs/src/builder/builder_helper.rs b/mps-cli-rs/src/builder/builder_helper.rs deleted file mode 100644 index d8e2561..0000000 --- a/mps-cli-rs/src/builder/builder_helper.rs +++ /dev/null @@ -1,60 +0,0 @@ -use std::collections::{HashMap, HashSet}; -use std::fs::File; -use std::io::BufReader; -use std::path::PathBuf; - -use quick_xml::{Error, Reader}; -use quick_xml::events::attributes::Attributes; -use quick_xml::name::QName; - -pub(crate) fn panic_read_file(msd_file_reader: &mut Reader>, e: Error) { - panic!("Error at position {}: {:?}", msd_file_reader.buffer_position(), e) -} - -pub(crate) fn panic_unexpected_eof_read_file(msd_file_reader: &mut Reader>) { - panic!("Error at position {}: Unexpected EOF!", msd_file_reader.buffer_position()) -} - -pub(crate) fn convert_to_string(path_buf_to_msd_file: &PathBuf) -> String { - path_buf_to_msd_file.to_str().unwrap().to_string() -} - -pub(crate) fn get_value_of_attribute_with_key(attributes: Attributes, attribute_name: &str) -> Option { - get_values_of_attributes_with_keys(attributes, vec![attribute_name]).remove(attribute_name) -} - -pub(crate) fn get_values_of_attributes_with_keys(attributes: Attributes, attribute_names: Vec<&str>) -> HashMap { - let attribute_names_set: HashSet<&str> = attribute_names.into_iter().collect(); - let mut key_value_map = HashMap::new(); - for attribute in attributes { - let unwrapped_attribute = attribute.unwrap(); - let key = convert_qname_to_string(&unwrapped_attribute.key); - if attribute_names_set.contains(&key.as_str()) { - key_value_map.insert(key, unwrapped_attribute.unescape_value().unwrap().to_string()); - } - } - return key_value_map; -} - -pub(crate) fn convert_qname_to_string(qname: &QName) -> String { - String::from_utf8(qname.as_ref().to_vec()).unwrap() -} - -#[cfg(test)] -mod tests { - use quick_xml::name::QName; - - use crate::builder::builder_helper::convert_qname_to_string; - - #[test] - fn test_convert_qname_to_string() { - // given - let qname = QName("test_q_name".as_bytes()); - - //when - let converted_string = convert_qname_to_string(&qname); - - //assert - assert_eq!(converted_string, "test_q_name"); - } -} diff --git a/mps-cli-rs/src/builder/mod.rs b/mps-cli-rs/src/builder/mod.rs index 32a9c22..42a92d0 100644 --- a/mps-cli-rs/src/builder/mod.rs +++ b/mps-cli-rs/src/builder/mod.rs @@ -1,6 +1,5 @@ pub mod smodules_repository_builder; mod ssolution_builder; pub mod smodel_builder_file_per_root_persistency; -mod builder_helper; mod root_node_from_mpsr_file_builder; pub mod slanguage_builder; diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index 9a55e8d..4baeb63 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -1,10 +1,6 @@ -use std::borrow::{Borrow, BorrowMut}; +use std::borrow::BorrowMut; use std::collections::HashMap; -use std::fs::File; -use std::io::BufReader; -use std::ops::DerefMut; use std::path::PathBuf; -use std::sync::Mutex; use std::io::Read; use roxmltree::{Document, Node}; use std::rc::Rc; @@ -12,7 +8,6 @@ use std::cell::RefCell; use walkdir::{DirEntry, WalkDir}; -use crate::builder::builder_helper::{convert_to_string, get_value_of_attribute_with_key, get_values_of_attributes_with_keys, panic_read_file, panic_unexpected_eof_read_file}; use crate::model::sconcept::{SConcept, SContainmentLink, SProperty, SReferenceLink}; use crate::model::smodel::SModel; use crate::model::snode::SNode; @@ -57,14 +52,11 @@ impl<'a> SModelBuilderCache<'a> { pub struct SModelBuilderFilePerRootPersistency {} impl SModelBuilderFilePerRootPersistency { - pub(crate) fn new() -> Self { - SModelBuilderFilePerRootPersistency {} - } - + pub(crate) fn build_model<'a>(path_to_model: PathBuf, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache<'a>) -> Rc>> { let mut model_file = path_to_model.clone(); model_file.push(".model"); - let mut model: Rc>> = Self::extract_model_core_info(model_file, &model_builder_cache); + let model: Rc>> = Self::extract_model_core_info(model_file, &model_builder_cache); let mpsr_file_walker = WalkDir::new(path_to_model).min_depth(1).max_depth(1); let mpsr_files = mpsr_file_walker.into_iter().filter(|entry| { @@ -93,7 +85,7 @@ impl SModelBuilderFilePerRootPersistency { let file = std::fs::File::open(path_to_model_file.clone()); let mut s = String::new(); - file.unwrap().read_to_string(&mut s); + let _ = file.unwrap().read_to_string(&mut s); let parse_res = roxmltree::Document::parse(&s); let document = parse_res.unwrap(); @@ -113,7 +105,7 @@ impl SModelBuilderFilePerRootPersistency { if do_not_generate_str == "true" { is_do_not_generate = true; } } - let mut my_model = model_builder_cache.get_model(name, uuid); + let my_model = model_builder_cache.get_model(name, uuid); my_model.as_ref().borrow_mut().path_to_model_file = path_to_model_file; my_model.as_ref().borrow_mut().is_do_not_generate = is_do_not_generate; my_model.as_ref().borrow_mut().is_file_per_root_persistency = true; @@ -139,7 +131,7 @@ impl SModelBuilderFilePerRootPersistency { let file = std::fs::File::open(dir_entry.path().as_os_str()); let mut s = String::new(); - file.unwrap().read_to_string(&mut s); + let _ = file.unwrap().read_to_string(&mut s); let parse_res = roxmltree::Document::parse_with_options(&s, roxmltree::ParsingOptions::default()); let document = parse_res.unwrap(); diff --git a/mps-cli-rs/src/builder/smodules_repository_builder.rs b/mps-cli-rs/src/builder/smodules_repository_builder.rs index 4abdd8b..b0f8083 100644 --- a/mps-cli-rs/src/builder/smodules_repository_builder.rs +++ b/mps-cli-rs/src/builder/smodules_repository_builder.rs @@ -106,8 +106,13 @@ mod tests { let do_not_gen_models: Vec<&&Rc>> = models.iter().filter(|&model| model.as_ref().borrow().is_do_not_generate).collect(); let number_of_solutions = repository.solutions.borrow().len(); println!("Found {} solutions with {} models (out of which {} are set to do not generate) in {} ms", number_of_solutions, models.len(), do_not_gen_models.len(), required_time); - assert!(number_of_solutions > 1); - assert!(models.len() > 1); + assert_eq!(number_of_solutions, 2); + assert_eq!(models.len(), 3); assert_eq!(do_not_gen_models.len(), 1); + + assert!(repository.find_solution_by_name("mps.cli.lanuse.library_top").is_some()); + + + //assert!(repository.get_model_by_uuid("r:ec5f093b-9d83-43a1-9b41-b5952da8b1ed").is_some()); } } \ No newline at end of file diff --git a/mps-cli-rs/src/builder/ssolution_builder.rs b/mps-cli-rs/src/builder/ssolution_builder.rs index 2e10db2..a46b73b 100644 --- a/mps-cli-rs/src/builder/ssolution_builder.rs +++ b/mps-cli-rs/src/builder/ssolution_builder.rs @@ -1,14 +1,9 @@ -use std::borrow::BorrowMut; use std::path::PathBuf; use std::time::Instant; -use quick_xml::events::Event; -use quick_xml::name::QName; -use quick_xml::Reader; +use std::io::Read; use walkdir::WalkDir; -use crate::builder::builder_helper::convert_to_string; -use crate::builder::builder_helper::panic_read_file; use crate::builder::smodel_builder_file_per_root_persistency::SModelBuilderFilePerRootPersistency; use crate::builder::slanguage_builder::SLanguageBuilder; use crate::model::ssolution::SSolution; @@ -18,10 +13,10 @@ use super::smodel_builder_file_per_root_persistency::SModelBuilderCache; pub fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache<'a>) -> SSolution<'a> { let now = Instant::now(); - let path_to_msd_file = convert_to_string(&path_buf_to_msd_file); + let path_to_msd_file = path_buf_to_msd_file.to_str().unwrap().to_string(); let mut solution: SSolution = extract_solution_core_info(path_to_msd_file); let solution_dir = path_buf_to_msd_file.parent().unwrap(); - let model_dir = convert_to_string(&solution_dir.to_path_buf()) + "/models"; + let model_dir = solution_dir.to_path_buf().to_str().unwrap().to_string() + "/models"; let model_dir = WalkDir::new(model_dir).min_depth(1).max_depth(1); let mut models = vec![]; @@ -43,38 +38,21 @@ pub fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_builder : &'a fn extract_solution_core_info<'a>(path_to_msd_file: String) -> SSolution<'a> { //let solution_file = SolutionFile::new(&path_to_msd_file); - let mut msd_file_reader = Reader::from_file(&path_to_msd_file).unwrap(); - let mut buf = Vec::new(); - let mut name: String = "".to_string(); - let mut uuid: String = "".to_string(); - loop { - match msd_file_reader.read_event_into(&mut buf) { - Ok(Event::Start(e)) => { - match e.name().as_ref() { - b"solution" => { - for attribute in e.attributes() { - let attribute = attribute.unwrap(); - match attribute.key { - QName(b"name") => { name = attribute.unescape_value().unwrap().to_string() } - QName(b"uuid") => { uuid = attribute.unescape_value().unwrap().to_string() } - QName(_) => {} - } - } - break; - } - _ => {} - } - } - Err(e) => panic_read_file(&mut msd_file_reader, e), - _ => {} - } - } + + let file = std::fs::File::open(path_to_msd_file.clone()); + let mut s = String::new(); + let _ = file.unwrap().read_to_string(&mut s); + let parse_res = roxmltree::Document::parse(&s); + let document = parse_res.unwrap(); + + let model_element = document.root_element(); + let name = model_element.attributes().find(|a| a.name() == "name").unwrap().value().to_string(); + let uuid = model_element.attributes().find(|a| a.name() == "uuid").unwrap().value().to_string(); return SSolution::new(name, uuid, path_to_msd_file.clone()); } #[cfg(test)] mod tests { - use crate::builder::builder_helper::convert_to_string; use crate::builder::smodules_repository_builder::find_msd_files; use crate::builder::ssolution_builder::extract_solution_core_info; @@ -102,7 +80,7 @@ mod tests { let msd_files = find_msd_files(&path_to_test_project, 3); let mut solutions = vec![]; for msd_file in &msd_files { - let solution = extract_solution_core_info(convert_to_string(&msd_file)); + let solution = extract_solution_core_info(msd_file.to_str().unwrap().to_string()); solutions.push(solution); } diff --git a/mps-cli-rs/src/model/srepository.rs b/mps-cli-rs/src/model/srepository.rs index 7cf6299..ffbd17f 100644 --- a/mps-cli-rs/src/model/srepository.rs +++ b/mps-cli-rs/src/model/srepository.rs @@ -2,15 +2,14 @@ use crate::model::slanguage::SLanguage; use crate::model::smodel::SModel; use crate::model::snode::SNode; use crate::model::ssolution::SSolution; +use std::borrow::Borrow; +use std::ops::Deref; use std::rc::Rc; use std::cell::RefCell; pub struct SRepository<'a> { pub solutions: RefCell>>>, languages: RefCell>>, - - models: RefCell>>>, - nodes: RefCell>>>, } impl<'a> SRepository<'a> { @@ -18,12 +17,10 @@ impl<'a> SRepository<'a> { SRepository { solutions : RefCell::new(solutions), languages : RefCell::new(languages), - models: RefCell::new(vec![]), - nodes: RefCell::new(vec![]), } } - pub fn find_solution_by_name(&self, name: &String) -> Option>> { + pub fn find_solution_by_name(&self, name: &str) -> Option>> { let solutions = self.solutions.borrow(); let found_solution = solutions.iter().find(|&ssolution| ssolution.name.eq(name)); if let Some(found_solution) = found_solution { @@ -32,12 +29,16 @@ impl<'a> SRepository<'a> { None } - pub fn get_model_by_uuid(&self, uuid: &'a String) -> Option>> { - let models = self.models.borrow(); - let res = models.iter().find(|&model| model.uuid.eq(uuid)); - if let Some(res) = res { - return Some(Rc::clone(res)); + /*pub fn get_model_by_uuid(&self, uuid: &str) -> Option>>> { + let solutions = self.solutions.borrow(); + for sol in solutions.into_iter() { + let models = sol.models; + for m in models.iter() { + if (**m).borrow().uuid.eq(uuid) { + return Some(Rc::clone(m)); + } + } } None - } + }*/ } \ No newline at end of file From aaa3950053ea8e16ea9a4fc2027cd1221b815b17 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Wed, 22 May 2024 10:47:46 +0200 Subject: [PATCH 15/43] mps-cli.rs: added support for SNodeRef --- ...model_builder_file_per_root_persistency.rs | 6 +++++ mps-cli-rs/src/model/snode.rs | 22 ++++++++++-------- mps-cli-rs/src/model/snoderef.rs | 23 ++++++++++++------- mps-cli-rs/src/model/ssolution.rs | 2 +- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index 4baeb63..ebace72 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -336,6 +336,12 @@ mod tests { assert_eq!(tom_sawyer.get_property("isbn"), Some(String::from("4323r2"))); assert_eq!(tom_sawyer.get_property("available"), Some(String::from("true"))); assert_eq!(tom_sawyer.concept.name, String::from("mps.cli.landefs.library.structure.Book")); + + let authors = tom_sawyer.get_children("authors"); + let mark_twain = authors.first().unwrap().get_reference("person").unwrap(); + assert_eq!(mark_twain.resolve_info, "Mark Twain"); + assert_eq!(mark_twain.to, "q0v6:4Yb5JA31NUv"); + } #[test] diff --git a/mps-cli-rs/src/model/snode.rs b/mps-cli-rs/src/model/snode.rs index e8bd5d7..1c77ab6 100644 --- a/mps-cli-rs/src/model/snode.rs +++ b/mps-cli-rs/src/model/snode.rs @@ -1,21 +1,17 @@ use std::collections::HashMap; use crate::model::sconcept::{SConcept, SContainmentLink, SProperty, SReferenceLink}; +use crate::model::snoderef::SNodeRef; use std::rc::Rc; use std::cell::RefCell; -pub struct SNodeRef { - to : String, - resolve : Option, -} - pub struct SNode<'a> { pub id: String, pub concept: Rc, pub role_in_parent: Option, properties: RefCell, String>>, children: RefCell, Vec>>>>, - references: RefCell, Rc>>, + references: RefCell, Rc>>>, pub parent: RefCell>>>, } @@ -46,10 +42,16 @@ impl<'a> SNode<'a> { } pub fn add_reference(&self, reference_link: &Rc, to: String, resolve : Option) { - self.references.borrow_mut().insert(Rc::clone(reference_link), Rc::new(SNodeRef { - to : to, - resolve : resolve, - })); + self.references.borrow_mut().insert(Rc::clone(reference_link), Rc::new(SNodeRef::new(to, resolve.unwrap()))); + } + + pub fn get_reference(&self, ref_role_name: &str) -> Option>> { + let references = self.references.borrow(); + let entry = references.iter().find(|it| it.0.name.eq(ref_role_name)); + match entry { + Some(e) => Some(e.1.clone()), + None => None + } } pub fn add_child(&self, cl: Rc, node: Rc>) { diff --git a/mps-cli-rs/src/model/snoderef.rs b/mps-cli-rs/src/model/snoderef.rs index c069b8e..0e3dd94 100644 --- a/mps-cli-rs/src/model/snoderef.rs +++ b/mps-cli-rs/src/model/snoderef.rs @@ -2,20 +2,27 @@ use crate::model::snode::SNode; use crate::model::srepository::SRepository; use std::rc::Rc; -struct SNodeRef { - model_uuid: String, - node_uuid: String, +pub struct SNodeRef<'a> { + pub to: String, + pub resolve_info: String, + referenced_node : Option>>, } -impl SNodeRef { - pub fn new(model_uuid: String, node_uuid: String) -> Self { +impl<'a> SNodeRef<'a> { + pub fn new(to: String, resolve_info: String) -> Self { SNodeRef { - model_uuid, - node_uuid, + to, + resolve_info, + referenced_node : None, } } - pub fn resolve<'a>(&'a self, repository: &'a SRepository<'a>) -> Option>> { + pub fn resolve(&'a self, repository: &'a SRepository<'a>) -> Option>> { + /*if self.referenced_node.is_some() { + return self.referenced_node.clone(); + }*/ + + /*return match repository.get_model_by_uuid(&self.model_uuid) { None => None, Some(model) => diff --git a/mps-cli-rs/src/model/ssolution.rs b/mps-cli-rs/src/model/ssolution.rs index 60729c1..b939595 100644 --- a/mps-cli-rs/src/model/ssolution.rs +++ b/mps-cli-rs/src/model/ssolution.rs @@ -5,7 +5,7 @@ use crate::model::smodel::SModel; pub struct SSolution<'a> { pub name: String, pub uuid: String, - path_to_module_file: String, + pub path_to_module_file: String, pub models: Vec>>>, } From 3ca5588203b59b9fc0e3a36fe2e5052d37477c66 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Thu, 23 May 2024 22:17:09 +0200 Subject: [PATCH 16/43] mini fix --- .../builder/smodel_builder_file_per_root_persistency.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index ebace72..790d3ed 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -84,6 +84,9 @@ impl SModelBuilderFilePerRootPersistency { let path_to_model_file = path_to_model.to_str().unwrap().to_string(); let file = std::fs::File::open(path_to_model_file.clone()); + if file.is_err() { + panic!("file not found '{}'", path_to_model_file); + } let mut s = String::new(); let _ = file.unwrap().read_to_string(&mut s); let parse_res = roxmltree::Document::parse(&s); @@ -132,15 +135,15 @@ impl SModelBuilderFilePerRootPersistency { let mut s = String::new(); let _ = file.unwrap().read_to_string(&mut s); - let parse_res = roxmltree::Document::parse_with_options(&s, roxmltree::ParsingOptions::default()); - + let parse_res = roxmltree::Document::parse(&s); + let document = parse_res.unwrap(); Self::parse_imports(&document, model_builder_cache); Self::parse_registry(&document, language_builder, model_builder_cache); let node = document.root_element().children().find(|it| it.tag_name().name() == "node"); let mut parent: Option> = None; - Some(Self::parse_node(&mut parent, &node.unwrap(), language_builder, &model_builder_cache)) + Some(Self::parse_node(&mut parent, &node.unwrap(), language_builder, &model_builder_cache)) } fn parse_imports(document: &Document, model_builder_cache : &SModelBuilderCache) { From c7119ed4b919728f60fdbcb8eed861d22d4db491 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Fri, 24 May 2024 07:39:29 +0200 Subject: [PATCH 17/43] mini fix for cases when no resolveInfo is found --- mps-cli-rs/src/model/snode.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps-cli-rs/src/model/snode.rs b/mps-cli-rs/src/model/snode.rs index 1c77ab6..e746be9 100644 --- a/mps-cli-rs/src/model/snode.rs +++ b/mps-cli-rs/src/model/snode.rs @@ -42,7 +42,7 @@ impl<'a> SNode<'a> { } pub fn add_reference(&self, reference_link: &Rc, to: String, resolve : Option) { - self.references.borrow_mut().insert(Rc::clone(reference_link), Rc::new(SNodeRef::new(to, resolve.unwrap()))); + self.references.borrow_mut().insert(Rc::clone(reference_link), Rc::new(SNodeRef::new(to, resolve.unwrap_or("".to_string())))); } pub fn get_reference(&self, ref_role_name: &str) -> Option>> { From df45b3d8c6476eb4a7796bf4c39b960180c3a9a4 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Fri, 24 May 2024 11:17:22 +0200 Subject: [PATCH 18/43] mini improvement --- mps-cli-rs/src/model/sconcept.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mps-cli-rs/src/model/sconcept.rs b/mps-cli-rs/src/model/sconcept.rs index 61b17bf..76ac999 100644 --- a/mps-cli-rs/src/model/sconcept.rs +++ b/mps-cli-rs/src/model/sconcept.rs @@ -5,9 +5,9 @@ use std::rc::Rc; #[derive(Debug, PartialEq, Clone)] pub struct SConcept { - pub(crate) name: String, - id: String, - pub(crate) properties: RefCell>>, + pub name: String, + pub id: String, + pub properties: RefCell>>, pub containment_links: RefCell>>, pub reference_links: RefCell>>, } From 9c894f5ba0a39f25f0005798dabca9d46054a8db Mon Sep 17 00:00:00 2001 From: danielratiu Date: Fri, 24 May 2024 23:37:53 +0200 Subject: [PATCH 19/43] simplified the code --- mps-cli-rs/src/builder/mod.rs | 1 - mps-cli-rs/src/builder/playground.rs | 20 ++++++++ .../root_node_from_mpsr_file_builder.rs | 1 - ...model_builder_file_per_root_persistency.rs | 48 ++++++++++--------- .../builder/smodules_repository_builder.rs | 45 +++++++---------- mps-cli-rs/src/builder/ssolution_builder.rs | 5 +- mps-cli-rs/src/main.rs | 38 ++++++++++++--- mps-cli-rs/src/model/smodel.rs | 12 ++--- mps-cli-rs/src/model/snode.rs | 26 +++++----- mps-cli-rs/src/model/snoderef.rs | 8 ++-- mps-cli-rs/src/model/srepository.rs | 15 +++--- mps-cli-rs/src/model/ssolution.rs | 6 +-- 12 files changed, 129 insertions(+), 96 deletions(-) create mode 100644 mps-cli-rs/src/builder/playground.rs delete mode 100644 mps-cli-rs/src/builder/root_node_from_mpsr_file_builder.rs diff --git a/mps-cli-rs/src/builder/mod.rs b/mps-cli-rs/src/builder/mod.rs index 42a92d0..308298b 100644 --- a/mps-cli-rs/src/builder/mod.rs +++ b/mps-cli-rs/src/builder/mod.rs @@ -1,5 +1,4 @@ pub mod smodules_repository_builder; mod ssolution_builder; pub mod smodel_builder_file_per_root_persistency; -mod root_node_from_mpsr_file_builder; pub mod slanguage_builder; diff --git a/mps-cli-rs/src/builder/playground.rs b/mps-cli-rs/src/builder/playground.rs new file mode 100644 index 0000000..aad8786 --- /dev/null +++ b/mps-cli-rs/src/builder/playground.rs @@ -0,0 +1,20 @@ +use std::cell::RefCell; +use std::rc::Rc; + +struct Person { + name: String, +} + +struct Company { + employees: RefCell>>, +} + +impl Company { + fn search_employee(&self, name: &str) -> Option> { + self.employees + .borrow() + .iter() + .find(|employee| employee.name == name) + .map(|employee| Rc::clone(employee)) + } +} diff --git a/mps-cli-rs/src/builder/root_node_from_mpsr_file_builder.rs b/mps-cli-rs/src/builder/root_node_from_mpsr_file_builder.rs deleted file mode 100644 index fbe7048..0000000 --- a/mps-cli-rs/src/builder/root_node_from_mpsr_file_builder.rs +++ /dev/null @@ -1 +0,0 @@ -//fn parse_node(x: &Reader>, e: &BytesStart, buf: &mut Vec) -> SNode {} \ No newline at end of file diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index 790d3ed..fdb44c8 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -15,16 +15,16 @@ use super::slanguage_builder::SLanguageBuilder; #[derive(Clone)] -pub struct SModelBuilderCache<'a> { +pub struct SModelBuilderCache { pub index_2_concept: RefCell>>, pub index_2_property: RefCell>>, pub index_2_containment_link: RefCell>>, pub index_2_reference_link: RefCell>>, pub index_2_imported_model_uuid: RefCell>, - pub index_2_model : RefCell>>>>, + pub index_2_model : RefCell>>>, } -impl<'a> SModelBuilderCache<'a> { +impl SModelBuilderCache { pub fn new() -> Self { SModelBuilderCache { index_2_concept: RefCell::new(HashMap::new()), @@ -36,14 +36,14 @@ impl<'a> SModelBuilderCache<'a> { } } - pub fn get_model(&'a self, name : String, uuid : String) -> Rc>> { + pub fn get_model(&self, name : String, uuid : String) -> Rc> { let mut i2m = self.index_2_model.borrow_mut(); if let Some(model) = i2m.get(&uuid) { Rc::clone(&model) } else { let temp = Rc::new(RefCell::new(SModel::new(name.clone(), uuid.clone()))); i2m.insert(uuid, temp.clone()); - temp + temp.clone() } } @@ -53,10 +53,10 @@ pub struct SModelBuilderFilePerRootPersistency {} impl SModelBuilderFilePerRootPersistency { - pub(crate) fn build_model<'a>(path_to_model: PathBuf, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache<'a>) -> Rc>> { + pub(crate) fn build_model<'a>(path_to_model: PathBuf, language_builder : &RefCell, model_builder_cache : &RefCell) -> Rc> { let mut model_file = path_to_model.clone(); model_file.push(".model"); - let model: Rc>> = Self::extract_model_core_info(model_file, &model_builder_cache); + let model: Rc> = Self::extract_model_core_info(model_file, model_builder_cache); let mpsr_file_walker = WalkDir::new(path_to_model).min_depth(1).max_depth(1); let mpsr_files = mpsr_file_walker.into_iter().filter(|entry| { @@ -80,7 +80,7 @@ impl SModelBuilderFilePerRootPersistency { return model; } - fn extract_model_core_info<'a>(path_to_model: PathBuf, model_builder_cache : &'a SModelBuilderCache<'a>) -> Rc>> { + fn extract_model_core_info<'a>(path_to_model: PathBuf, model_builder_cache : &RefCell) -> Rc> { let path_to_model_file = path_to_model.to_str().unwrap().to_string(); let file = std::fs::File::open(path_to_model_file.clone()); @@ -108,6 +108,7 @@ impl SModelBuilderFilePerRootPersistency { if do_not_generate_str == "true" { is_do_not_generate = true; } } + let model_builder_cache = model_builder_cache.borrow(); let my_model = model_builder_cache.get_model(name, uuid); my_model.as_ref().borrow_mut().path_to_model_file = path_to_model_file; my_model.as_ref().borrow_mut().is_do_not_generate = is_do_not_generate; @@ -122,15 +123,14 @@ impl SModelBuilderFilePerRootPersistency { let uuid = uuid_att.to_string()[0..uuid_att.find('(').unwrap()].to_string(); let name = uuid_att.to_string()[uuid_att.find('(').unwrap()+1..uuid_att.find(')').unwrap()].to_string(); let imported_model = model_builder_cache.get_model(name, uuid); - my_model.as_ref().borrow_mut().imported_models.push(imported_model); + my_model.as_ref().borrow_mut().imported_models.push(imported_model.clone()); } } my_model.clone() } - fn build_root_node_from_file<'a>(dir_entry: DirEntry, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> Option>> { - //println!("building root node from {}", dir_entry.path().as_os_str().to_str().unwrap()); + fn build_root_node_from_file<'a>(dir_entry: DirEntry, language_builder : &RefCell, model_builder_cache : &RefCell) -> Option> { let file = std::fs::File::open(dir_entry.path().as_os_str()); let mut s = String::new(); @@ -138,15 +138,16 @@ impl SModelBuilderFilePerRootPersistency { let parse_res = roxmltree::Document::parse(&s); let document = parse_res.unwrap(); - Self::parse_imports(&document, model_builder_cache); - Self::parse_registry(&document, language_builder, model_builder_cache); + Self::parse_imports(&document, &model_builder_cache); + Self::parse_registry(&document, &language_builder, &model_builder_cache); let node = document.root_element().children().find(|it| it.tag_name().name() == "node"); let mut parent: Option> = None; - Some(Self::parse_node(&mut parent, &node.unwrap(), language_builder, &model_builder_cache)) + Some(Self::parse_node(&mut parent, &node.unwrap(), &(language_builder.borrow()), &(model_builder_cache.borrow()))) } - fn parse_imports(document: &Document, model_builder_cache : &SModelBuilderCache) { + fn parse_imports(document: &Document, model_builder_cache : &RefCell) { + let model_builder_cache = model_builder_cache.borrow(); let model_element = document.root_element(); let imports_element = model_element.children().find(|c| c.tag_name().name() == "imports"); match imports_element { @@ -166,7 +167,9 @@ impl SModelBuilderFilePerRootPersistency { } } - fn parse_registry<'a>(document: &Document, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) { + fn parse_registry<'a>(document: &Document, language_builder : &RefCell, model_builder_cache : &RefCell) { + let language_builder = language_builder.borrow(); + let model_builder_cache = model_builder_cache.borrow(); let model_element = document.root_element(); let registry_element = model_element.children().find(|c| c.tag_name().name() == "registry"); match registry_element { @@ -214,7 +217,7 @@ impl SModelBuilderFilePerRootPersistency { } - fn parse_node<'a>(parent_node : &mut Option>>, node: &Node, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache) -> Rc> { + fn parse_node<'a>(parent_node : &mut Option>, node: &Node, language_builder : &SLanguageBuilder, model_builder_cache : &SModelBuilderCache) -> Rc { let node_attrs = node.attributes(); let concept_index = (node_attrs.clone()).into_iter().find(|a| a.name() == "concept").unwrap().value(); let node_id = (node_attrs.clone()).into_iter().find(|a| a.name() == "id").unwrap().value(); @@ -283,6 +286,7 @@ impl SModelBuilderFilePerRootPersistency { #[cfg(test)] mod tests { + use std::cell::RefCell; use std::path::PathBuf; use std::rc::Rc; @@ -297,7 +301,7 @@ mod tests { let path_to_model_file = PathBuf::from(path); //when - let model_builder_cache = SModelBuilderCache::new(); + let model_builder_cache = RefCell::new(SModelBuilderCache::new()); let temp = SModelBuilderFilePerRootPersistency::extract_model_core_info(path_to_model_file, &model_builder_cache); let model = temp.borrow(); @@ -320,8 +324,8 @@ mod tests { let path_to_mpsr_file = PathBuf::from(path); //when - let mut language_builder = SLanguageBuilder::new(); - let model_builder_cache = SModelBuilderCache::new(); + let mut language_builder = RefCell::new(SLanguageBuilder::new()); + let model_builder_cache = RefCell::new(SModelBuilderCache::new()); let temp = SModelBuilderFilePerRootPersistency::build_model(path_to_mpsr_file, &mut language_builder, &model_builder_cache); let model = temp.as_ref().borrow(); @@ -354,8 +358,8 @@ mod tests { let path_to_mpsr_file = PathBuf::from(path); //when - let mut language_builder = SLanguageBuilder::new(); - let model_builder_cache = SModelBuilderCache::new(); + let mut language_builder = RefCell::new(SLanguageBuilder::new()); + let model_builder_cache = RefCell::new(SModelBuilderCache::new()); let temp = SModelBuilderFilePerRootPersistency::build_model(path_to_mpsr_file, &mut language_builder, &model_builder_cache); let model = temp.as_ref().borrow(); diff --git a/mps-cli-rs/src/builder/smodules_repository_builder.rs b/mps-cli-rs/src/builder/smodules_repository_builder.rs index b0f8083..f6da85e 100644 --- a/mps-cli-rs/src/builder/smodules_repository_builder.rs +++ b/mps-cli-rs/src/builder/smodules_repository_builder.rs @@ -1,3 +1,4 @@ +use std::cell::RefCell; use std::path::PathBuf; use std::time::Instant; @@ -11,43 +12,33 @@ use crate::model::srepository::SRepository; use crate::model::ssolution::SSolution; use crate::model::slanguage::SLanguage; -pub fn build_repo_from_directories<'a>(source_dirs: Vec, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache<'a>) -> SRepository<'a> { +pub fn build_repo_from_directory<'a>(source_dir: String) -> SRepository { let mut all_solutions : Vec> = Vec::new(); + let language_builder = RefCell::new(SLanguageBuilder::new()); - for source_dir in source_dirs { - println!("loading models from directory: {}", source_dir); - let solutions = build_solutions_from(source_dir, &language_builder, model_builder_cache); - solutions.into_iter().for_each(|s| all_solutions.push(Rc::new(s))); - } - let mut languages: Vec> = Vec::new(); - language_builder.language_id_to_slanguage.borrow().values().for_each(|v| languages.push(Rc::clone(v))); - SRepository::new(all_solutions, languages) -} - - -pub fn build_repo_from_directory<'a>(source_dir: String, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache<'a>) -> SRepository<'a> { - let mut all_solutions : Vec> = Vec::new(); - let solutions = build_solutions_from(source_dir, language_builder, model_builder_cache); - solutions.into_iter().for_each(|s| all_solutions.push(Rc::new(s))); + build_solutions_from(source_dir, &language_builder, & mut all_solutions); let mut languages: Vec> = Vec::new(); - language_builder.language_id_to_slanguage.borrow().values().for_each(|v| languages.push(Rc::clone(v))); + language_builder.borrow().language_id_to_slanguage.borrow().values().for_each(|v| languages.push(Rc::clone(v))); SRepository::new(all_solutions, languages) } -fn build_solutions_from<'a>(source_dir: String, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache<'a>) -> Vec> { +fn build_solutions_from<'a>(source_dir: String, language_builder : &RefCell, solutions : &'a mut Vec>) { let now = Instant::now(); - let solutions = collect_modules_from_sources(source_dir.clone(), language_builder, model_builder_cache); + collect_modules_from_sources(source_dir.clone(), language_builder, solutions); let elapsed = now.elapsed(); println!("{} milli seconds for handling {}", elapsed.as_millis(), source_dir); - - return solutions; } -pub fn collect_modules_from_sources<'a>(source_dir: String, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache<'a>) -> Vec> { +pub fn collect_modules_from_sources<'a>(source_dir: String, language_builder : &RefCell, solutions : &'a mut Vec>) { + let model_builder_cache = RefCell::new(SModelBuilderCache::new()); + let msd_files = find_msd_files(&source_dir, 3); - let solutions: Vec = msd_files.iter().map(|msd_file| build_solution(msd_file, language_builder, &model_builder_cache)).collect(); - return solutions; + msd_files.iter() + .for_each(|msd_file| { + let s = build_solution(msd_file, language_builder, &model_builder_cache); + solutions.push(Rc::new(s)); + }); } pub fn find_msd_files(source_dir: &String, start_depth: usize) -> Vec { @@ -71,8 +62,6 @@ mod tests { use std::cell::RefCell; use std::rc::Rc; - use crate::builder::slanguage_builder::SLanguageBuilder; - use crate::builder::smodel_builder_file_per_root_persistency::SModelBuilderCache; use crate::builder::smodules_repository_builder::{build_repo_from_directory, find_msd_files}; use crate::model::smodel::SModel; @@ -95,9 +84,7 @@ mod tests { use std::time::Instant; let now = Instant::now(); //when - let language_builder = SLanguageBuilder::new(); - let model_builder_cache = SModelBuilderCache::new(); - let repository = build_repo_from_directory(src_dir, &language_builder, &model_builder_cache); + let repository = build_repo_from_directory(src_dir); //then let required_time = now.elapsed().as_millis(); diff --git a/mps-cli-rs/src/builder/ssolution_builder.rs b/mps-cli-rs/src/builder/ssolution_builder.rs index a46b73b..3ac92cb 100644 --- a/mps-cli-rs/src/builder/ssolution_builder.rs +++ b/mps-cli-rs/src/builder/ssolution_builder.rs @@ -1,3 +1,4 @@ +use std::cell::RefCell; use std::path::PathBuf; use std::time::Instant; @@ -10,7 +11,7 @@ use crate::model::ssolution::SSolution; use super::smodel_builder_file_per_root_persistency::SModelBuilderCache; -pub fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_builder : &'a SLanguageBuilder, model_builder_cache : &'a SModelBuilderCache<'a>) -> SSolution<'a> { +pub fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_builder : &RefCell, model_builder_cache : &RefCell) -> SSolution { let now = Instant::now(); let path_to_msd_file = path_buf_to_msd_file.to_str().unwrap().to_string(); @@ -36,7 +37,7 @@ pub fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_builder : &'a return solution; } -fn extract_solution_core_info<'a>(path_to_msd_file: String) -> SSolution<'a> { +fn extract_solution_core_info<'a>(path_to_msd_file: String) -> SSolution { //let solution_file = SolutionFile::new(&path_to_msd_file); let file = std::fs::File::open(path_to_msd_file.clone()); diff --git a/mps-cli-rs/src/main.rs b/mps-cli-rs/src/main.rs index 6c62bd6..4a2d66c 100644 --- a/mps-cli-rs/src/main.rs +++ b/mps-cli-rs/src/main.rs @@ -2,14 +2,40 @@ mod model; mod builder; use crate::builder::smodules_repository_builder::build_repo_from_directory; -use crate::builder::slanguage_builder::SLanguageBuilder; -use crate::builder::smodel_builder_file_per_root_persistency::SModelBuilderCache; fn main() { - let language_builder = SLanguageBuilder::new(); - let model_builder_cache = SModelBuilderCache::new(); - let repository = build_repo_from_directory(String::from("C:\\work\\E3_2.0_Solution\\solutions"), &language_builder, &model_builder_cache); + let repository = build_repo_from_directory(String::from("C:\\work\\E3_2.0_Solution\\solutions")); println!("number of solutions: {}", repository.solutions.borrow().len()); } -//160523 milli seconds \ No newline at end of file + +/* +use std::{path::PathBuf, time::Instant}; +use std::io::Read; +use roxmltree::{Document, Node, ParsingOptions}; +use std::rc::Rc; +use std::cell::RefCell; + +use walkdir::{DirEntry, WalkDir}; + +fn main() { + let repo_dir = WalkDir::new("C:\\work\\E3_2.0_Solution\\solutions").min_depth(1).max_depth(10); + + let initial_timestamp = Instant::now(); + let mpsr_files : Vec = repo_dir.into_iter() + .filter_map(|e| e.ok()) + .filter(|e| e.clone().into_path().is_file()) + .filter(|f| f.file_name().to_str().unwrap().ends_with(".mpsr")) + .collect(); + let files_collected_timestamp = Instant::now(); + println!("{} files collected in {}ms", mpsr_files.len(), files_collected_timestamp.duration_since(initial_timestamp).as_millis()); + + for file in mpsr_files.iter() { + let file = std::fs::File::open(file.path()); + let mut s = String::new(); + let _ = file.unwrap().read_to_string(&mut s); + let parse_res = roxmltree::Document::parse(&s); + }; + println!("{} files parsed in {}ms", mpsr_files.len(), Instant::now().duration_since(files_collected_timestamp).as_millis()); + +}*/ \ No newline at end of file diff --git a/mps-cli-rs/src/model/smodel.rs b/mps-cli-rs/src/model/smodel.rs index 8360acc..eb3efb2 100644 --- a/mps-cli-rs/src/model/smodel.rs +++ b/mps-cli-rs/src/model/smodel.rs @@ -1,17 +1,17 @@ use crate::model::snode::SNode; use std::{cell::RefCell, rc::Rc}; -pub struct SModel<'a> { +pub struct SModel { pub name: String, pub uuid: String, - pub root_nodes: Vec>>, + pub root_nodes: Vec>, pub path_to_model_file: String, pub is_do_not_generate: bool, pub is_file_per_root_persistency: bool, - pub imported_models: Vec>>> + pub imported_models: Vec>> } -impl<'a> SModel<'a> { +impl SModel { pub fn new(name: String, uuid: String) -> Self { SModel { name, @@ -24,7 +24,7 @@ impl<'a> SModel<'a> { } } - pub fn get_nodes(&self) -> Vec>> { + pub fn get_nodes(&self) -> Vec> { let mut nodes = Vec::new(); for root in self.root_nodes.iter() { nodes.extend(SNode::get_descendants(Rc::clone(root), true)); @@ -32,7 +32,7 @@ impl<'a> SModel<'a> { return nodes; } - pub fn get_node_by_id(&self, id: &str) -> Option>> { + pub fn get_node_by_id(&self, id: &str) -> Option> { let nodes = self.get_nodes(); let n = nodes.iter().find(|node| node.id.eq(id)); if let Some(nn) = n { return Some(Rc::clone(nn)); } diff --git a/mps-cli-rs/src/model/snode.rs b/mps-cli-rs/src/model/snode.rs index e746be9..bc96931 100644 --- a/mps-cli-rs/src/model/snode.rs +++ b/mps-cli-rs/src/model/snode.rs @@ -5,17 +5,17 @@ use crate::model::snoderef::SNodeRef; use std::rc::Rc; use std::cell::RefCell; -pub struct SNode<'a> { +pub struct SNode { pub id: String, pub concept: Rc, pub role_in_parent: Option, properties: RefCell, String>>, - children: RefCell, Vec>>>>, - references: RefCell, Rc>>>, - pub parent: RefCell>>>, + children: RefCell, Vec>>>, + references: RefCell, Rc>>, + pub parent: RefCell>>, } -impl<'a> SNode<'a> { +impl SNode { pub fn new(id: String, concept: Rc, role_in_parent: Option) -> Self { SNode { id, @@ -45,7 +45,7 @@ impl<'a> SNode<'a> { self.references.borrow_mut().insert(Rc::clone(reference_link), Rc::new(SNodeRef::new(to, resolve.unwrap_or("".to_string())))); } - pub fn get_reference(&self, ref_role_name: &str) -> Option>> { + pub fn get_reference(&self, ref_role_name: &str) -> Option> { let references = self.references.borrow(); let entry = references.iter().find(|it| it.0.name.eq(ref_role_name)); match entry { @@ -54,13 +54,13 @@ impl<'a> SNode<'a> { } } - pub fn add_child(&self, cl: Rc, node: Rc>) { + pub fn add_child(&self, cl: Rc, node: Rc) { let mut children = self.children.borrow_mut(); let vec = children.entry(Rc::clone(&cl)).or_insert(Vec::new()); vec.push(Rc::clone(&node)); } - pub fn get_children(&self, child_role_name: &str) -> Vec>> { + pub fn get_children(&self, child_role_name: &str) -> Vec> { let children = self.children.borrow(); let entry = children.iter().find(|it| it.0.name.eq(child_role_name)); match entry { @@ -69,20 +69,20 @@ impl<'a> SNode<'a> { } } - pub fn set_parent(&self, parent : Rc>) { + pub fn set_parent(&self, parent : Rc) { self.parent.replace(Some(parent)); } - pub fn get_descendants(node : Rc>, include_self: bool) -> Vec>> { - let mut descendants: Vec>> = Vec::new(); + pub fn get_descendants(node : Rc, include_self: bool) -> Vec> { + let mut descendants: Vec> = Vec::new(); if include_self { descendants.push(Rc::clone(&node)) } Self::get_descendants_internal(node, &mut descendants); return descendants; } - fn get_descendants_internal(node : Rc>, descendants: &mut Vec>>) { + fn get_descendants_internal(node : Rc, descendants: &mut Vec>) { let children = node.children.borrow(); - let vectors_of_children : Vec<&Rc>> = children.values().flatten().collect(); + let vectors_of_children : Vec<&Rc> = children.values().flatten().collect(); for child in vectors_of_children { descendants.push(Rc::clone(child)); Self::get_descendants_internal(Rc::clone(child), descendants); diff --git a/mps-cli-rs/src/model/snoderef.rs b/mps-cli-rs/src/model/snoderef.rs index 0e3dd94..24242be 100644 --- a/mps-cli-rs/src/model/snoderef.rs +++ b/mps-cli-rs/src/model/snoderef.rs @@ -2,13 +2,13 @@ use crate::model::snode::SNode; use crate::model::srepository::SRepository; use std::rc::Rc; -pub struct SNodeRef<'a> { +pub struct SNodeRef { pub to: String, pub resolve_info: String, - referenced_node : Option>>, + referenced_node : Option>, } -impl<'a> SNodeRef<'a> { +impl SNodeRef { pub fn new(to: String, resolve_info: String) -> Self { SNodeRef { to, @@ -17,7 +17,7 @@ impl<'a> SNodeRef<'a> { } } - pub fn resolve(&'a self, repository: &'a SRepository<'a>) -> Option>> { + pub fn resolve(&self, repository: &SRepository) -> Option> { /*if self.referenced_node.is_some() { return self.referenced_node.clone(); }*/ diff --git a/mps-cli-rs/src/model/srepository.rs b/mps-cli-rs/src/model/srepository.rs index ffbd17f..0bb2c6b 100644 --- a/mps-cli-rs/src/model/srepository.rs +++ b/mps-cli-rs/src/model/srepository.rs @@ -7,26 +7,23 @@ use std::ops::Deref; use std::rc::Rc; use std::cell::RefCell; -pub struct SRepository<'a> { - pub solutions: RefCell>>>, +pub struct SRepository { + pub solutions: RefCell>>, languages: RefCell>>, } -impl<'a> SRepository<'a> { - pub fn new(solutions: Vec>>, languages: Vec>) -> Self { +impl SRepository { + pub fn new(solutions: Vec>, languages: Vec>) -> Self { SRepository { solutions : RefCell::new(solutions), languages : RefCell::new(languages), } } - pub fn find_solution_by_name(&self, name: &str) -> Option>> { + pub fn find_solution_by_name(&self, name: &str) -> Option> { let solutions = self.solutions.borrow(); let found_solution = solutions.iter().find(|&ssolution| ssolution.name.eq(name)); - if let Some(found_solution) = found_solution { - return Some(Rc::clone(found_solution)); - } - None + found_solution.map(|s| Rc::clone(s)) } /*pub fn get_model_by_uuid(&self, uuid: &str) -> Option>>> { diff --git a/mps-cli-rs/src/model/ssolution.rs b/mps-cli-rs/src/model/ssolution.rs index b939595..3cb723c 100644 --- a/mps-cli-rs/src/model/ssolution.rs +++ b/mps-cli-rs/src/model/ssolution.rs @@ -2,14 +2,14 @@ use std::{cell::RefCell, rc::Rc}; use crate::model::smodel::SModel; -pub struct SSolution<'a> { +pub struct SSolution { pub name: String, pub uuid: String, pub path_to_module_file: String, - pub models: Vec>>>, + pub models: Vec>>, } -impl<'a> SSolution<'a> { +impl SSolution { pub fn new(name: String, uuid: String, path_to_module_file: String) -> Self { SSolution { name, From 3bbe8d2783b1a708f45d74189ecb7a30a4420919 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Thu, 6 Jun 2024 08:04:13 +0200 Subject: [PATCH 20/43] rs: cleanup + restructured tests --- .../tests/test_node_id_encoding_utils.py | 0 mps-cli-rs/Cargo.toml | 13 ++++- mps-cli-rs/src/model/smodel.rs | 9 +++ mps-cli-rs/src/model/srepository.rs | 24 ++++++++ mps-cli-rs/src/model/ssolution.rs | 8 +++ mps-cli-rs/src/mps_cli_lib.rs | 8 +++ .../tests/file_per_root_persistency_tests.rs | 55 +++++++++++++++++++ mps-cli-rs/tests/model_completeness_tests.rs | 16 ++++++ 8 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 mps-cli-py/tests/test_node_id_encoding_utils.py create mode 100644 mps-cli-rs/src/mps_cli_lib.rs create mode 100644 mps-cli-rs/tests/file_per_root_persistency_tests.rs create mode 100644 mps-cli-rs/tests/model_completeness_tests.rs diff --git a/mps-cli-py/tests/test_node_id_encoding_utils.py b/mps-cli-py/tests/test_node_id_encoding_utils.py new file mode 100644 index 0000000..e69de29 diff --git a/mps-cli-rs/Cargo.toml b/mps-cli-rs/Cargo.toml index 83457d7..6e9740d 100644 --- a/mps-cli-rs/Cargo.toml +++ b/mps-cli-rs/Cargo.toml @@ -1,14 +1,21 @@ [package] -name = "mps_cli_rs" +name = "mps-cli" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +path = "src/mps_cli_lib.rs" + +[features] +default = [] +std = [] + [dependencies] walkdir = "2.5.0" -roxmltree = "0.19.0" +roxmltree = "0.20.0" [profile.release] -lto = "thin" +lto = "fat" codegen-units = 1 \ No newline at end of file diff --git a/mps-cli-rs/src/model/smodel.rs b/mps-cli-rs/src/model/smodel.rs index eb3efb2..77b10aa 100644 --- a/mps-cli-rs/src/model/smodel.rs +++ b/mps-cli-rs/src/model/smodel.rs @@ -38,5 +38,14 @@ impl SModel { if let Some(nn) = n { return Some(Rc::clone(nn)); } None } + + pub fn find_root(&self, name : &str) -> Option> { + let root = self.root_nodes.iter().find(|r| if let Some(n) = r.get_property("name") { n == name } else { false }); + if let Some(rn) = root { + Some(Rc::clone(rn)) + } else { + None + } + } } diff --git a/mps-cli-rs/src/model/srepository.rs b/mps-cli-rs/src/model/srepository.rs index 0bb2c6b..47c7fe2 100644 --- a/mps-cli-rs/src/model/srepository.rs +++ b/mps-cli-rs/src/model/srepository.rs @@ -26,6 +26,30 @@ impl SRepository { found_solution.map(|s| Rc::clone(s)) } + pub fn find_model_by_name(&self, name: &str) -> Option>> { + let solutions = self.solutions.borrow(); + for s in solutions.iter() { + for m in s.models.iter() { + if let Ok(model) = m.clone().try_borrow() { + println!("model {}", model.name); + if model.name == name { return Some(Rc::clone(m)); } + } + } + } + None + } + + pub fn get_all_models(&self) -> Vec>> { + let mut res : Vec>> = Vec::new(); + let solutions = self.solutions.borrow(); + for s in solutions.iter() { + for m in s.models.iter() { + res.push(Rc::clone(m)); + } + } + res + } + /*pub fn get_model_by_uuid(&self, uuid: &str) -> Option>>> { let solutions = self.solutions.borrow(); for sol in solutions.into_iter() { diff --git a/mps-cli-rs/src/model/ssolution.rs b/mps-cli-rs/src/model/ssolution.rs index 3cb723c..663565c 100644 --- a/mps-cli-rs/src/model/ssolution.rs +++ b/mps-cli-rs/src/model/ssolution.rs @@ -18,4 +18,12 @@ impl SSolution { models: vec![], } } + + pub fn find_model(&self, name : &str) -> Option>> { + let model = self.models.iter().find(|m| m.borrow().name == name); + if let Some(model) = model { + return Some(Rc::clone(model)); + } + None + } } \ No newline at end of file diff --git a/mps-cli-rs/src/mps_cli_lib.rs b/mps-cli-rs/src/mps_cli_lib.rs new file mode 100644 index 0000000..ec3ce1c --- /dev/null +++ b/mps-cli-rs/src/mps_cli_lib.rs @@ -0,0 +1,8 @@ +pub mod model; +mod builder; + +use crate::model::srepository::SRepository; + +pub fn build_repo_from_directory(source_dir: String) -> SRepository { + crate::builder::smodules_repository_builder::build_repo_from_directory(source_dir) +} \ No newline at end of file diff --git a/mps-cli-rs/tests/file_per_root_persistency_tests.rs b/mps-cli-rs/tests/file_per_root_persistency_tests.rs new file mode 100644 index 0000000..5f138e1 --- /dev/null +++ b/mps-cli-rs/tests/file_per_root_persistency_tests.rs @@ -0,0 +1,55 @@ +mod model_completeness_tests; +use mps_cli::build_repo_from_directory; + +#[test] +fn test_build_repository() { + // given + let path = "../mps_test_projects/mps_cli_lanuse_file_per_root/"; + + //when + let repo = build_repo_from_directory(path.to_string()); + + //assert + assert_eq!(repo.solutions.borrow().len(), 2); + + let library_top_solution = repo.find_solution_by_name("mps.cli.lanuse.library_top").unwrap(); + assert_eq!(library_top_solution.models.len(), 2); + let library_top_model = library_top_solution.find_model("mps.cli.lanuse.library_top.library_top").unwrap(); + assert_eq!(library_top_model.borrow().root_nodes.len(), 2); + + + let library_second_solution = repo.find_solution_by_name("mps.cli.lanuse.library_second").unwrap(); + assert_eq!(library_second_solution.models.len(), 1); + + let munich_library = library_top_model.borrow().find_root("munich_library"); + assert!(munich_library.is_some()); + + let munich_library = munich_library.unwrap(); + let munich_library_entities = munich_library.get_children("entities"); + assert_eq!(munich_library_entities.len(), 4); + let tom_sawyer = munich_library_entities.first().unwrap(); + assert_eq!(tom_sawyer.get_property("name"), Some(String::from("Tom Sawyer"))); + assert_eq!(tom_sawyer.role_in_parent, Some(String::from("entities"))); + assert_eq!(tom_sawyer.get_property("publicationDate"), Some(String::from("1876"))); + assert_eq!(tom_sawyer.get_property("isbn"), Some(String::from("4323r2"))); + assert_eq!(tom_sawyer.get_property("available"), Some(String::from("true"))); + assert_eq!(tom_sawyer.concept.name, String::from("mps.cli.landefs.library.structure.Book")); + + let authors = tom_sawyer.get_children("authors"); + let mark_twain = authors.first().unwrap().get_reference("person").unwrap(); + assert_eq!(mark_twain.resolve_info, "Mark Twain"); + assert_eq!(mark_twain.to, "q0v6:4Yb5JA31NUv"); +} + + +#[test] +fn test_navigate_model() { + let path = "../mps_test_projects/mps_cli_lanuse_file_per_root/solutions/"; + let repo = build_repo_from_directory(path.to_string()); + + let library_top_model = repo.find_model_by_name("mps.cli.lanuse.library_top.library_top").unwrap(); + if let Ok(library_top_model) = library_top_model.try_borrow() { + model_completeness_tests::check_model_completeness(&library_top_model); + }; + +} \ No newline at end of file diff --git a/mps-cli-rs/tests/model_completeness_tests.rs b/mps-cli-rs/tests/model_completeness_tests.rs new file mode 100644 index 0000000..05c3410 --- /dev/null +++ b/mps-cli-rs/tests/model_completeness_tests.rs @@ -0,0 +1,16 @@ + +use std::rc::Rc; +use mps_cli::model::{smodel::SModel, snode::SNode}; + + +pub (crate) fn check_model_completeness(model : &SModel) { + + //assert + let munich_library_root = model.root_nodes.first().unwrap(); + assert_eq!(munich_library_root.get_property("name"), Some(String::from("munich_library"))); + assert_eq!(SNode::get_descendants(Rc::clone(munich_library_root), true).len(), 8); + assert_eq!(munich_library_root.get_children("entities").len(), 4); + + assert_eq!(model.get_nodes().len(), 9); + assert_eq!(model.get_node_by_id("4Yb5JA31NUC").unwrap().get_property("name").unwrap(), "munich_library"); +} \ No newline at end of file From ad6681b0c61f835eac44533e27557ed2bad2df79 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Sat, 8 Jun 2024 21:28:00 +0200 Subject: [PATCH 21/43] rs: improved tests --- ...model_builder_file_per_root_persistency.rs | 56 ------------------- .../tests/file_per_root_persistency_tests.rs | 50 +---------------- mps-cli-rs/tests/model_completeness_tests.rs | 43 +++++++++++--- 3 files changed, 37 insertions(+), 112 deletions(-) diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index fdb44c8..41261f7 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -317,60 +317,4 @@ mod tests { assert_eq!(import.borrow_mut().uuid, "r:ec5f093b-9d83-43a1-9b41-b5952da8b1ed"); } - #[test] - fn test_build_model() { - // given - let path = "../mps_test_projects/mps_cli_lanuse_file_per_root/solutions/mps.cli.lanuse.library_top/models/mps.cli.lanuse.library_top.library_top"; - let path_to_mpsr_file = PathBuf::from(path); - - //when - let mut language_builder = RefCell::new(SLanguageBuilder::new()); - let model_builder_cache = RefCell::new(SModelBuilderCache::new()); - let temp = SModelBuilderFilePerRootPersistency::build_model(path_to_mpsr_file, &mut language_builder, &model_builder_cache); - let model = temp.as_ref().borrow(); - - //assert - assert_eq!(model.root_nodes.len(), 2); - let munich_library = model.root_nodes.first().unwrap(); - assert_eq!(munich_library.get_property("name"), Some(String::from("munich_library"))); - - let munich_library_entities = munich_library.get_children("entities"); - assert_eq!(munich_library_entities.len(), 4); - let tom_sawyer = munich_library_entities.first().unwrap(); - assert_eq!(tom_sawyer.get_property("name"), Some(String::from("Tom Sawyer"))); - assert_eq!(tom_sawyer.role_in_parent, Some(String::from("entities"))); - assert_eq!(tom_sawyer.get_property("publicationDate"), Some(String::from("1876"))); - assert_eq!(tom_sawyer.get_property("isbn"), Some(String::from("4323r2"))); - assert_eq!(tom_sawyer.get_property("available"), Some(String::from("true"))); - assert_eq!(tom_sawyer.concept.name, String::from("mps.cli.landefs.library.structure.Book")); - - let authors = tom_sawyer.get_children("authors"); - let mark_twain = authors.first().unwrap().get_reference("person").unwrap(); - assert_eq!(mark_twain.resolve_info, "Mark Twain"); - assert_eq!(mark_twain.to, "q0v6:4Yb5JA31NUv"); - - } - - #[test] - fn test_navigate_model() { - // given - let path = "../mps_test_projects/mps_cli_lanuse_file_per_root/solutions/mps.cli.lanuse.library_top/models/mps.cli.lanuse.library_top.library_top"; - let path_to_mpsr_file = PathBuf::from(path); - - //when - let mut language_builder = RefCell::new(SLanguageBuilder::new()); - let model_builder_cache = RefCell::new(SModelBuilderCache::new()); - let temp = SModelBuilderFilePerRootPersistency::build_model(path_to_mpsr_file, &mut language_builder, &model_builder_cache); - let model = temp.as_ref().borrow(); - - //assert - let munich_library_root = model.root_nodes.first().unwrap(); - assert_eq!(munich_library_root.get_property("name"), Some(String::from("munich_library"))); - assert_eq!(SNode::get_descendants(Rc::clone(munich_library_root), true).len(), 8); - assert_eq!(munich_library_root.get_children("entities").len(), 4); - - assert_eq!(model.get_nodes().len(), 9); - assert_eq!(model.get_node_by_id("4Yb5JA31NUC").unwrap().get_property("name").unwrap(), "munich_library"); - } - } diff --git a/mps-cli-rs/tests/file_per_root_persistency_tests.rs b/mps-cli-rs/tests/file_per_root_persistency_tests.rs index 5f138e1..49dd015 100644 --- a/mps-cli-rs/tests/file_per_root_persistency_tests.rs +++ b/mps-cli-rs/tests/file_per_root_persistency_tests.rs @@ -3,53 +3,7 @@ use mps_cli::build_repo_from_directory; #[test] fn test_build_repository() { - // given - let path = "../mps_test_projects/mps_cli_lanuse_file_per_root/"; - - //when - let repo = build_repo_from_directory(path.to_string()); - - //assert - assert_eq!(repo.solutions.borrow().len(), 2); - - let library_top_solution = repo.find_solution_by_name("mps.cli.lanuse.library_top").unwrap(); - assert_eq!(library_top_solution.models.len(), 2); - let library_top_model = library_top_solution.find_model("mps.cli.lanuse.library_top.library_top").unwrap(); - assert_eq!(library_top_model.borrow().root_nodes.len(), 2); - - - let library_second_solution = repo.find_solution_by_name("mps.cli.lanuse.library_second").unwrap(); - assert_eq!(library_second_solution.models.len(), 1); - - let munich_library = library_top_model.borrow().find_root("munich_library"); - assert!(munich_library.is_some()); - - let munich_library = munich_library.unwrap(); - let munich_library_entities = munich_library.get_children("entities"); - assert_eq!(munich_library_entities.len(), 4); - let tom_sawyer = munich_library_entities.first().unwrap(); - assert_eq!(tom_sawyer.get_property("name"), Some(String::from("Tom Sawyer"))); - assert_eq!(tom_sawyer.role_in_parent, Some(String::from("entities"))); - assert_eq!(tom_sawyer.get_property("publicationDate"), Some(String::from("1876"))); - assert_eq!(tom_sawyer.get_property("isbn"), Some(String::from("4323r2"))); - assert_eq!(tom_sawyer.get_property("available"), Some(String::from("true"))); - assert_eq!(tom_sawyer.concept.name, String::from("mps.cli.landefs.library.structure.Book")); - - let authors = tom_sawyer.get_children("authors"); - let mark_twain = authors.first().unwrap().get_reference("person").unwrap(); - assert_eq!(mark_twain.resolve_info, "Mark Twain"); - assert_eq!(mark_twain.to, "q0v6:4Yb5JA31NUv"); -} - - -#[test] -fn test_navigate_model() { - let path = "../mps_test_projects/mps_cli_lanuse_file_per_root/solutions/"; + let path = "../mps_test_projects/mps_cli_lanuse_file_per_root/"; let repo = build_repo_from_directory(path.to_string()); - - let library_top_model = repo.find_model_by_name("mps.cli.lanuse.library_top.library_top").unwrap(); - if let Ok(library_top_model) = library_top_model.try_borrow() { - model_completeness_tests::check_model_completeness(&library_top_model); - }; - + model_completeness_tests::check_model_completeness(&repo); } \ No newline at end of file diff --git a/mps-cli-rs/tests/model_completeness_tests.rs b/mps-cli-rs/tests/model_completeness_tests.rs index 05c3410..d801a49 100644 --- a/mps-cli-rs/tests/model_completeness_tests.rs +++ b/mps-cli-rs/tests/model_completeness_tests.rs @@ -1,16 +1,43 @@ -use std::rc::Rc; -use mps_cli::model::{smodel::SModel, snode::SNode}; +use std::{cell::Ref, rc::Rc}; +use mps_cli::model::{smodel::SModel, srepository::SRepository, snode::SNode}; +#[cfg(test)] +pub (crate) fn check_model_completeness(repo : &SRepository) { + //library_first_solution + let library_first_solution = repo.find_solution_by_name("mps.cli.lanuse.library_top").unwrap(); + assert_eq!(library_first_solution.models.len(), 2); + assert!(library_first_solution.find_model("mps.cli.lanuse.library_top.authors_top").is_some()); + assert!(library_first_solution.find_model("mps.cli.lanuse.library_top.library_top").is_some()); -pub (crate) fn check_model_completeness(model : &SModel) { - - //assert - let munich_library_root = model.root_nodes.first().unwrap(); + let library_top_model = repo.find_model_by_name("mps.cli.lanuse.library_top.library_top").unwrap(); + let library_top_model : Ref = library_top_model.try_borrow().ok().unwrap(); + assert_eq!(library_top_model.root_nodes.len(), 2); + let munich_library_root = library_top_model.root_nodes.first().unwrap(); assert_eq!(munich_library_root.get_property("name"), Some(String::from("munich_library"))); assert_eq!(SNode::get_descendants(Rc::clone(munich_library_root), true).len(), 8); assert_eq!(munich_library_root.get_children("entities").len(), 4); - assert_eq!(model.get_nodes().len(), 9); - assert_eq!(model.get_node_by_id("4Yb5JA31NUC").unwrap().get_property("name").unwrap(), "munich_library"); + assert_eq!(library_top_model.get_nodes().len(), 9); + assert_eq!(library_top_model.get_node_by_id("4Yb5JA31NUC").unwrap().get_property("name").unwrap(), "munich_library"); + + + let munich_library_entities = munich_library_root.get_children("entities"); + assert_eq!(munich_library_entities.len(), 4); + let tom_sawyer = munich_library_entities.first().unwrap(); + assert_eq!(tom_sawyer.get_property("name"), Some(String::from("Tom Sawyer"))); + assert_eq!(tom_sawyer.role_in_parent, Some(String::from("entities"))); + assert_eq!(tom_sawyer.get_property("publicationDate"), Some(String::from("1876"))); + assert_eq!(tom_sawyer.get_property("isbn"), Some(String::from("4323r2"))); + assert_eq!(tom_sawyer.get_property("available"), Some(String::from("true"))); + assert_eq!(tom_sawyer.concept.name, String::from("mps.cli.landefs.library.structure.Book")); + + let authors = tom_sawyer.get_children("authors"); + let mark_twain = authors.first().unwrap().get_reference("person").unwrap(); + assert_eq!(mark_twain.resolve_info, "Mark Twain"); + assert_eq!(mark_twain.to, "q0v6:4Yb5JA31NUv"); + + // library_second_solution + let library_second_solution = repo.find_solution_by_name("mps.cli.lanuse.library_second").unwrap(); + assert_eq!(library_second_solution.models.len(), 1); } \ No newline at end of file From 0b0e2e1f7753488c3686a31c62c83b7801e367e8 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Sat, 8 Jun 2024 22:54:15 +0200 Subject: [PATCH 22/43] rs: fixed snoderef --- ...model_builder_file_per_root_persistency.rs | 31 +++++++++++++++---- mps-cli-rs/src/model/snode.rs | 4 +-- mps-cli-rs/src/model/snoderef.rs | 22 ++++++------- mps-cli-rs/src/model/srepository.rs | 13 +++++--- mps-cli-rs/src/model/ssolution.rs | 1 + mps-cli-rs/tests/model_completeness_tests.rs | 6 ++-- 6 files changed, 50 insertions(+), 27 deletions(-) diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index 41261f7..1973c60 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -1,4 +1,4 @@ -use std::borrow::BorrowMut; +use std::borrow::{Borrow, BorrowMut}; use std::collections::HashMap; use std::path::PathBuf; use std::io::Read; @@ -22,17 +22,19 @@ pub struct SModelBuilderCache { pub index_2_reference_link: RefCell>>, pub index_2_imported_model_uuid: RefCell>, pub index_2_model : RefCell>>>, + pub current_model : RefCell>>>, } impl SModelBuilderCache { pub fn new() -> Self { SModelBuilderCache { - index_2_concept: RefCell::new(HashMap::new()), - index_2_property: RefCell::new(HashMap::new()), + index_2_concept : RefCell::new(HashMap::new()), + index_2_property : RefCell::new(HashMap::new()), index_2_containment_link : RefCell::new(HashMap::new()), index_2_reference_link : RefCell::new(HashMap::new()), - index_2_imported_model_uuid: RefCell::new(HashMap::new()), - index_2_model: RefCell::new(HashMap::new()), + index_2_imported_model_uuid : RefCell::new(HashMap::new()), + index_2_model : RefCell::new(HashMap::new()), + current_model : RefCell::new(None), } } @@ -57,6 +59,7 @@ impl SModelBuilderFilePerRootPersistency { let mut model_file = path_to_model.clone(); model_file.push(".model"); let model: Rc> = Self::extract_model_core_info(model_file, model_builder_cache); + model_builder_cache.borrow_mut().current_model.replace(Some(Rc::clone(&model))); let mpsr_file_walker = WalkDir::new(path_to_model).min_depth(1).max_depth(1); let mpsr_files = mpsr_file_walker.into_iter().filter(|entry| { @@ -270,7 +273,23 @@ impl SModelBuilderFilePerRootPersistency { let index_2_reference_links = model_builder_cache.index_2_reference_link.borrow(); let reference_link = index_2_reference_links.get(&role.to_string()).unwrap(); - current_node.add_reference(reference_link, to.to_string(), resolve); + + let mut model_id = String::from(""); + let mut node_id = String::from(""); + if let Some(index) = to.find(":") { + let model_index = &to[0..index]; + let mm = model_builder_cache.index_2_imported_model_uuid.borrow(); + model_id = String::from(mm.get(model_index).unwrap()); + node_id = String::from(&to[index + 1..to.len()]); + } else { + let crt_model = model_builder_cache.current_model.borrow(); + let m = crt_model.as_ref().unwrap(); + let m = m.as_ref().borrow(); + model_id = String::from(m.uuid.as_str()); + node_id = String::from(to); + }; + + current_node.add_reference(reference_link, model_id, node_id, resolve); }; let nodes = node.children().filter(|it| it.tag_name().name() == "node"); diff --git a/mps-cli-rs/src/model/snode.rs b/mps-cli-rs/src/model/snode.rs index bc96931..1116a85 100644 --- a/mps-cli-rs/src/model/snode.rs +++ b/mps-cli-rs/src/model/snode.rs @@ -41,8 +41,8 @@ impl SNode { } } - pub fn add_reference(&self, reference_link: &Rc, to: String, resolve : Option) { - self.references.borrow_mut().insert(Rc::clone(reference_link), Rc::new(SNodeRef::new(to, resolve.unwrap_or("".to_string())))); + pub fn add_reference(&self, reference_link: &Rc, model_id : String, node_id : String, resolve : Option) { + self.references.borrow_mut().insert(Rc::clone(reference_link), Rc::new(SNodeRef::new(model_id, node_id, resolve.unwrap_or("".to_string())))); } pub fn get_reference(&self, ref_role_name: &str) -> Option> { diff --git a/mps-cli-rs/src/model/snoderef.rs b/mps-cli-rs/src/model/snoderef.rs index 24242be..5d2975b 100644 --- a/mps-cli-rs/src/model/snoderef.rs +++ b/mps-cli-rs/src/model/snoderef.rs @@ -3,37 +3,35 @@ use crate::model::srepository::SRepository; use std::rc::Rc; pub struct SNodeRef { - pub to: String, + pub model_id: String, + pub node_id: String, pub resolve_info: String, referenced_node : Option>, } impl SNodeRef { - pub fn new(to: String, resolve_info: String) -> Self { + pub fn new(model_id: String, node_id: String, resolve_info: String) -> Self { SNodeRef { - to, + model_id, + node_id, resolve_info, referenced_node : None, } } pub fn resolve(&self, repository: &SRepository) -> Option> { - /*if self.referenced_node.is_some() { + if self.referenced_node.is_some() { return self.referenced_node.clone(); - }*/ - + } - /*return match repository.get_model_by_uuid(&self.model_uuid) { + return match repository.get_model_by_uuid(self.model_id.as_str()) { None => None, Some(model) => - if let Some(n) = model.get_node_by_uuid(&self.node_uuid) { + if let Some(n) = model.borrow().get_node_by_id(self.node_id.as_str()) { return Some(n); } else { return None; } - };*/ - //let model = repository.get_model_by_uuid(&self.model_uuid).unwrap(); - //model.get_node_by_uuid(&self.node_uuid); - None + }; } } \ No newline at end of file diff --git a/mps-cli-rs/src/model/srepository.rs b/mps-cli-rs/src/model/srepository.rs index 47c7fe2..11635ee 100644 --- a/mps-cli-rs/src/model/srepository.rs +++ b/mps-cli-rs/src/model/srepository.rs @@ -20,12 +20,14 @@ impl SRepository { } } + #[allow(dead_code)] pub fn find_solution_by_name(&self, name: &str) -> Option> { let solutions = self.solutions.borrow(); let found_solution = solutions.iter().find(|&ssolution| ssolution.name.eq(name)); found_solution.map(|s| Rc::clone(s)) } + #[allow(dead_code)] pub fn find_model_by_name(&self, name: &str) -> Option>> { let solutions = self.solutions.borrow(); for s in solutions.iter() { @@ -39,6 +41,7 @@ impl SRepository { None } + #[allow(dead_code)] pub fn get_all_models(&self) -> Vec>> { let mut res : Vec>> = Vec::new(); let solutions = self.solutions.borrow(); @@ -50,16 +53,16 @@ impl SRepository { res } - /*pub fn get_model_by_uuid(&self, uuid: &str) -> Option>>> { + #[allow(dead_code)] + pub fn get_model_by_uuid(&self, uuid: &str) -> Option>> { let solutions = self.solutions.borrow(); - for sol in solutions.into_iter() { - let models = sol.models; - for m in models.iter() { + for sol in solutions.iter() { + for m in sol.models.iter() { if (**m).borrow().uuid.eq(uuid) { return Some(Rc::clone(m)); } } } None - }*/ + } } \ No newline at end of file diff --git a/mps-cli-rs/src/model/ssolution.rs b/mps-cli-rs/src/model/ssolution.rs index 663565c..1c8ee42 100644 --- a/mps-cli-rs/src/model/ssolution.rs +++ b/mps-cli-rs/src/model/ssolution.rs @@ -19,6 +19,7 @@ impl SSolution { } } + #[allow(dead_code)] pub fn find_model(&self, name : &str) -> Option>> { let model = self.models.iter().find(|m| m.borrow().name == name); if let Some(model) = model { diff --git a/mps-cli-rs/tests/model_completeness_tests.rs b/mps-cli-rs/tests/model_completeness_tests.rs index d801a49..10e7a28 100644 --- a/mps-cli-rs/tests/model_completeness_tests.rs +++ b/mps-cli-rs/tests/model_completeness_tests.rs @@ -35,8 +35,10 @@ pub (crate) fn check_model_completeness(repo : &SRepository) { let authors = tom_sawyer.get_children("authors"); let mark_twain = authors.first().unwrap().get_reference("person").unwrap(); assert_eq!(mark_twain.resolve_info, "Mark Twain"); - assert_eq!(mark_twain.to, "q0v6:4Yb5JA31NUv"); - + assert_eq!(mark_twain.model_id, "r:ec5f093b-9d83-43a1-9b41-b5952da8b1ed"); + assert_eq!(mark_twain.node_id, "4Yb5JA31NUv"); + assert!(mark_twain.resolve(repo).is_some()); + // library_second_solution let library_second_solution = repo.find_solution_by_name("mps.cli.lanuse.library_second").unwrap(); assert_eq!(library_second_solution.models.len(), 1); From dee859cab988c13d24667d371a983969ab25bb3c Mon Sep 17 00:00:00 2001 From: danielratiu Date: Sun, 16 Jun 2024 16:57:40 +0200 Subject: [PATCH 23/43] rs: added node-id decoding utils --- mps-cli-rs/Cargo.toml | 1 + mps-cli-rs/src/builder/mod.rs | 1 + mps-cli-rs/src/builder/node_id_utils.rs | 58 +++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 mps-cli-rs/src/builder/node_id_utils.rs diff --git a/mps-cli-rs/Cargo.toml b/mps-cli-rs/Cargo.toml index 6e9740d..b994d72 100644 --- a/mps-cli-rs/Cargo.toml +++ b/mps-cli-rs/Cargo.toml @@ -2,6 +2,7 @@ name = "mps-cli" version = "0.1.0" edition = "2021" +license = "Eclipse Public License - v 2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/mps-cli-rs/src/builder/mod.rs b/mps-cli-rs/src/builder/mod.rs index 308298b..ae86f08 100644 --- a/mps-cli-rs/src/builder/mod.rs +++ b/mps-cli-rs/src/builder/mod.rs @@ -2,3 +2,4 @@ pub mod smodules_repository_builder; mod ssolution_builder; pub mod smodel_builder_file_per_root_persistency; pub mod slanguage_builder; +mod node_id_utils; diff --git a/mps-cli-rs/src/builder/node_id_utils.rs b/mps-cli-rs/src/builder/node_id_utils.rs new file mode 100644 index 0000000..34773bd --- /dev/null +++ b/mps-cli-rs/src/builder/node_id_utils.rs @@ -0,0 +1,58 @@ +use std::collections::HashMap; + + +struct NodeIdEncodingUtils { + myIndexChars : String, + min_char : u8, + myCharToValue : HashMap, + +} + +impl NodeIdEncodingUtils { + pub fn new() -> Self { + let my_index_chars = String::from("0123456789abcdefghijklmnopqrstuvwxyz$_ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + let min_char = '$' as u8; + let mut myCharToValue : HashMap = HashMap::new(); + let bytes = my_index_chars.as_bytes(); + for i in 0..my_index_chars.len() { + let char_value = bytes[i] as u8; + let ii: usize = (char_value - min_char) as usize; + myCharToValue.insert(ii, i); + } + + NodeIdEncodingUtils { + myIndexChars : my_index_chars, + min_char : min_char, + myCharToValue : myCharToValue, + } + } + + pub fn decode(&self, uid_string : String) -> String { + let mut res = 0; + let bytes = uid_string.as_bytes(); + let mut c = bytes[0]; + let ii : usize = (c as u8 - self.min_char) as usize; + let mut value = self.myCharToValue[&ii]; + res = value; + for idx in 1..uid_string.len() { + res = res << 6; + c = bytes[idx]; + value = self.myIndexChars.find(c as char).unwrap(); + res = res | value; + } + return res.to_string(); + } + +} + +#[cfg(test)] +mod tests { + use crate::builder::node_id_utils::NodeIdEncodingUtils; + + #[test] + fn test_conversion() { + let node_id_utils = NodeIdEncodingUtils::new(); + + assert_eq!("5731700211660045983", node_id_utils.decode(String::from("4Yb5JA31NUv"))); + } +} \ No newline at end of file From 63b07d7ec929914c07561a802562053ed7f997cf Mon Sep 17 00:00:00 2001 From: danielratiu Date: Wed, 19 Jun 2024 17:10:42 +0200 Subject: [PATCH 24/43] rs: cleanup code --- mps-cli-rs/Cargo.toml | 2 +- mps-cli-rs/src/builder/mod.rs | 6 ++--- mps-cli-rs/src/builder/node_id_utils.rs | 4 ++-- ...model_builder_file_per_root_persistency.rs | 13 ++++------ .../builder/smodules_repository_builder.rs | 6 ++--- mps-cli-rs/src/builder/ssolution_builder.rs | 24 +------------------ mps-cli-rs/src/{mps_cli_lib.rs => lib.rs} | 0 mps-cli-rs/src/model/sconcept.rs | 1 + 8 files changed, 16 insertions(+), 40 deletions(-) rename mps-cli-rs/src/{mps_cli_lib.rs => lib.rs} (100%) diff --git a/mps-cli-rs/Cargo.toml b/mps-cli-rs/Cargo.toml index b994d72..7c8fc2f 100644 --- a/mps-cli-rs/Cargo.toml +++ b/mps-cli-rs/Cargo.toml @@ -7,7 +7,7 @@ license = "Eclipse Public License - v 2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] -path = "src/mps_cli_lib.rs" +path = "src/lib.rs" [features] default = [] diff --git a/mps-cli-rs/src/builder/mod.rs b/mps-cli-rs/src/builder/mod.rs index ae86f08..25c2ff9 100644 --- a/mps-cli-rs/src/builder/mod.rs +++ b/mps-cli-rs/src/builder/mod.rs @@ -1,5 +1,5 @@ -pub mod smodules_repository_builder; +pub(crate) mod smodules_repository_builder; mod ssolution_builder; -pub mod smodel_builder_file_per_root_persistency; -pub mod slanguage_builder; +mod smodel_builder_file_per_root_persistency; +mod slanguage_builder; mod node_id_utils; diff --git a/mps-cli-rs/src/builder/node_id_utils.rs b/mps-cli-rs/src/builder/node_id_utils.rs index 34773bd..2c04256 100644 --- a/mps-cli-rs/src/builder/node_id_utils.rs +++ b/mps-cli-rs/src/builder/node_id_utils.rs @@ -9,7 +9,7 @@ struct NodeIdEncodingUtils { } impl NodeIdEncodingUtils { - pub fn new() -> Self { + pub(crate) fn new() -> Self { let my_index_chars = String::from("0123456789abcdefghijklmnopqrstuvwxyz$_ABCDEFGHIJKLMNOPQRSTUVWXYZ"); let min_char = '$' as u8; let mut myCharToValue : HashMap = HashMap::new(); @@ -27,7 +27,7 @@ impl NodeIdEncodingUtils { } } - pub fn decode(&self, uid_string : String) -> String { + pub(crate) fn decode(&self, uid_string : String) -> String { let mut res = 0; let bytes = uid_string.as_bytes(); let mut c = bytes[0]; diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index 1973c60..3e9ed82 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -1,4 +1,4 @@ -use std::borrow::{Borrow, BorrowMut}; +use std::borrow::BorrowMut; use std::collections::HashMap; use std::path::PathBuf; use std::io::Read; @@ -26,7 +26,7 @@ pub struct SModelBuilderCache { } impl SModelBuilderCache { - pub fn new() -> Self { + pub(crate) fn new() -> Self { SModelBuilderCache { index_2_concept : RefCell::new(HashMap::new()), index_2_property : RefCell::new(HashMap::new()), @@ -38,7 +38,7 @@ impl SModelBuilderCache { } } - pub fn get_model(&self, name : String, uuid : String) -> Rc> { + fn get_model(&self, name : String, uuid : String) -> Rc> { let mut i2m = self.index_2_model.borrow_mut(); if let Some(model) = i2m.get(&uuid) { Rc::clone(&model) @@ -274,8 +274,8 @@ impl SModelBuilderFilePerRootPersistency { let index_2_reference_links = model_builder_cache.index_2_reference_link.borrow(); let reference_link = index_2_reference_links.get(&role.to_string()).unwrap(); - let mut model_id = String::from(""); - let mut node_id = String::from(""); + let model_id : String; + let node_id : String; if let Some(index) = to.find(":") { let model_index = &to[0..index]; let mm = model_builder_cache.index_2_imported_model_uuid.borrow(); @@ -307,11 +307,8 @@ impl SModelBuilderFilePerRootPersistency { mod tests { use std::cell::RefCell; use std::path::PathBuf; - use std::rc::Rc; - use crate::builder::slanguage_builder::SLanguageBuilder; use crate::builder::smodel_builder_file_per_root_persistency::{SModelBuilderCache, SModelBuilderFilePerRootPersistency}; - use crate::model::snode::SNode; #[test] fn test_model_extract_core_info() { diff --git a/mps-cli-rs/src/builder/smodules_repository_builder.rs b/mps-cli-rs/src/builder/smodules_repository_builder.rs index f6da85e..48b6a8f 100644 --- a/mps-cli-rs/src/builder/smodules_repository_builder.rs +++ b/mps-cli-rs/src/builder/smodules_repository_builder.rs @@ -12,7 +12,7 @@ use crate::model::srepository::SRepository; use crate::model::ssolution::SSolution; use crate::model::slanguage::SLanguage; -pub fn build_repo_from_directory<'a>(source_dir: String) -> SRepository { +pub(crate) fn build_repo_from_directory<'a>(source_dir: String) -> SRepository { let mut all_solutions : Vec> = Vec::new(); let language_builder = RefCell::new(SLanguageBuilder::new()); @@ -30,7 +30,7 @@ fn build_solutions_from<'a>(source_dir: String, language_builder : &RefCell(source_dir: String, language_builder : &RefCell, solutions : &'a mut Vec>) { +fn collect_modules_from_sources<'a>(source_dir: String, language_builder : &RefCell, solutions : &'a mut Vec>) { let model_builder_cache = RefCell::new(SModelBuilderCache::new()); let msd_files = find_msd_files(&source_dir, 3); @@ -41,7 +41,7 @@ pub fn collect_modules_from_sources<'a>(source_dir: String, language_builder : & }); } -pub fn find_msd_files(source_dir: &String, start_depth: usize) -> Vec { +fn find_msd_files(source_dir: &String, start_depth: usize) -> Vec { let walk_dir: WalkDir = WalkDir::new(source_dir).max_depth(start_depth); let mut msd_files = Vec::new(); for entry in walk_dir.into_iter() { diff --git a/mps-cli-rs/src/builder/ssolution_builder.rs b/mps-cli-rs/src/builder/ssolution_builder.rs index 3ac92cb..64d9e96 100644 --- a/mps-cli-rs/src/builder/ssolution_builder.rs +++ b/mps-cli-rs/src/builder/ssolution_builder.rs @@ -11,7 +11,7 @@ use crate::model::ssolution::SSolution; use super::smodel_builder_file_per_root_persistency::SModelBuilderCache; -pub fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_builder : &RefCell, model_builder_cache : &RefCell) -> SSolution { +pub(crate) fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_builder : &RefCell, model_builder_cache : &RefCell) -> SSolution { let now = Instant::now(); let path_to_msd_file = path_buf_to_msd_file.to_str().unwrap().to_string(); @@ -54,7 +54,6 @@ fn extract_solution_core_info<'a>(path_to_msd_file: String) -> SSolution { #[cfg(test)] mod tests { - use crate::builder::smodules_repository_builder::find_msd_files; use crate::builder::ssolution_builder::extract_solution_core_info; #[test] @@ -69,25 +68,4 @@ mod tests { assert_eq!(solution.name, "mps.cli.lanuse.library_top"); assert_eq!(solution.uuid, "f1017d72-b2a4-4f19-9b27-1327f37f5b09"); } - - #[test] - fn smoke_test_extract_core_info_for_solutions() { - //given - let path_to_test_project = "../mps_test_projects/mps_cli_lanuse_file_per_root".to_string(); - - use std::time::Instant; - let now = Instant::now(); - //when - let msd_files = find_msd_files(&path_to_test_project, 3); - let mut solutions = vec![]; - for msd_file in &msd_files { - let solution = extract_solution_core_info(msd_file.to_str().unwrap().to_string()); - solutions.push(solution); - } - - //then - println!("Found {} msd files and parsed them in {} solutions in {} ms", msd_files.len(), solutions.len(), now.elapsed().as_millis()); - assert!(msd_files.len() > 1); - assert!(solutions.len() > 1); - } } \ No newline at end of file diff --git a/mps-cli-rs/src/mps_cli_lib.rs b/mps-cli-rs/src/lib.rs similarity index 100% rename from mps-cli-rs/src/mps_cli_lib.rs rename to mps-cli-rs/src/lib.rs diff --git a/mps-cli-rs/src/model/sconcept.rs b/mps-cli-rs/src/model/sconcept.rs index 76ac999..d81eb47 100644 --- a/mps-cli-rs/src/model/sconcept.rs +++ b/mps-cli-rs/src/model/sconcept.rs @@ -41,6 +41,7 @@ impl SConcept { } } + #[allow(dead_code)] pub fn print_concept_details(&self) { let properties_string_vector: Vec = self.properties.borrow().iter().map(|prop| format!("{} {}", prop.0, prop.1.name)).collect(); let properties_info = properties_string_vector.join(", "); From 851a5cb5e57a60d276ab6269ea7a1ea7320c8309 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Wed, 19 Jun 2024 17:12:12 +0200 Subject: [PATCH 25/43] py: improved demo.py modified: mps-cli-py/src/mpscli/demo.py --- mps-cli-py/src/mpscli/demo.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mps-cli-py/src/mpscli/demo.py b/mps-cli-py/src/mpscli/demo.py index 951ad73..3e64eb8 100644 --- a/mps-cli-py/src/mpscli/demo.py +++ b/mps-cli-py/src/mpscli/demo.py @@ -1,6 +1,7 @@ +import sys +sys.path.insert(1, '..') from model.builder.SSolutionsRepositoryBuilder import SSolutionsRepositoryBuilder builder = SSolutionsRepositoryBuilder() -#repo = builder.build('..\\..\\mps_test_projects\\mps_cli_lanuse_file_per_root') -repo = builder.build('..\\..\\..\\..\\E3_2.0_Solution\\solutions') \ No newline at end of file +repo = builder.build('..\\..\\mps_test_projects\\mps_cli_lanuse_file_per_root') \ No newline at end of file From ddb395834085a470678b7a84be578121930ef7cb Mon Sep 17 00:00:00 2001 From: danielratiu Date: Wed, 19 Jun 2024 21:26:07 +0200 Subject: [PATCH 26/43] rs: cleanup --- mps-cli-rs/Cargo.lock | 118 +------------------ mps-cli-rs/src/model/slanguage.rs | 1 - mps-cli-rs/src/model/snoderef.rs | 2 +- mps-cli-rs/src/model/srepository.rs | 5 +- mps-cli-rs/src/model/ssolution.rs | 1 - mps-cli-rs/tests/model_completeness_tests.rs | 9 ++ 6 files changed, 14 insertions(+), 122 deletions(-) diff --git a/mps-cli-rs/Cargo.lock b/mps-cli-rs/Cargo.lock index 28a3b12..44ef65a 100644 --- a/mps-cli-rs/Cargo.lock +++ b/mps-cli-rs/Cargo.lock @@ -3,78 +3,18 @@ version = 3 [[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "getrandom" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "libc" -version = "0.2.153" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" - -[[package]] -name = "memchr" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" - -[[package]] -name = "mps_cli_rs" +name = "mps-cli" version = "0.1.0" dependencies = [ - "quick-xml", "roxmltree", - "serde", - "uuid", "walkdir", ] -[[package]] -name = "proc-macro2" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quick-xml" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - [[package]] name = "roxmltree" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cd14fd5e3b777a7422cca79358c57a8f6e3a703d9ac187448d0daf220c2407f" +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" [[package]] name = "same-file" @@ -85,52 +25,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "serde" -version = "1.0.197" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.197" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "syn" -version = "2.0.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "uuid" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" -dependencies = [ - "getrandom", -] - [[package]] name = "walkdir" version = "2.5.0" @@ -141,12 +35,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - [[package]] name = "winapi" version = "0.3.9" diff --git a/mps-cli-rs/src/model/slanguage.rs b/mps-cli-rs/src/model/slanguage.rs index f2fdf75..f8f90ff 100644 --- a/mps-cli-rs/src/model/slanguage.rs +++ b/mps-cli-rs/src/model/slanguage.rs @@ -2,7 +2,6 @@ use crate::model::sconcept::SConcept; use std::cell::RefCell; use std::rc::Rc; -#[derive(Clone)] pub struct SLanguage { pub name: String, pub id: String, diff --git a/mps-cli-rs/src/model/snoderef.rs b/mps-cli-rs/src/model/snoderef.rs index 5d2975b..224aad6 100644 --- a/mps-cli-rs/src/model/snoderef.rs +++ b/mps-cli-rs/src/model/snoderef.rs @@ -6,7 +6,7 @@ pub struct SNodeRef { pub model_id: String, pub node_id: String, pub resolve_info: String, - referenced_node : Option>, + pub referenced_node : Option>, } impl SNodeRef { diff --git a/mps-cli-rs/src/model/srepository.rs b/mps-cli-rs/src/model/srepository.rs index 11635ee..3fdecc9 100644 --- a/mps-cli-rs/src/model/srepository.rs +++ b/mps-cli-rs/src/model/srepository.rs @@ -1,15 +1,12 @@ use crate::model::slanguage::SLanguage; use crate::model::smodel::SModel; -use crate::model::snode::SNode; use crate::model::ssolution::SSolution; -use std::borrow::Borrow; -use std::ops::Deref; use std::rc::Rc; use std::cell::RefCell; pub struct SRepository { pub solutions: RefCell>>, - languages: RefCell>>, + pub languages: RefCell>>, } impl SRepository { diff --git a/mps-cli-rs/src/model/ssolution.rs b/mps-cli-rs/src/model/ssolution.rs index 1c8ee42..663565c 100644 --- a/mps-cli-rs/src/model/ssolution.rs +++ b/mps-cli-rs/src/model/ssolution.rs @@ -19,7 +19,6 @@ impl SSolution { } } - #[allow(dead_code)] pub fn find_model(&self, name : &str) -> Option>> { let model = self.models.iter().find(|m| m.borrow().name == name); if let Some(model) = model { diff --git a/mps-cli-rs/tests/model_completeness_tests.rs b/mps-cli-rs/tests/model_completeness_tests.rs index 10e7a28..88cd2c4 100644 --- a/mps-cli-rs/tests/model_completeness_tests.rs +++ b/mps-cli-rs/tests/model_completeness_tests.rs @@ -42,4 +42,13 @@ pub (crate) fn check_model_completeness(repo : &SRepository) { // library_second_solution let library_second_solution = repo.find_solution_by_name("mps.cli.lanuse.library_second").unwrap(); assert_eq!(library_second_solution.models.len(), 1); + + // languages + let languages = repo.languages.borrow(); + assert_eq!(languages.len(), 3); + assert!(languages.iter().find(|l| l.name.eq("mps.cli.landefs.library")).is_some()); + let people_lan = languages.iter().find(|l| l.name.eq("mps.cli.landefs.people")); + assert!(people_lan.is_some()); + assert_eq!(people_lan.unwrap().id, "a7aaae55-aa5e-4a05-b2d0-013745658efa"); + assert!(languages.iter().find(|l| l.name.eq("jetbrains.mps.lang.core")).is_some()); } \ No newline at end of file From a175afea5aced239c2a1aa2abece6efd4d3b3d91 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Wed, 19 Jun 2024 21:46:51 +0200 Subject: [PATCH 27/43] github: initial workflow for rust --- .github/workflows/mps_cli_rs_build.yaml | 27 +++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/mps_cli_rs_build.yaml diff --git a/.github/workflows/mps_cli_rs_build.yaml b/.github/workflows/mps_cli_rs_build.yaml new file mode 100644 index 0000000..95738d0 --- /dev/null +++ b/.github/workflows/mps_cli_rs_build.yaml @@ -0,0 +1,27 @@ +name: MPS-CLI-RS_CI + +on: + push: + branches: + - 'main' + pull_request: + workflow_dispatch: + +env: + GITHUB_TOKEN: ${{ secrets.MPSCLI_GITHUB_PKG_REGISTRY }} + +jobs: + build_mps_cli_py: + runs-on: ubuntu-latest + env: + DISPLAY: ':99' + + steps: + - uses: actions/checkout@v3 + - name: setup toolchain + uses: hecrj/setup-rust-action@v1 + with: + rust-version: stable + + - name: cargo test + run: cargo test \ No newline at end of file From 8cbfb2ed7390fe5eeaef6996caa047e78651500d Mon Sep 17 00:00:00 2001 From: danielratiu Date: Tue, 23 Jul 2024 07:25:56 +0200 Subject: [PATCH 28/43] rs: simplified SNode struct --- ...model_builder_file_per_root_persistency.rs | 26 ++++++++------ mps-cli-rs/src/model/snode.rs | 34 +++++++++---------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index 3e9ed82..6411d6e 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -238,15 +238,8 @@ impl SModelBuilderFilePerRootPersistency { }, None => None, }; - let current_node : Rc = Rc::new(SNode::new(node_id.to_string(), Rc::clone(my_concept), role_human_readable)); + let mut current_node = SNode::new(node_id.to_string(), Rc::clone(my_concept), role_human_readable); - if let Some(parent) = parent_node { - let index_2_containment_link = model_builder_cache.index_2_containment_link.borrow(); - let cl = index_2_containment_link.get(&role.unwrap()); - parent.borrow_mut().add_child(Rc::clone(cl.unwrap()), Rc::clone(¤t_node)); - current_node.set_parent(Rc::clone(parent)); - }; - let properties = node.children().filter(|it| it.tag_name().name() == "property"); for property in properties { let role = property.attributes().find(|a| a.name() == "role").unwrap().value(); @@ -292,12 +285,25 @@ impl SModelBuilderFilePerRootPersistency { current_node.add_reference(reference_link, model_id, node_id, resolve); }; + let current_node_rc : Rc; + + if let Some(parent) = parent_node { + let index_2_containment_link = model_builder_cache.index_2_containment_link.borrow(); + let cl = index_2_containment_link.get(&role.unwrap()); + current_node.set_parent(Rc::clone(parent)); + current_node_rc = Rc::new(current_node); + parent.borrow_mut().add_child(Rc::clone(cl.unwrap()), Rc::clone(¤t_node_rc)); + } else { + current_node_rc = Rc::new(current_node); + }; + let nodes = node.children().filter(|it| it.tag_name().name() == "node"); for node in nodes { - Self::parse_node(&mut Some(Rc::clone(¤t_node)), &node, language_builder, model_builder_cache); + Self::parse_node(&mut Some(Rc::clone(¤t_node_rc)), &node, language_builder, model_builder_cache); }; - Rc::clone(¤t_node) + + Rc::clone(¤t_node_rc) } diff --git a/mps-cli-rs/src/model/snode.rs b/mps-cli-rs/src/model/snode.rs index 1116a85..e3d1293 100644 --- a/mps-cli-rs/src/model/snode.rs +++ b/mps-cli-rs/src/model/snode.rs @@ -9,10 +9,10 @@ pub struct SNode { pub id: String, pub concept: Rc, pub role_in_parent: Option, - properties: RefCell, String>>, + properties: HashMap, String>, children: RefCell, Vec>>>, - references: RefCell, Rc>>, - pub parent: RefCell>>, + references: HashMap, Rc>, + pub parent: Option>, } impl SNode { @@ -21,33 +21,31 @@ impl SNode { id, concept, role_in_parent, - properties: RefCell::new(HashMap::new()), + properties: HashMap::new(), children: RefCell::new(HashMap::new()), - references: RefCell::new(HashMap::new()), - parent: RefCell::new(None), + references: HashMap::new(), + parent: None, } } - pub fn add_property(&self, property: &Rc, value: String) { - self.properties.borrow_mut().insert(Rc::clone(property), value); + pub fn add_property(&mut self, property: &Rc, value: String) { + self.properties.insert(Rc::clone(property), value); } - pub fn get_property(&self, property_name: &str) -> Option { - let properties = self.properties.borrow(); - let entry = properties.iter().find(|it| it.0.name.eq(property_name)); + pub fn get_property(&self, property_name: &str) -> Option { + let entry = self.properties.iter().find(|it| it.0.name.eq(property_name)); return match entry { Some(key_val) => { Some(String::clone(key_val.1)) } None => None } } - pub fn add_reference(&self, reference_link: &Rc, model_id : String, node_id : String, resolve : Option) { - self.references.borrow_mut().insert(Rc::clone(reference_link), Rc::new(SNodeRef::new(model_id, node_id, resolve.unwrap_or("".to_string())))); + pub fn add_reference(&mut self, reference_link: &Rc, model_id : String, node_id : String, resolve : Option) { + self.references.insert(Rc::clone(reference_link), Rc::new(SNodeRef::new(model_id, node_id, resolve.unwrap_or("".to_string())))); } - pub fn get_reference(&self, ref_role_name: &str) -> Option> { - let references = self.references.borrow(); - let entry = references.iter().find(|it| it.0.name.eq(ref_role_name)); + pub fn get_reference(&self, ref_role_name: &str) -> Option> { + let entry = self.references.iter().find(|it| it.0.name.eq(ref_role_name)); match entry { Some(e) => Some(e.1.clone()), None => None @@ -69,8 +67,8 @@ impl SNode { } } - pub fn set_parent(&self, parent : Rc) { - self.parent.replace(Some(parent)); + pub fn set_parent(&mut self, parent : Rc) { + self.parent = Some(parent); } pub fn get_descendants(node : Rc, include_self: bool) -> Vec> { From b0dd4ffc6c07113d9ee10e833e761cd6a89ab3ac Mon Sep 17 00:00:00 2001 From: danielratiu Date: Tue, 23 Jul 2024 07:51:43 +0200 Subject: [PATCH 29/43] rs: simplified slanguage_builder --- mps-cli-rs/src/builder/slanguage_builder.rs | 20 +++++++++---------- ...model_builder_file_per_root_persistency.rs | 11 +++++----- .../builder/smodules_repository_builder.rs | 10 +++++----- mps-cli-rs/src/builder/ssolution_builder.rs | 2 +- 4 files changed, 20 insertions(+), 23 deletions(-) diff --git a/mps-cli-rs/src/builder/slanguage_builder.rs b/mps-cli-rs/src/builder/slanguage_builder.rs index 7064469..2f15260 100644 --- a/mps-cli-rs/src/builder/slanguage_builder.rs +++ b/mps-cli-rs/src/builder/slanguage_builder.rs @@ -7,27 +7,25 @@ use crate::model::slanguage::SLanguage; pub(crate) struct SLanguageBuilder { - pub language_id_to_slanguage: RefCell>>, - pub concept_id_to_concept : RefCell>>, + pub language_id_to_slanguage: HashMap>, + pub concept_id_to_concept : HashMap>, } impl<'a> SLanguageBuilder { pub(crate) fn new() -> Self { SLanguageBuilder { - language_id_to_slanguage: RefCell::new(HashMap::new()), - concept_id_to_concept: RefCell::new(HashMap::new()), + language_id_to_slanguage: HashMap::new(), + concept_id_to_concept: HashMap::new(), } } - pub(crate) fn get_or_build_language(&self, language_id: &String, language_name: &String) -> Rc { - let mut l = self.language_id_to_slanguage.borrow_mut(); - let res = l.entry(language_id.to_string()).or_insert_with(|| Rc::new(SLanguage::new(language_name.to_string(), language_id.to_string()))); + pub(crate) fn get_or_build_language(&mut self, language_id: &String, language_name: &String) -> Rc { + let res = self.language_id_to_slanguage.entry(language_id.to_string()).or_insert_with(|| Rc::new(SLanguage::new(language_name.to_string(), language_id.to_string()))); Rc::clone(res) } - pub(crate) fn get_or_create_concept(&'a self, language: Rc, concept_id: &str, concept_name: &str) -> Rc { - let mut concept_id_to_concept = self.concept_id_to_concept.borrow_mut(); - let concept = concept_id_to_concept.get(concept_id); + pub(crate) fn get_or_create_concept(&mut self, language: Rc, concept_id: &str, concept_name: &str) -> Rc { + let concept = self.concept_id_to_concept.get(concept_id); if let Some(c) = concept { return Rc::clone(c); } @@ -35,7 +33,7 @@ impl<'a> SLanguageBuilder { let mut concepts = language.concepts.borrow_mut(); let concept = SConcept::new(concept_name.to_string(), concept_id.to_string()); let rc = Rc::new(concept); - concept_id_to_concept.insert(concept_id.to_string(), rc.clone()); + self.concept_id_to_concept.insert(concept_id.to_string(), rc.clone()); concepts.push(rc.clone()); rc } diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index 6411d6e..9121ed2 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -55,7 +55,7 @@ pub struct SModelBuilderFilePerRootPersistency {} impl SModelBuilderFilePerRootPersistency { - pub(crate) fn build_model<'a>(path_to_model: PathBuf, language_builder : &RefCell, model_builder_cache : &RefCell) -> Rc> { + pub(crate) fn build_model<'a>(path_to_model: PathBuf, language_builder : &mut SLanguageBuilder, model_builder_cache : &RefCell) -> Rc> { let mut model_file = path_to_model.clone(); model_file.push(".model"); let model: Rc> = Self::extract_model_core_info(model_file, model_builder_cache); @@ -133,7 +133,7 @@ impl SModelBuilderFilePerRootPersistency { my_model.clone() } - fn build_root_node_from_file<'a>(dir_entry: DirEntry, language_builder : &RefCell, model_builder_cache : &RefCell) -> Option> { + fn build_root_node_from_file<'a>(dir_entry: DirEntry, language_builder : &mut SLanguageBuilder, model_builder_cache : &RefCell) -> Option> { let file = std::fs::File::open(dir_entry.path().as_os_str()); let mut s = String::new(); @@ -142,11 +142,11 @@ impl SModelBuilderFilePerRootPersistency { let document = parse_res.unwrap(); Self::parse_imports(&document, &model_builder_cache); - Self::parse_registry(&document, &language_builder, &model_builder_cache); + Self::parse_registry(&document, language_builder, &model_builder_cache); let node = document.root_element().children().find(|it| it.tag_name().name() == "node"); let mut parent: Option> = None; - Some(Self::parse_node(&mut parent, &node.unwrap(), &(language_builder.borrow()), &(model_builder_cache.borrow()))) + Some(Self::parse_node(&mut parent, &node.unwrap(), language_builder, &(model_builder_cache.borrow()))) } fn parse_imports(document: &Document, model_builder_cache : &RefCell) { @@ -170,8 +170,7 @@ impl SModelBuilderFilePerRootPersistency { } } - fn parse_registry<'a>(document: &Document, language_builder : &RefCell, model_builder_cache : &RefCell) { - let language_builder = language_builder.borrow(); + fn parse_registry<'a>(document: &Document, language_builder : &mut SLanguageBuilder, model_builder_cache : &RefCell) { let model_builder_cache = model_builder_cache.borrow(); let model_element = document.root_element(); let registry_element = model_element.children().find(|c| c.tag_name().name() == "registry"); diff --git a/mps-cli-rs/src/builder/smodules_repository_builder.rs b/mps-cli-rs/src/builder/smodules_repository_builder.rs index 48b6a8f..bf1a220 100644 --- a/mps-cli-rs/src/builder/smodules_repository_builder.rs +++ b/mps-cli-rs/src/builder/smodules_repository_builder.rs @@ -14,23 +14,23 @@ use crate::model::slanguage::SLanguage; pub(crate) fn build_repo_from_directory<'a>(source_dir: String) -> SRepository { let mut all_solutions : Vec> = Vec::new(); - let language_builder = RefCell::new(SLanguageBuilder::new()); + let mut language_builder = SLanguageBuilder::new(); - build_solutions_from(source_dir, &language_builder, & mut all_solutions); + build_solutions_from(source_dir, &mut language_builder, & mut all_solutions); let mut languages: Vec> = Vec::new(); - language_builder.borrow().language_id_to_slanguage.borrow().values().for_each(|v| languages.push(Rc::clone(v))); + language_builder.language_id_to_slanguage.values().for_each(|v| languages.push(Rc::clone(v))); SRepository::new(all_solutions, languages) } -fn build_solutions_from<'a>(source_dir: String, language_builder : &RefCell, solutions : &'a mut Vec>) { +fn build_solutions_from<'a>(source_dir: String, language_builder : &mut SLanguageBuilder, solutions : &'a mut Vec>) { let now = Instant::now(); collect_modules_from_sources(source_dir.clone(), language_builder, solutions); let elapsed = now.elapsed(); println!("{} milli seconds for handling {}", elapsed.as_millis(), source_dir); } -fn collect_modules_from_sources<'a>(source_dir: String, language_builder : &RefCell, solutions : &'a mut Vec>) { +fn collect_modules_from_sources<'a>(source_dir: String, language_builder : &mut SLanguageBuilder, solutions : &'a mut Vec>) { let model_builder_cache = RefCell::new(SModelBuilderCache::new()); let msd_files = find_msd_files(&source_dir, 3); diff --git a/mps-cli-rs/src/builder/ssolution_builder.rs b/mps-cli-rs/src/builder/ssolution_builder.rs index 64d9e96..b8c6813 100644 --- a/mps-cli-rs/src/builder/ssolution_builder.rs +++ b/mps-cli-rs/src/builder/ssolution_builder.rs @@ -11,7 +11,7 @@ use crate::model::ssolution::SSolution; use super::smodel_builder_file_per_root_persistency::SModelBuilderCache; -pub(crate) fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_builder : &RefCell, model_builder_cache : &RefCell) -> SSolution { +pub(crate) fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_builder : &mut SLanguageBuilder, model_builder_cache : &RefCell) -> SSolution { let now = Instant::now(); let path_to_msd_file = path_buf_to_msd_file.to_str().unwrap().to_string(); From 14a41cb3e23c38d6804fd4e40ff49dc809f56543 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Tue, 23 Jul 2024 08:08:23 +0200 Subject: [PATCH 30/43] rs: simplified smodel builder --- mps-cli-rs/src/builder/slanguage_builder.rs | 1 - ...model_builder_file_per_root_persistency.rs | 80 +++++++++---------- .../builder/smodules_repository_builder.rs | 4 +- mps-cli-rs/src/builder/ssolution_builder.rs | 2 +- 4 files changed, 41 insertions(+), 46 deletions(-) diff --git a/mps-cli-rs/src/builder/slanguage_builder.rs b/mps-cli-rs/src/builder/slanguage_builder.rs index 2f15260..ec27c72 100644 --- a/mps-cli-rs/src/builder/slanguage_builder.rs +++ b/mps-cli-rs/src/builder/slanguage_builder.rs @@ -1,4 +1,3 @@ -use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index 9121ed2..a1448f4 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -16,35 +16,34 @@ use super::slanguage_builder::SLanguageBuilder; #[derive(Clone)] pub struct SModelBuilderCache { - pub index_2_concept: RefCell>>, - pub index_2_property: RefCell>>, - pub index_2_containment_link: RefCell>>, - pub index_2_reference_link: RefCell>>, - pub index_2_imported_model_uuid: RefCell>, - pub index_2_model : RefCell>>>, - pub current_model : RefCell>>>, + pub index_2_concept: HashMap>, + pub index_2_property: HashMap>, + pub index_2_containment_link: HashMap>, + pub index_2_reference_link: HashMap>, + pub index_2_imported_model_uuid: HashMap, + pub index_2_model : HashMap>>, + pub current_model : Option>>, } impl SModelBuilderCache { pub(crate) fn new() -> Self { SModelBuilderCache { - index_2_concept : RefCell::new(HashMap::new()), - index_2_property : RefCell::new(HashMap::new()), - index_2_containment_link : RefCell::new(HashMap::new()), - index_2_reference_link : RefCell::new(HashMap::new()), - index_2_imported_model_uuid : RefCell::new(HashMap::new()), - index_2_model : RefCell::new(HashMap::new()), - current_model : RefCell::new(None), + index_2_concept : HashMap::new(), + index_2_property : HashMap::new(), + index_2_containment_link : HashMap::new(), + index_2_reference_link : HashMap::new(), + index_2_imported_model_uuid : HashMap::new(), + index_2_model : HashMap::new(), + current_model : None, } } - fn get_model(&self, name : String, uuid : String) -> Rc> { - let mut i2m = self.index_2_model.borrow_mut(); - if let Some(model) = i2m.get(&uuid) { + fn get_model(&mut self, name : String, uuid : String) -> Rc> { + if let Some(model) = self.index_2_model.get(&uuid) { Rc::clone(&model) } else { let temp = Rc::new(RefCell::new(SModel::new(name.clone(), uuid.clone()))); - i2m.insert(uuid, temp.clone()); + self.index_2_model.insert(uuid, temp.clone()); temp.clone() } } @@ -55,11 +54,11 @@ pub struct SModelBuilderFilePerRootPersistency {} impl SModelBuilderFilePerRootPersistency { - pub(crate) fn build_model<'a>(path_to_model: PathBuf, language_builder : &mut SLanguageBuilder, model_builder_cache : &RefCell) -> Rc> { + pub(crate) fn build_model<'a>(path_to_model: PathBuf, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> Rc> { let mut model_file = path_to_model.clone(); model_file.push(".model"); let model: Rc> = Self::extract_model_core_info(model_file, model_builder_cache); - model_builder_cache.borrow_mut().current_model.replace(Some(Rc::clone(&model))); + model_builder_cache.current_model = Some(Rc::clone(&model)); let mpsr_file_walker = WalkDir::new(path_to_model).min_depth(1).max_depth(1); let mpsr_files = mpsr_file_walker.into_iter().filter(|entry| { @@ -83,7 +82,7 @@ impl SModelBuilderFilePerRootPersistency { return model; } - fn extract_model_core_info<'a>(path_to_model: PathBuf, model_builder_cache : &RefCell) -> Rc> { + fn extract_model_core_info<'a>(path_to_model: PathBuf, model_builder_cache : &mut SModelBuilderCache) -> Rc> { let path_to_model_file = path_to_model.to_str().unwrap().to_string(); let file = std::fs::File::open(path_to_model_file.clone()); @@ -110,8 +109,7 @@ impl SModelBuilderFilePerRootPersistency { let do_not_generate_str = do_not_generate_attribute.attributes().find(|aa| aa.name() == "value").unwrap().value(); if do_not_generate_str == "true" { is_do_not_generate = true; } } - - let model_builder_cache = model_builder_cache.borrow(); + let my_model = model_builder_cache.get_model(name, uuid); my_model.as_ref().borrow_mut().path_to_model_file = path_to_model_file; my_model.as_ref().borrow_mut().is_do_not_generate = is_do_not_generate; @@ -133,7 +131,7 @@ impl SModelBuilderFilePerRootPersistency { my_model.clone() } - fn build_root_node_from_file<'a>(dir_entry: DirEntry, language_builder : &mut SLanguageBuilder, model_builder_cache : &RefCell) -> Option> { + fn build_root_node_from_file<'a>(dir_entry: DirEntry, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> Option> { let file = std::fs::File::open(dir_entry.path().as_os_str()); let mut s = String::new(); @@ -141,16 +139,15 @@ impl SModelBuilderFilePerRootPersistency { let parse_res = roxmltree::Document::parse(&s); let document = parse_res.unwrap(); - Self::parse_imports(&document, &model_builder_cache); - Self::parse_registry(&document, language_builder, &model_builder_cache); + Self::parse_imports(&document, model_builder_cache); + Self::parse_registry(&document, language_builder, model_builder_cache); let node = document.root_element().children().find(|it| it.tag_name().name() == "node"); let mut parent: Option> = None; - Some(Self::parse_node(&mut parent, &node.unwrap(), language_builder, &(model_builder_cache.borrow()))) + Some(Self::parse_node(&mut parent, &node.unwrap(), language_builder, model_builder_cache)) } - fn parse_imports(document: &Document, model_builder_cache : &RefCell) { - let model_builder_cache = model_builder_cache.borrow(); + fn parse_imports(document: &Document, model_builder_cache : &mut SModelBuilderCache) { let model_element = document.root_element(); let imports_element = model_element.children().find(|c| c.tag_name().name() == "imports"); match imports_element { @@ -162,7 +159,7 @@ impl SModelBuilderFilePerRootPersistency { let uuid = import.attributes().find(|a| a.name() == "ref").unwrap().value(); let uuid = uuid.to_string()[0..uuid.find('(').unwrap()].to_string(); - model_builder_cache.index_2_imported_model_uuid.borrow_mut().insert(index.to_string(), uuid); + model_builder_cache.index_2_imported_model_uuid.insert(index.to_string(), uuid); } } }, @@ -170,8 +167,7 @@ impl SModelBuilderFilePerRootPersistency { } } - fn parse_registry<'a>(document: &Document, language_builder : &mut SLanguageBuilder, model_builder_cache : &RefCell) { - let model_builder_cache = model_builder_cache.borrow(); + fn parse_registry<'a>(document: &Document, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) { let model_element = document.root_element(); let registry_element = model_element.children().find(|c| c.tag_name().name() == "registry"); match registry_element { @@ -219,19 +215,19 @@ impl SModelBuilderFilePerRootPersistency { } - fn parse_node<'a>(parent_node : &mut Option>, node: &Node, language_builder : &SLanguageBuilder, model_builder_cache : &SModelBuilderCache) -> Rc { + fn parse_node<'a>(parent_node : &mut Option>, node: &Node, language_builder : &SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> Rc { let node_attrs = node.attributes(); let concept_index = (node_attrs.clone()).into_iter().find(|a| a.name() == "concept").unwrap().value(); let node_id = (node_attrs.clone()).into_iter().find(|a| a.name() == "id").unwrap().value(); let role = (node_attrs.clone()).into_iter().find(|a| a.name() == "role"); let role = if role.is_none() { None } else { Some(role.unwrap().value().to_string()) }; - let index_2_concept = model_builder_cache.index_2_concept.borrow(); + let index_2_concept = &model_builder_cache.index_2_concept; let my_concept = index_2_concept.get(concept_index).unwrap(); let role_human_readable = match role.clone() { Some(role_string) => { - let index_2_containment_link = model_builder_cache.index_2_containment_link.borrow(); + let index_2_containment_link = &model_builder_cache.index_2_containment_link; let r = index_2_containment_link.get(&role_string).unwrap(); Some(String::from(&r.name)) }, @@ -243,7 +239,7 @@ impl SModelBuilderFilePerRootPersistency { for property in properties { let role = property.attributes().find(|a| a.name() == "role").unwrap().value(); let value = property.attributes().find(|a| a.name() == "value").unwrap().value(); - let index_2_properties = model_builder_cache.index_2_property.borrow(); + let index_2_properties = &model_builder_cache.index_2_property; let prop = index_2_properties.get(role).unwrap(); current_node.add_property(prop, value.to_string()); }; @@ -263,18 +259,18 @@ impl SModelBuilderFilePerRootPersistency { None }; - let index_2_reference_links = model_builder_cache.index_2_reference_link.borrow(); + let index_2_reference_links = &model_builder_cache.index_2_reference_link; let reference_link = index_2_reference_links.get(&role.to_string()).unwrap(); let model_id : String; let node_id : String; if let Some(index) = to.find(":") { let model_index = &to[0..index]; - let mm = model_builder_cache.index_2_imported_model_uuid.borrow(); + let mm = &model_builder_cache.index_2_imported_model_uuid; model_id = String::from(mm.get(model_index).unwrap()); node_id = String::from(&to[index + 1..to.len()]); } else { - let crt_model = model_builder_cache.current_model.borrow(); + let crt_model = &model_builder_cache.current_model; let m = crt_model.as_ref().unwrap(); let m = m.as_ref().borrow(); model_id = String::from(m.uuid.as_str()); @@ -287,7 +283,7 @@ impl SModelBuilderFilePerRootPersistency { let current_node_rc : Rc; if let Some(parent) = parent_node { - let index_2_containment_link = model_builder_cache.index_2_containment_link.borrow(); + let index_2_containment_link = &model_builder_cache.index_2_containment_link; let cl = index_2_containment_link.get(&role.unwrap()); current_node.set_parent(Rc::clone(parent)); current_node_rc = Rc::new(current_node); @@ -322,8 +318,8 @@ mod tests { let path_to_model_file = PathBuf::from(path); //when - let model_builder_cache = RefCell::new(SModelBuilderCache::new()); - let temp = SModelBuilderFilePerRootPersistency::extract_model_core_info(path_to_model_file, &model_builder_cache); + let mut model_builder_cache = SModelBuilderCache::new(); + let temp = SModelBuilderFilePerRootPersistency::extract_model_core_info(path_to_model_file, &mut model_builder_cache); let model = temp.borrow(); //assert diff --git a/mps-cli-rs/src/builder/smodules_repository_builder.rs b/mps-cli-rs/src/builder/smodules_repository_builder.rs index bf1a220..8803025 100644 --- a/mps-cli-rs/src/builder/smodules_repository_builder.rs +++ b/mps-cli-rs/src/builder/smodules_repository_builder.rs @@ -31,12 +31,12 @@ fn build_solutions_from<'a>(source_dir: String, language_builder : &mut SLanguag } fn collect_modules_from_sources<'a>(source_dir: String, language_builder : &mut SLanguageBuilder, solutions : &'a mut Vec>) { - let model_builder_cache = RefCell::new(SModelBuilderCache::new()); + let mut model_builder_cache = SModelBuilderCache::new(); let msd_files = find_msd_files(&source_dir, 3); msd_files.iter() .for_each(|msd_file| { - let s = build_solution(msd_file, language_builder, &model_builder_cache); + let s = build_solution(msd_file, language_builder, &mut model_builder_cache); solutions.push(Rc::new(s)); }); } diff --git a/mps-cli-rs/src/builder/ssolution_builder.rs b/mps-cli-rs/src/builder/ssolution_builder.rs index b8c6813..0afa1de 100644 --- a/mps-cli-rs/src/builder/ssolution_builder.rs +++ b/mps-cli-rs/src/builder/ssolution_builder.rs @@ -11,7 +11,7 @@ use crate::model::ssolution::SSolution; use super::smodel_builder_file_per_root_persistency::SModelBuilderCache; -pub(crate) fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_builder : &mut SLanguageBuilder, model_builder_cache : &RefCell) -> SSolution { +pub(crate) fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> SSolution { let now = Instant::now(); let path_to_msd_file = path_buf_to_msd_file.to_str().unwrap().to_string(); From c7a874c827ce1bab7a5514857065b6e461aaa8ae Mon Sep 17 00:00:00 2001 From: danielratiu Date: Tue, 23 Jul 2024 08:14:42 +0200 Subject: [PATCH 31/43] rs: simplified srepository --- .../builder/smodules_repository_builder.rs | 8 ++---- mps-cli-rs/src/builder/ssolution_builder.rs | 1 - mps-cli-rs/src/main.rs | 2 +- mps-cli-rs/src/model/srepository.rs | 28 ++++++++----------- mps-cli-rs/tests/model_completeness_tests.rs | 2 +- 5 files changed, 17 insertions(+), 24 deletions(-) diff --git a/mps-cli-rs/src/builder/smodules_repository_builder.rs b/mps-cli-rs/src/builder/smodules_repository_builder.rs index 8803025..55abe28 100644 --- a/mps-cli-rs/src/builder/smodules_repository_builder.rs +++ b/mps-cli-rs/src/builder/smodules_repository_builder.rs @@ -1,4 +1,3 @@ -use std::cell::RefCell; use std::path::PathBuf; use std::time::Instant; @@ -87,11 +86,10 @@ mod tests { let repository = build_repo_from_directory(src_dir); //then - let required_time = now.elapsed().as_millis(); - let solutions = repository.solutions.borrow(); - let models: Vec<&Rc>> = solutions.iter().flat_map(|solution| &solution.models).collect(); + let required_time = now.elapsed().as_millis(); + let models: Vec<&Rc>> = repository.solutions.iter().flat_map(|solution| &solution.models).collect(); let do_not_gen_models: Vec<&&Rc>> = models.iter().filter(|&model| model.as_ref().borrow().is_do_not_generate).collect(); - let number_of_solutions = repository.solutions.borrow().len(); + let number_of_solutions = repository.solutions.len(); println!("Found {} solutions with {} models (out of which {} are set to do not generate) in {} ms", number_of_solutions, models.len(), do_not_gen_models.len(), required_time); assert_eq!(number_of_solutions, 2); assert_eq!(models.len(), 3); diff --git a/mps-cli-rs/src/builder/ssolution_builder.rs b/mps-cli-rs/src/builder/ssolution_builder.rs index 0afa1de..719893a 100644 --- a/mps-cli-rs/src/builder/ssolution_builder.rs +++ b/mps-cli-rs/src/builder/ssolution_builder.rs @@ -1,4 +1,3 @@ -use std::cell::RefCell; use std::path::PathBuf; use std::time::Instant; diff --git a/mps-cli-rs/src/main.rs b/mps-cli-rs/src/main.rs index 4a2d66c..2eecbff 100644 --- a/mps-cli-rs/src/main.rs +++ b/mps-cli-rs/src/main.rs @@ -5,7 +5,7 @@ use crate::builder::smodules_repository_builder::build_repo_from_directory; fn main() { let repository = build_repo_from_directory(String::from("C:\\work\\E3_2.0_Solution\\solutions")); - println!("number of solutions: {}", repository.solutions.borrow().len()); + println!("number of solutions: {}", repository.solutions.len()); } diff --git a/mps-cli-rs/src/model/srepository.rs b/mps-cli-rs/src/model/srepository.rs index 3fdecc9..34fb430 100644 --- a/mps-cli-rs/src/model/srepository.rs +++ b/mps-cli-rs/src/model/srepository.rs @@ -5,29 +5,27 @@ use std::rc::Rc; use std::cell::RefCell; pub struct SRepository { - pub solutions: RefCell>>, - pub languages: RefCell>>, + pub solutions: Vec>, + pub languages: Vec>, } impl SRepository { pub fn new(solutions: Vec>, languages: Vec>) -> Self { SRepository { - solutions : RefCell::new(solutions), - languages : RefCell::new(languages), + solutions : solutions, + languages : languages, } } #[allow(dead_code)] - pub fn find_solution_by_name(&self, name: &str) -> Option> { - let solutions = self.solutions.borrow(); - let found_solution = solutions.iter().find(|&ssolution| ssolution.name.eq(name)); + pub fn find_solution_by_name(&self, name: &str) -> Option> { + let found_solution = self.solutions.iter().find(|&ssolution| ssolution.name.eq(name)); found_solution.map(|s| Rc::clone(s)) } #[allow(dead_code)] - pub fn find_model_by_name(&self, name: &str) -> Option>> { - let solutions = self.solutions.borrow(); - for s in solutions.iter() { + pub fn find_model_by_name(&self, name: &str) -> Option>> { + for s in self.solutions.iter() { for m in s.models.iter() { if let Ok(model) = m.clone().try_borrow() { println!("model {}", model.name); @@ -40,9 +38,8 @@ impl SRepository { #[allow(dead_code)] pub fn get_all_models(&self) -> Vec>> { - let mut res : Vec>> = Vec::new(); - let solutions = self.solutions.borrow(); - for s in solutions.iter() { + let mut res : Vec>> = Vec::new(); + for s in self.solutions.iter() { for m in s.models.iter() { res.push(Rc::clone(m)); } @@ -51,9 +48,8 @@ impl SRepository { } #[allow(dead_code)] - pub fn get_model_by_uuid(&self, uuid: &str) -> Option>> { - let solutions = self.solutions.borrow(); - for sol in solutions.iter() { + pub fn get_model_by_uuid(&self, uuid: &str) -> Option>> { + for sol in self.solutions.iter() { for m in sol.models.iter() { if (**m).borrow().uuid.eq(uuid) { return Some(Rc::clone(m)); diff --git a/mps-cli-rs/tests/model_completeness_tests.rs b/mps-cli-rs/tests/model_completeness_tests.rs index 88cd2c4..ddeb108 100644 --- a/mps-cli-rs/tests/model_completeness_tests.rs +++ b/mps-cli-rs/tests/model_completeness_tests.rs @@ -44,7 +44,7 @@ pub (crate) fn check_model_completeness(repo : &SRepository) { assert_eq!(library_second_solution.models.len(), 1); // languages - let languages = repo.languages.borrow(); + let languages = &repo.languages; assert_eq!(languages.len(), 3); assert!(languages.iter().find(|l| l.name.eq("mps.cli.landefs.library")).is_some()); let people_lan = languages.iter().find(|l| l.name.eq("mps.cli.landefs.people")); From e714672863448da4441b5b7680d2af5a71dd56ad Mon Sep 17 00:00:00 2001 From: danielratiu Date: Wed, 24 Jul 2024 19:26:39 +0200 Subject: [PATCH 32/43] rs: simplified the code --- mps-cli-rs/src/builder/smodules_repository_builder.rs | 8 ++++---- mps-cli-rs/src/model/srepository.rs | 9 ++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/mps-cli-rs/src/builder/smodules_repository_builder.rs b/mps-cli-rs/src/builder/smodules_repository_builder.rs index 55abe28..9545653 100644 --- a/mps-cli-rs/src/builder/smodules_repository_builder.rs +++ b/mps-cli-rs/src/builder/smodules_repository_builder.rs @@ -12,7 +12,7 @@ use crate::model::ssolution::SSolution; use crate::model::slanguage::SLanguage; pub(crate) fn build_repo_from_directory<'a>(source_dir: String) -> SRepository { - let mut all_solutions : Vec> = Vec::new(); + let mut all_solutions : Vec = Vec::new(); let mut language_builder = SLanguageBuilder::new(); build_solutions_from(source_dir, &mut language_builder, & mut all_solutions); @@ -22,21 +22,21 @@ pub(crate) fn build_repo_from_directory<'a>(source_dir: String) -> SRepository { SRepository::new(all_solutions, languages) } -fn build_solutions_from<'a>(source_dir: String, language_builder : &mut SLanguageBuilder, solutions : &'a mut Vec>) { +fn build_solutions_from<'a>(source_dir: String, language_builder : &mut SLanguageBuilder, solutions : &'a mut Vec) { let now = Instant::now(); collect_modules_from_sources(source_dir.clone(), language_builder, solutions); let elapsed = now.elapsed(); println!("{} milli seconds for handling {}", elapsed.as_millis(), source_dir); } -fn collect_modules_from_sources<'a>(source_dir: String, language_builder : &mut SLanguageBuilder, solutions : &'a mut Vec>) { +fn collect_modules_from_sources<'a>(source_dir: String, language_builder : &mut SLanguageBuilder, solutions : &'a mut Vec) { let mut model_builder_cache = SModelBuilderCache::new(); let msd_files = find_msd_files(&source_dir, 3); msd_files.iter() .for_each(|msd_file| { let s = build_solution(msd_file, language_builder, &mut model_builder_cache); - solutions.push(Rc::new(s)); + solutions.push(s); }); } diff --git a/mps-cli-rs/src/model/srepository.rs b/mps-cli-rs/src/model/srepository.rs index 34fb430..91dcc14 100644 --- a/mps-cli-rs/src/model/srepository.rs +++ b/mps-cli-rs/src/model/srepository.rs @@ -5,12 +5,12 @@ use std::rc::Rc; use std::cell::RefCell; pub struct SRepository { - pub solutions: Vec>, + pub solutions: Vec, pub languages: Vec>, } impl SRepository { - pub fn new(solutions: Vec>, languages: Vec>) -> Self { + pub fn new(solutions: Vec, languages: Vec>) -> Self { SRepository { solutions : solutions, languages : languages, @@ -18,9 +18,8 @@ impl SRepository { } #[allow(dead_code)] - pub fn find_solution_by_name(&self, name: &str) -> Option> { - let found_solution = self.solutions.iter().find(|&ssolution| ssolution.name.eq(name)); - found_solution.map(|s| Rc::clone(s)) + pub fn find_solution_by_name(&self, name: &str) -> Option<&SSolution> { + self.solutions.iter().find(|&ssolution| ssolution.name.eq(name)) } #[allow(dead_code)] From a788f79a3b9a204f2a6e7e51d5a50069f28bc9d4 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Wed, 24 Jul 2024 21:32:03 +0200 Subject: [PATCH 33/43] rs: simplification --- mps-cli-rs/src/builder/slanguage_builder.rs | 21 +++++++++++-------- .../builder/smodules_repository_builder.rs | 3 ++- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/mps-cli-rs/src/builder/slanguage_builder.rs b/mps-cli-rs/src/builder/slanguage_builder.rs index ec27c72..09a7208 100644 --- a/mps-cli-rs/src/builder/slanguage_builder.rs +++ b/mps-cli-rs/src/builder/slanguage_builder.rs @@ -1,3 +1,4 @@ +use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; @@ -6,25 +7,27 @@ use crate::model::slanguage::SLanguage; pub(crate) struct SLanguageBuilder { - pub language_id_to_slanguage: HashMap>, - pub concept_id_to_concept : HashMap>, + pub language_id_to_slanguage: RefCell>>, + pub concept_id_to_concept : RefCell>>, } impl<'a> SLanguageBuilder { pub(crate) fn new() -> Self { SLanguageBuilder { - language_id_to_slanguage: HashMap::new(), - concept_id_to_concept: HashMap::new(), + language_id_to_slanguage: RefCell::new(HashMap::new()), + concept_id_to_concept: RefCell::new(HashMap::new()), } } - pub(crate) fn get_or_build_language(&mut self, language_id: &String, language_name: &String) -> Rc { - let res = self.language_id_to_slanguage.entry(language_id.to_string()).or_insert_with(|| Rc::new(SLanguage::new(language_name.to_string(), language_id.to_string()))); + pub(crate) fn get_or_build_language(&self, language_id: &String, language_name: &String) -> Rc { + let mut language_id_to_slanguage = self.language_id_to_slanguage.borrow_mut(); + let res = language_id_to_slanguage.entry(language_id.to_string()).or_insert_with(|| Rc::new(SLanguage::new(language_name.to_string(), language_id.to_string()))); Rc::clone(res) } - pub(crate) fn get_or_create_concept(&mut self, language: Rc, concept_id: &str, concept_name: &str) -> Rc { - let concept = self.concept_id_to_concept.get(concept_id); + pub(crate) fn get_or_create_concept(&self, language: Rc, concept_id: &str, concept_name: &str) -> Rc { + let mut concept_id_to_concept = self.concept_id_to_concept.borrow_mut(); + let concept = concept_id_to_concept.get(concept_id); if let Some(c) = concept { return Rc::clone(c); } @@ -32,7 +35,7 @@ impl<'a> SLanguageBuilder { let mut concepts = language.concepts.borrow_mut(); let concept = SConcept::new(concept_name.to_string(), concept_id.to_string()); let rc = Rc::new(concept); - self.concept_id_to_concept.insert(concept_id.to_string(), rc.clone()); + concept_id_to_concept.insert(concept_id.to_string(), rc.clone()); concepts.push(rc.clone()); rc } diff --git a/mps-cli-rs/src/builder/smodules_repository_builder.rs b/mps-cli-rs/src/builder/smodules_repository_builder.rs index 9545653..7ed7fb8 100644 --- a/mps-cli-rs/src/builder/smodules_repository_builder.rs +++ b/mps-cli-rs/src/builder/smodules_repository_builder.rs @@ -18,7 +18,8 @@ pub(crate) fn build_repo_from_directory<'a>(source_dir: String) -> SRepository { build_solutions_from(source_dir, &mut language_builder, & mut all_solutions); let mut languages: Vec> = Vec::new(); - language_builder.language_id_to_slanguage.values().for_each(|v| languages.push(Rc::clone(v))); + let slanguages = language_builder.language_id_to_slanguage.into_inner(); + slanguages.values().for_each(|v| languages.push(Rc::clone(v))); SRepository::new(all_solutions, languages) } From 0af376152378dbdfc306cda62883343f4bdf8f1f Mon Sep 17 00:00:00 2001 From: danielratiu Date: Fri, 26 Jul 2024 19:17:44 +0200 Subject: [PATCH 34/43] rs: simplification --- mps-cli-rs/src/builder/slanguage_builder.rs | 13 ++++--------- ...smodel_builder_file_per_root_persistency.rs | 16 +++++++++------- .../src/builder/smodules_repository_builder.rs | 18 +++++++++--------- mps-cli-rs/src/builder/ssolution_builder.rs | 6 ++++-- mps-cli-rs/src/model/srepository.rs | 4 ++-- 5 files changed, 28 insertions(+), 29 deletions(-) diff --git a/mps-cli-rs/src/builder/slanguage_builder.rs b/mps-cli-rs/src/builder/slanguage_builder.rs index 09a7208..4fb2a99 100644 --- a/mps-cli-rs/src/builder/slanguage_builder.rs +++ b/mps-cli-rs/src/builder/slanguage_builder.rs @@ -7,25 +7,17 @@ use crate::model::slanguage::SLanguage; pub(crate) struct SLanguageBuilder { - pub language_id_to_slanguage: RefCell>>, pub concept_id_to_concept : RefCell>>, } impl<'a> SLanguageBuilder { pub(crate) fn new() -> Self { SLanguageBuilder { - language_id_to_slanguage: RefCell::new(HashMap::new()), concept_id_to_concept: RefCell::new(HashMap::new()), } } - pub(crate) fn get_or_build_language(&self, language_id: &String, language_name: &String) -> Rc { - let mut language_id_to_slanguage = self.language_id_to_slanguage.borrow_mut(); - let res = language_id_to_slanguage.entry(language_id.to_string()).or_insert_with(|| Rc::new(SLanguage::new(language_name.to_string(), language_id.to_string()))); - Rc::clone(res) - } - - pub(crate) fn get_or_create_concept(&self, language: Rc, concept_id: &str, concept_name: &str) -> Rc { + pub(crate) fn get_or_create_concept(&self, language: &mut SLanguage, concept_id: &str, concept_name: &str) -> Rc { let mut concept_id_to_concept = self.concept_id_to_concept.borrow_mut(); let concept = concept_id_to_concept.get(concept_id); if let Some(c) = concept { @@ -65,3 +57,6 @@ impl<'a> SLanguageBuilder { +pub(crate) fn get_or_build_language<'a>(language_id: &String, language_name: &String, language_id_to_slanguage: &'a mut HashMap) -> &'a mut SLanguage { + language_id_to_slanguage.entry(language_id.to_string()).or_insert_with(|| SLanguage::new(language_name.to_string(), language_id.to_string())) +} \ No newline at end of file diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index a1448f4..aff0780 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -9,9 +9,11 @@ use std::cell::RefCell; use walkdir::{DirEntry, WalkDir}; use crate::model::sconcept::{SConcept, SContainmentLink, SProperty, SReferenceLink}; +use crate::model::slanguage::SLanguage; use crate::model::smodel::SModel; use crate::model::snode::SNode; use super::slanguage_builder::SLanguageBuilder; +use super::slanguage_builder::get_or_build_language; #[derive(Clone)] @@ -54,7 +56,7 @@ pub struct SModelBuilderFilePerRootPersistency {} impl SModelBuilderFilePerRootPersistency { - pub(crate) fn build_model<'a>(path_to_model: PathBuf, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> Rc> { + pub(crate) fn build_model<'a>(path_to_model: PathBuf, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> Rc> { let mut model_file = path_to_model.clone(); model_file.push(".model"); let model: Rc> = Self::extract_model_core_info(model_file, model_builder_cache); @@ -73,7 +75,7 @@ impl SModelBuilderFilePerRootPersistency { let mut roots = vec!(); for mpsr_file in mpsr_files.into_iter() { let file = mpsr_file.unwrap(); - if let Some(r) = Self::build_root_node_from_file(file, language_builder, model_builder_cache) { + if let Some(r) = Self::build_root_node_from_file(file, language_id_to_slanguage, language_builder, model_builder_cache) { roots.push(r); } }; @@ -131,7 +133,7 @@ impl SModelBuilderFilePerRootPersistency { my_model.clone() } - fn build_root_node_from_file<'a>(dir_entry: DirEntry, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> Option> { + fn build_root_node_from_file<'a>(dir_entry: DirEntry, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> Option> { let file = std::fs::File::open(dir_entry.path().as_os_str()); let mut s = String::new(); @@ -140,7 +142,7 @@ impl SModelBuilderFilePerRootPersistency { let document = parse_res.unwrap(); Self::parse_imports(&document, model_builder_cache); - Self::parse_registry(&document, language_builder, model_builder_cache); + Self::parse_registry(&document, language_id_to_slanguage, language_builder, model_builder_cache); let node = document.root_element().children().find(|it| it.tag_name().name() == "node"); let mut parent: Option> = None; @@ -167,7 +169,7 @@ impl SModelBuilderFilePerRootPersistency { } } - fn parse_registry<'a>(document: &Document, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) { + fn parse_registry<'a>(document: &Document, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) { let model_element = document.root_element(); let registry_element = model_element.children().find(|c| c.tag_name().name() == "registry"); match registry_element { @@ -178,14 +180,14 @@ impl SModelBuilderFilePerRootPersistency { let language_id = language.attributes().find(|a| a.name() == "id").unwrap().value(); let language_name = language.attributes().find(|a| a.name() == "name").unwrap().value(); - let lang = language_builder.get_or_build_language(&language_id.to_string(), &language_name.to_string()); + let lang = get_or_build_language(&language_id.to_string(), &language_name.to_string(), language_id_to_slanguage); for concept in language.children() { if concept.tag_name().name() != "concept" { continue; } let concept_id = concept.attributes().find(|a| a.name() == "id").unwrap().value(); let concept_name = concept.attributes().find(|a| a.name() == "name").unwrap().value(); let concept_index = concept.attributes().find(|a| a.name() == "index").unwrap().value(); - let conc = language_builder.get_or_create_concept(Rc::clone(&lang), concept_id, concept_name); + let conc = language_builder.get_or_create_concept(lang, concept_id, concept_name); model_builder_cache.index_2_concept.borrow_mut().insert(concept_index.to_string(), Rc::clone(&conc)); for properties_links_references in concept.children() { diff --git a/mps-cli-rs/src/builder/smodules_repository_builder.rs b/mps-cli-rs/src/builder/smodules_repository_builder.rs index 7ed7fb8..1305bad 100644 --- a/mps-cli-rs/src/builder/smodules_repository_builder.rs +++ b/mps-cli-rs/src/builder/smodules_repository_builder.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::path::PathBuf; use std::time::Instant; @@ -14,29 +15,28 @@ use crate::model::slanguage::SLanguage; pub(crate) fn build_repo_from_directory<'a>(source_dir: String) -> SRepository { let mut all_solutions : Vec = Vec::new(); let mut language_builder = SLanguageBuilder::new(); + let mut language_id_to_slanguage : HashMap = HashMap::new(); - build_solutions_from(source_dir, &mut language_builder, & mut all_solutions); + build_solutions_from(source_dir, &mut language_id_to_slanguage, &mut language_builder, & mut all_solutions); - let mut languages: Vec> = Vec::new(); - let slanguages = language_builder.language_id_to_slanguage.into_inner(); - slanguages.values().for_each(|v| languages.push(Rc::clone(v))); - SRepository::new(all_solutions, languages) + let all_languages = language_id_to_slanguage.into_iter().map(|(_k, lan)| lan).collect(); + SRepository::new(all_solutions, all_languages) } -fn build_solutions_from<'a>(source_dir: String, language_builder : &mut SLanguageBuilder, solutions : &'a mut Vec) { +fn build_solutions_from<'a>(source_dir: String, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, solutions : &'a mut Vec) { let now = Instant::now(); - collect_modules_from_sources(source_dir.clone(), language_builder, solutions); + collect_modules_from_sources(source_dir.clone(), language_id_to_slanguage, language_builder, solutions); let elapsed = now.elapsed(); println!("{} milli seconds for handling {}", elapsed.as_millis(), source_dir); } -fn collect_modules_from_sources<'a>(source_dir: String, language_builder : &mut SLanguageBuilder, solutions : &'a mut Vec) { +fn collect_modules_from_sources<'a>(source_dir: String, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, solutions : &'a mut Vec) { let mut model_builder_cache = SModelBuilderCache::new(); let msd_files = find_msd_files(&source_dir, 3); msd_files.iter() .for_each(|msd_file| { - let s = build_solution(msd_file, language_builder, &mut model_builder_cache); + let s = build_solution(msd_file, language_id_to_slanguage, language_builder, &mut model_builder_cache); solutions.push(s); }); } diff --git a/mps-cli-rs/src/builder/ssolution_builder.rs b/mps-cli-rs/src/builder/ssolution_builder.rs index 719893a..a98fbf6 100644 --- a/mps-cli-rs/src/builder/ssolution_builder.rs +++ b/mps-cli-rs/src/builder/ssolution_builder.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::path::PathBuf; use std::time::Instant; @@ -6,11 +7,12 @@ use walkdir::WalkDir; use crate::builder::smodel_builder_file_per_root_persistency::SModelBuilderFilePerRootPersistency; use crate::builder::slanguage_builder::SLanguageBuilder; +use crate::model::slanguage::SLanguage; use crate::model::ssolution::SSolution; use super::smodel_builder_file_per_root_persistency::SModelBuilderCache; -pub(crate) fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> SSolution { +pub(crate) fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> SSolution { let now = Instant::now(); let path_to_msd_file = path_buf_to_msd_file.to_str().unwrap().to_string(); @@ -23,7 +25,7 @@ pub(crate) fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_builde for model_entry in model_dir.into_iter() { let path = model_entry.unwrap().into_path(); if path.is_dir() { - let model = SModelBuilderFilePerRootPersistency::build_model(path, language_builder, model_builder_cache); + let model = SModelBuilderFilePerRootPersistency::build_model(path, language_id_to_slanguage, language_builder, model_builder_cache); models.push(model) } else { println!("ERROR: model entry {} is a file not a directory. Cannot be parsed as only file per root persistency is supported.", path.to_str().unwrap().to_string()) diff --git a/mps-cli-rs/src/model/srepository.rs b/mps-cli-rs/src/model/srepository.rs index 91dcc14..cb1bc8e 100644 --- a/mps-cli-rs/src/model/srepository.rs +++ b/mps-cli-rs/src/model/srepository.rs @@ -6,11 +6,11 @@ use std::cell::RefCell; pub struct SRepository { pub solutions: Vec, - pub languages: Vec>, + pub languages: Vec, } impl SRepository { - pub fn new(solutions: Vec, languages: Vec>) -> Self { + pub fn new(solutions: Vec, languages: Vec) -> Self { SRepository { solutions : solutions, languages : languages, From 5ab3fd8f2790870f0595c864210624034fb3fdbc Mon Sep 17 00:00:00 2001 From: danielratiu Date: Sat, 27 Jul 2024 02:32:33 +0200 Subject: [PATCH 35/43] rs: simplify the code --- mps-cli-rs/src/builder/slanguage_builder.rs | 3 +-- mps-cli-rs/src/model/slanguage.rs | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/mps-cli-rs/src/builder/slanguage_builder.rs b/mps-cli-rs/src/builder/slanguage_builder.rs index 4fb2a99..6b50c4a 100644 --- a/mps-cli-rs/src/builder/slanguage_builder.rs +++ b/mps-cli-rs/src/builder/slanguage_builder.rs @@ -24,11 +24,10 @@ impl<'a> SLanguageBuilder { return Rc::clone(c); } - let mut concepts = language.concepts.borrow_mut(); let concept = SConcept::new(concept_name.to_string(), concept_id.to_string()); let rc = Rc::new(concept); concept_id_to_concept.insert(concept_id.to_string(), rc.clone()); - concepts.push(rc.clone()); + language.concepts.push(rc.clone()); rc } diff --git a/mps-cli-rs/src/model/slanguage.rs b/mps-cli-rs/src/model/slanguage.rs index f8f90ff..2549a69 100644 --- a/mps-cli-rs/src/model/slanguage.rs +++ b/mps-cli-rs/src/model/slanguage.rs @@ -5,7 +5,7 @@ use std::rc::Rc; pub struct SLanguage { pub name: String, pub id: String, - pub concepts: RefCell>>, + pub concepts: Vec>, } impl SLanguage { @@ -13,7 +13,7 @@ impl SLanguage { SLanguage { name, id, - concepts: RefCell::new(vec![]), + concepts: vec![], } } } From 8638a37e541db7085597fc29870259e04b4a954f Mon Sep 17 00:00:00 2001 From: danielratiu Date: Sat, 27 Jul 2024 02:56:47 +0200 Subject: [PATCH 36/43] rs: cleanup --- mps-cli-rs/src/model/slanguage.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/mps-cli-rs/src/model/slanguage.rs b/mps-cli-rs/src/model/slanguage.rs index 2549a69..92cf695 100644 --- a/mps-cli-rs/src/model/slanguage.rs +++ b/mps-cli-rs/src/model/slanguage.rs @@ -1,5 +1,4 @@ use crate::model::sconcept::SConcept; -use std::cell::RefCell; use std::rc::Rc; pub struct SLanguage { From e16d4bd42670e483925116c50ec027ac2521488e Mon Sep 17 00:00:00 2001 From: danielratiu Date: Sun, 28 Jul 2024 08:21:40 +0200 Subject: [PATCH 37/43] rs: cleanup --- mps-cli-rs/src/builder/node_id_utils.rs | 18 +- mps-cli-rs/src/builder/slanguage_builder.rs | 4 - ...model_builder_file_per_root_persistency.rs | 430 +++++++++--------- .../builder/smodules_repository_builder.rs | 2 - mps-cli-rs/src/builder/ssolution_builder.rs | 6 +- mps-cli-rs/src/model/sconcept.rs | 8 +- 6 files changed, 225 insertions(+), 243 deletions(-) diff --git a/mps-cli-rs/src/builder/node_id_utils.rs b/mps-cli-rs/src/builder/node_id_utils.rs index 2c04256..b7cdfc5 100644 --- a/mps-cli-rs/src/builder/node_id_utils.rs +++ b/mps-cli-rs/src/builder/node_id_utils.rs @@ -1,29 +1,27 @@ use std::collections::HashMap; - struct NodeIdEncodingUtils { - myIndexChars : String, + my_index_chars : String, min_char : u8, - myCharToValue : HashMap, - + my_char_to_value : HashMap, } impl NodeIdEncodingUtils { pub(crate) fn new() -> Self { let my_index_chars = String::from("0123456789abcdefghijklmnopqrstuvwxyz$_ABCDEFGHIJKLMNOPQRSTUVWXYZ"); let min_char = '$' as u8; - let mut myCharToValue : HashMap = HashMap::new(); + let mut my_char_to_value : HashMap = HashMap::new(); let bytes = my_index_chars.as_bytes(); for i in 0..my_index_chars.len() { let char_value = bytes[i] as u8; let ii: usize = (char_value - min_char) as usize; - myCharToValue.insert(ii, i); + my_char_to_value.insert(ii, i); } NodeIdEncodingUtils { - myIndexChars : my_index_chars, + my_index_chars : my_index_chars, min_char : min_char, - myCharToValue : myCharToValue, + my_char_to_value : my_char_to_value, } } @@ -32,12 +30,12 @@ impl NodeIdEncodingUtils { let bytes = uid_string.as_bytes(); let mut c = bytes[0]; let ii : usize = (c as u8 - self.min_char) as usize; - let mut value = self.myCharToValue[&ii]; + let mut value = self.my_char_to_value[&ii]; res = value; for idx in 1..uid_string.len() { res = res << 6; c = bytes[idx]; - value = self.myIndexChars.find(c as char).unwrap(); + value = self.my_index_chars.find(c as char).unwrap(); res = res | value; } return res.to_string(); diff --git a/mps-cli-rs/src/builder/slanguage_builder.rs b/mps-cli-rs/src/builder/slanguage_builder.rs index 6b50c4a..a47252d 100644 --- a/mps-cli-rs/src/builder/slanguage_builder.rs +++ b/mps-cli-rs/src/builder/slanguage_builder.rs @@ -52,10 +52,6 @@ impl<'a> SLanguageBuilder { } - - - - pub(crate) fn get_or_build_language<'a>(language_id: &String, language_name: &String, language_id_to_slanguage: &'a mut HashMap) -> &'a mut SLanguage { language_id_to_slanguage.entry(language_id.to_string()).or_insert_with(|| SLanguage::new(language_name.to_string(), language_id.to_string())) } \ No newline at end of file diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index aff0780..14a65ff 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -52,266 +52,258 @@ impl SModelBuilderCache { } -pub struct SModelBuilderFilePerRootPersistency {} - -impl SModelBuilderFilePerRootPersistency { - - pub(crate) fn build_model<'a>(path_to_model: PathBuf, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> Rc> { - let mut model_file = path_to_model.clone(); - model_file.push(".model"); - let model: Rc> = Self::extract_model_core_info(model_file, model_builder_cache); - model_builder_cache.current_model = Some(Rc::clone(&model)); - - let mpsr_file_walker = WalkDir::new(path_to_model).min_depth(1).max_depth(1); - let mpsr_files = mpsr_file_walker.into_iter().filter(|entry| { - if entry.is_ok() { - let dir_entry = entry.as_ref().unwrap(); - let extension = dir_entry.path().extension(); - return dir_entry.file_type().is_file() && extension.is_some_and(|e| e.eq("mpsr")); - } - return false; - }); - - let mut roots = vec!(); - for mpsr_file in mpsr_files.into_iter() { - let file = mpsr_file.unwrap(); - if let Some(r) = Self::build_root_node_from_file(file, language_id_to_slanguage, language_builder, model_builder_cache) { - roots.push(r); - } - }; - model.as_ref().borrow_mut().root_nodes.extend(roots); +pub(crate) fn build_model<'a>(path_to_model: PathBuf, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> Rc> { + let mut model_file = path_to_model.clone(); + model_file.push(".model"); + let model: Rc> = extract_model_core_info(model_file, model_builder_cache); + model_builder_cache.current_model = Some(Rc::clone(&model)); + + let mpsr_file_walker = WalkDir::new(path_to_model).min_depth(1).max_depth(1); + let mpsr_files = mpsr_file_walker.into_iter().filter(|entry| { + if entry.is_ok() { + let dir_entry = entry.as_ref().unwrap(); + let extension = dir_entry.path().extension(); + return dir_entry.file_type().is_file() && extension.is_some_and(|e| e.eq("mpsr")); + } + return false; + }); + + let mut roots = vec!(); + for mpsr_file in mpsr_files.into_iter() { + let file = mpsr_file.unwrap(); + if let Some(r) = build_root_node_from_file(file, language_id_to_slanguage, language_builder, model_builder_cache) { + roots.push(r); + } + }; + model.as_ref().borrow_mut().root_nodes.extend(roots); - return model; - } + return model; +} - fn extract_model_core_info<'a>(path_to_model: PathBuf, model_builder_cache : &mut SModelBuilderCache) -> Rc> { - let path_to_model_file = path_to_model.to_str().unwrap().to_string(); +fn extract_model_core_info<'a>(path_to_model: PathBuf, model_builder_cache : &mut SModelBuilderCache) -> Rc> { + let path_to_model_file = path_to_model.to_str().unwrap().to_string(); - let file = std::fs::File::open(path_to_model_file.clone()); - if file.is_err() { - panic!("file not found '{}'", path_to_model_file); - } - let mut s = String::new(); - let _ = file.unwrap().read_to_string(&mut s); - let parse_res = roxmltree::Document::parse(&s); - let document = parse_res.unwrap(); - - let model_element = document.root_element(); - let uuid_and_name = model_element.attributes().find(|a| a.name() == "ref").unwrap().value().to_string(); - - let left_parens_pos = uuid_and_name.find('(').unwrap(); - let right_parens_pos = uuid_and_name.find(')').unwrap(); - let uuid = uuid_and_name[0..left_parens_pos].to_string(); - let name = uuid_and_name[left_parens_pos + 1..right_parens_pos].to_string(); - - let mut is_do_not_generate = false; - let model_attributes_elements = model_element.children().filter(|c| (c.tag_name().name().to_string() == "attribute")); - let do_not_generate_attribute = (model_attributes_elements.clone()).find(|a| a.attributes().find(|aa| aa.value() == "doNotGenerate").is_some()); - if let Some(do_not_generate_attribute) = do_not_generate_attribute { - let do_not_generate_str = do_not_generate_attribute.attributes().find(|aa| aa.name() == "value").unwrap().value(); - if do_not_generate_str == "true" { is_do_not_generate = true; } - } + let file = std::fs::File::open(path_to_model_file.clone()); + if file.is_err() { + panic!("file not found '{}'", path_to_model_file); + } + let mut s = String::new(); + let _ = file.unwrap().read_to_string(&mut s); + let parse_res = roxmltree::Document::parse(&s); + let document = parse_res.unwrap(); + + let model_element = document.root_element(); + let uuid_and_name = model_element.attributes().find(|a| a.name() == "ref").unwrap().value().to_string(); + + let left_parens_pos = uuid_and_name.find('(').unwrap(); + let right_parens_pos = uuid_and_name.find(')').unwrap(); + let uuid = uuid_and_name[0..left_parens_pos].to_string(); + let name = uuid_and_name[left_parens_pos + 1..right_parens_pos].to_string(); + + let mut is_do_not_generate = false; + let model_attributes_elements = model_element.children().filter(|c| (c.tag_name().name().to_string() == "attribute")); + let do_not_generate_attribute = (model_attributes_elements.clone()).find(|a| a.attributes().find(|aa| aa.value() == "doNotGenerate").is_some()); + if let Some(do_not_generate_attribute) = do_not_generate_attribute { + let do_not_generate_str = do_not_generate_attribute.attributes().find(|aa| aa.name() == "value").unwrap().value(); + if do_not_generate_str == "true" { is_do_not_generate = true; } + } - let my_model = model_builder_cache.get_model(name, uuid); - my_model.as_ref().borrow_mut().path_to_model_file = path_to_model_file; - my_model.as_ref().borrow_mut().is_do_not_generate = is_do_not_generate; - my_model.as_ref().borrow_mut().is_file_per_root_persistency = true; - - let imports = model_element.children().find(|c| c.tag_name().name() == "imports").unwrap(); - for import in imports.children() { - let tag_name = import.tag_name(); - if tag_name.name() == "import" { - let uuid_att = import.attributes().find(|a| a.name() == "ref").unwrap().value(); - - let uuid = uuid_att.to_string()[0..uuid_att.find('(').unwrap()].to_string(); - let name = uuid_att.to_string()[uuid_att.find('(').unwrap()+1..uuid_att.find(')').unwrap()].to_string(); - let imported_model = model_builder_cache.get_model(name, uuid); - my_model.as_ref().borrow_mut().imported_models.push(imported_model.clone()); - } + let my_model = model_builder_cache.get_model(name, uuid); + my_model.as_ref().borrow_mut().path_to_model_file = path_to_model_file; + my_model.as_ref().borrow_mut().is_do_not_generate = is_do_not_generate; + my_model.as_ref().borrow_mut().is_file_per_root_persistency = true; + + let imports = model_element.children().find(|c| c.tag_name().name() == "imports").unwrap(); + for import in imports.children() { + let tag_name = import.tag_name(); + if tag_name.name() == "import" { + let uuid_att = import.attributes().find(|a| a.name() == "ref").unwrap().value(); + + let uuid = uuid_att.to_string()[0..uuid_att.find('(').unwrap()].to_string(); + let name = uuid_att.to_string()[uuid_att.find('(').unwrap()+1..uuid_att.find(')').unwrap()].to_string(); + let imported_model = model_builder_cache.get_model(name, uuid); + my_model.as_ref().borrow_mut().imported_models.push(imported_model.clone()); } - - my_model.clone() } - fn build_root_node_from_file<'a>(dir_entry: DirEntry, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> Option> { - let file = std::fs::File::open(dir_entry.path().as_os_str()); + my_model.clone() +} - let mut s = String::new(); - let _ = file.unwrap().read_to_string(&mut s); - let parse_res = roxmltree::Document::parse(&s); +fn build_root_node_from_file<'a>(dir_entry: DirEntry, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> Option> { + let file = std::fs::File::open(dir_entry.path().as_os_str()); + + let mut s = String::new(); + let _ = file.unwrap().read_to_string(&mut s); + let parse_res = roxmltree::Document::parse(&s); - let document = parse_res.unwrap(); - Self::parse_imports(&document, model_builder_cache); - Self::parse_registry(&document, language_id_to_slanguage, language_builder, model_builder_cache); + let document = parse_res.unwrap(); + parse_imports(&document, model_builder_cache); + parse_registry(&document, language_id_to_slanguage, language_builder, model_builder_cache); - let node = document.root_element().children().find(|it| it.tag_name().name() == "node"); - let mut parent: Option> = None; - Some(Self::parse_node(&mut parent, &node.unwrap(), language_builder, model_builder_cache)) - } + let node = document.root_element().children().find(|it| it.tag_name().name() == "node"); + let mut parent: Option> = None; + Some(parse_node(&mut parent, &node.unwrap(), language_builder, model_builder_cache)) +} - fn parse_imports(document: &Document, model_builder_cache : &mut SModelBuilderCache) { - let model_element = document.root_element(); - let imports_element = model_element.children().find(|c| c.tag_name().name() == "imports"); - match imports_element { - Some(imports) => { - for import in imports.children() { - let tag_name = import.tag_name(); - if tag_name.name() == "import" { - let index = import.attributes().find(|a| a.name() == "index").unwrap().value(); - let uuid = import.attributes().find(|a| a.name() == "ref").unwrap().value(); - - let uuid = uuid.to_string()[0..uuid.find('(').unwrap()].to_string(); - model_builder_cache.index_2_imported_model_uuid.insert(index.to_string(), uuid); - } +fn parse_imports(document: &Document, model_builder_cache : &mut SModelBuilderCache) { + let model_element = document.root_element(); + let imports_element = model_element.children().find(|c| c.tag_name().name() == "imports"); + match imports_element { + Some(imports) => { + for import in imports.children() { + let tag_name = import.tag_name(); + if tag_name.name() == "import" { + let index = import.attributes().find(|a| a.name() == "index").unwrap().value(); + let uuid = import.attributes().find(|a| a.name() == "ref").unwrap().value(); + + let uuid = uuid.to_string()[0..uuid.find('(').unwrap()].to_string(); + model_builder_cache.index_2_imported_model_uuid.insert(index.to_string(), uuid); } - }, - _ => () - } + } + }, + _ => () } +} - fn parse_registry<'a>(document: &Document, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) { - let model_element = document.root_element(); - let registry_element = model_element.children().find(|c| c.tag_name().name() == "registry"); - match registry_element { - Some(registry) => { - for language in registry.children() { - if language.tag_name().name() != "language" { continue; } +fn parse_registry<'a>(document: &Document, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) { + let model_element = document.root_element(); + let registry_element = model_element.children().find(|c| c.tag_name().name() == "registry"); + match registry_element { + Some(registry) => { + for language in registry.children() { + if language.tag_name().name() != "language" { continue; } - let language_id = language.attributes().find(|a| a.name() == "id").unwrap().value(); - let language_name = language.attributes().find(|a| a.name() == "name").unwrap().value(); + let language_id = language.attributes().find(|a| a.name() == "id").unwrap().value(); + let language_name = language.attributes().find(|a| a.name() == "name").unwrap().value(); - let lang = get_or_build_language(&language_id.to_string(), &language_name.to_string(), language_id_to_slanguage); - for concept in language.children() { - if concept.tag_name().name() != "concept" { continue; } + let lang = get_or_build_language(&language_id.to_string(), &language_name.to_string(), language_id_to_slanguage); + for concept in language.children() { + if concept.tag_name().name() != "concept" { continue; } - let concept_id = concept.attributes().find(|a| a.name() == "id").unwrap().value(); - let concept_name = concept.attributes().find(|a| a.name() == "name").unwrap().value(); - let concept_index = concept.attributes().find(|a| a.name() == "index").unwrap().value(); - let conc = language_builder.get_or_create_concept(lang, concept_id, concept_name); - model_builder_cache.index_2_concept.borrow_mut().insert(concept_index.to_string(), Rc::clone(&conc)); + let concept_id = concept.attributes().find(|a| a.name() == "id").unwrap().value(); + let concept_name = concept.attributes().find(|a| a.name() == "name").unwrap().value(); + let concept_index = concept.attributes().find(|a| a.name() == "index").unwrap().value(); + let conc = language_builder.get_or_create_concept(lang, concept_id, concept_name); + model_builder_cache.index_2_concept.borrow_mut().insert(concept_index.to_string(), Rc::clone(&conc)); - for properties_links_references in concept.children() { - if properties_links_references.tag_name().name() == "" { continue; } + for properties_links_references in concept.children() { + if properties_links_references.tag_name().name() == "" { continue; } - let tag_name = properties_links_references.tag_name().name(); - let id = properties_links_references.attributes().find(|a| a.name() == "id").unwrap().value(); - let name = properties_links_references.attributes().find(|a| a.name() == "name").unwrap().value(); - let index = properties_links_references.attributes().find(|a| a.name() == "index").unwrap().value(); + let tag_name = properties_links_references.tag_name().name(); + let id = properties_links_references.attributes().find(|a| a.name() == "id").unwrap().value(); + let name = properties_links_references.attributes().find(|a| a.name() == "name").unwrap().value(); + let index = properties_links_references.attributes().find(|a| a.name() == "index").unwrap().value(); - if tag_name == "property" { - let prop = language_builder.get_or_create_property(Rc::clone(&conc),id.to_string(), name.to_string()); - model_builder_cache.index_2_property.borrow_mut().insert(index.to_string(), Rc::clone(&prop)); - } else if tag_name == "child" { - let child_link = language_builder.get_or_create_child(Rc::clone(&conc),id.to_string(), name.to_string()); - model_builder_cache.index_2_containment_link.borrow_mut().insert(index.to_string(), Rc::clone(&child_link)); - } else if tag_name == "reference" { - let ref_link = language_builder.get_or_create_reference(Rc::clone(&conc),id.to_string(), name.to_string()); - model_builder_cache.index_2_reference_link.borrow_mut().insert(index.to_string(), Rc::clone(&ref_link)); - } - } - } - }; - }, - _ => () - } + if tag_name == "property" { + let prop = language_builder.get_or_create_property(Rc::clone(&conc),id.to_string(), name.to_string()); + model_builder_cache.index_2_property.borrow_mut().insert(index.to_string(), Rc::clone(&prop)); + } else if tag_name == "child" { + let child_link = language_builder.get_or_create_child(Rc::clone(&conc),id.to_string(), name.to_string()); + model_builder_cache.index_2_containment_link.borrow_mut().insert(index.to_string(), Rc::clone(&child_link)); + } else if tag_name == "reference" { + let ref_link = language_builder.get_or_create_reference(Rc::clone(&conc),id.to_string(), name.to_string()); + model_builder_cache.index_2_reference_link.borrow_mut().insert(index.to_string(), Rc::clone(&ref_link)); + } + } + } + }; + }, + _ => () } +} - fn parse_node<'a>(parent_node : &mut Option>, node: &Node, language_builder : &SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> Rc { - let node_attrs = node.attributes(); - let concept_index = (node_attrs.clone()).into_iter().find(|a| a.name() == "concept").unwrap().value(); - let node_id = (node_attrs.clone()).into_iter().find(|a| a.name() == "id").unwrap().value(); - let role = (node_attrs.clone()).into_iter().find(|a| a.name() == "role"); - let role = if role.is_none() { None } else { Some(role.unwrap().value().to_string()) }; +fn parse_node<'a>(parent_node : &mut Option>, node: &Node, language_builder : &SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> Rc { + let node_attrs = node.attributes(); + let concept_index = (node_attrs.clone()).into_iter().find(|a| a.name() == "concept").unwrap().value(); + let node_id = (node_attrs.clone()).into_iter().find(|a| a.name() == "id").unwrap().value(); + let role = (node_attrs.clone()).into_iter().find(|a| a.name() == "role"); + let role = if role.is_none() { None } else { Some(role.unwrap().value().to_string()) }; - let index_2_concept = &model_builder_cache.index_2_concept; + let index_2_concept = &model_builder_cache.index_2_concept; - let my_concept = index_2_concept.get(concept_index).unwrap(); - let role_human_readable = match role.clone() { - Some(role_string) => { - let index_2_containment_link = &model_builder_cache.index_2_containment_link; - let r = index_2_containment_link.get(&role_string).unwrap(); - Some(String::from(&r.name)) - }, - None => None, - }; - let mut current_node = SNode::new(node_id.to_string(), Rc::clone(my_concept), role_human_readable); + let my_concept = index_2_concept.get(concept_index).unwrap(); + let role_human_readable = match role.clone() { + Some(role_string) => { + let index_2_containment_link = &model_builder_cache.index_2_containment_link; + let r = index_2_containment_link.get(&role_string).unwrap(); + Some(String::from(&r.name)) + }, + None => None, + }; + let mut current_node = SNode::new(node_id.to_string(), Rc::clone(my_concept), role_human_readable); - let properties = node.children().filter(|it| it.tag_name().name() == "property"); - for property in properties { - let role = property.attributes().find(|a| a.name() == "role").unwrap().value(); - let value = property.attributes().find(|a| a.name() == "value").unwrap().value(); - let index_2_properties = &model_builder_cache.index_2_property; - let prop = index_2_properties.get(role).unwrap(); - current_node.add_property(prop, value.to_string()); + let properties = node.children().filter(|it| it.tag_name().name() == "property"); + for property in properties { + let role = property.attributes().find(|a| a.name() == "role").unwrap().value(); + let value = property.attributes().find(|a| a.name() == "value").unwrap().value(); + let index_2_properties = &model_builder_cache.index_2_property; + let prop = index_2_properties.get(role).unwrap(); + current_node.add_property(prop, value.to_string()); + }; + + let refs = node.children().filter(|it| it.tag_name().name() == "ref"); + for ref_ in refs { + let role = ref_.attributes().find(|a| a.name() == "role").unwrap().value(); + let to = ref_.attributes().find(|a| a.name() == "to"); + let to: &str = if let Some(t) = to { + t.value() + } else { + ref_.attributes().find(|a| a.name() == "node").unwrap().value() }; - - let refs = node.children().filter(|it| it.tag_name().name() == "ref"); - for ref_ in refs { - let role = ref_.attributes().find(|a| a.name() == "role").unwrap().value(); - let to = ref_.attributes().find(|a| a.name() == "to"); - let to: &str = if let Some(t) = to { - t.value() - } else { - ref_.attributes().find(|a| a.name() == "node").unwrap().value() - }; - let resolve = if let Some(r) = ref_.attributes().find(|a| a.name() == "resolve") { - Some(String::from(r.value())) - } else { - None - }; - - let index_2_reference_links = &model_builder_cache.index_2_reference_link; - let reference_link = index_2_reference_links.get(&role.to_string()).unwrap(); - - let model_id : String; - let node_id : String; - if let Some(index) = to.find(":") { - let model_index = &to[0..index]; - let mm = &model_builder_cache.index_2_imported_model_uuid; - model_id = String::from(mm.get(model_index).unwrap()); - node_id = String::from(&to[index + 1..to.len()]); - } else { - let crt_model = &model_builder_cache.current_model; - let m = crt_model.as_ref().unwrap(); - let m = m.as_ref().borrow(); - model_id = String::from(m.uuid.as_str()); - node_id = String::from(to); - }; - - current_node.add_reference(reference_link, model_id, node_id, resolve); + let resolve = if let Some(r) = ref_.attributes().find(|a| a.name() == "resolve") { + Some(String::from(r.value())) + } else { + None }; - let current_node_rc : Rc; - - if let Some(parent) = parent_node { - let index_2_containment_link = &model_builder_cache.index_2_containment_link; - let cl = index_2_containment_link.get(&role.unwrap()); - current_node.set_parent(Rc::clone(parent)); - current_node_rc = Rc::new(current_node); - parent.borrow_mut().add_child(Rc::clone(cl.unwrap()), Rc::clone(¤t_node_rc)); + let index_2_reference_links = &model_builder_cache.index_2_reference_link; + let reference_link = index_2_reference_links.get(&role.to_string()).unwrap(); + + let model_id : String; + let node_id : String; + if let Some(index) = to.find(":") { + let model_index = &to[0..index]; + let mm = &model_builder_cache.index_2_imported_model_uuid; + model_id = String::from(mm.get(model_index).unwrap()); + node_id = String::from(&to[index + 1..to.len()]); } else { - current_node_rc = Rc::new(current_node); + let crt_model = &model_builder_cache.current_model; + let m = crt_model.as_ref().unwrap(); + let m = m.as_ref().borrow(); + model_id = String::from(m.uuid.as_str()); + node_id = String::from(to); }; - let nodes = node.children().filter(|it| it.tag_name().name() == "node"); - for node in nodes { - Self::parse_node(&mut Some(Rc::clone(¤t_node_rc)), &node, language_builder, model_builder_cache); - }; + current_node.add_reference(reference_link, model_id, node_id, resolve); + }; + let current_node_rc : Rc; - Rc::clone(¤t_node_rc) - } + if let Some(parent) = parent_node { + let index_2_containment_link = &model_builder_cache.index_2_containment_link; + let cl = index_2_containment_link.get(&role.unwrap()); + current_node.set_parent(Rc::clone(parent)); + current_node_rc = Rc::new(current_node); + parent.borrow_mut().add_child(Rc::clone(cl.unwrap()), Rc::clone(¤t_node_rc)); + } else { + current_node_rc = Rc::new(current_node); + }; + let nodes = node.children().filter(|it| it.tag_name().name() == "node"); + for node in nodes { + parse_node(&mut Some(Rc::clone(¤t_node_rc)), &node, language_builder, model_builder_cache); + }; + Rc::clone(¤t_node_rc) } + #[cfg(test)] mod tests { - use std::cell::RefCell; use std::path::PathBuf; - use crate::builder::smodel_builder_file_per_root_persistency::{SModelBuilderCache, SModelBuilderFilePerRootPersistency}; + use crate::builder::smodel_builder_file_per_root_persistency::{SModelBuilderCache, extract_model_core_info}; #[test] fn test_model_extract_core_info() { @@ -321,7 +313,7 @@ mod tests { //when let mut model_builder_cache = SModelBuilderCache::new(); - let temp = SModelBuilderFilePerRootPersistency::extract_model_core_info(path_to_model_file, &mut model_builder_cache); + let temp = extract_model_core_info(path_to_model_file, &mut model_builder_cache); let model = temp.borrow(); //assert diff --git a/mps-cli-rs/src/builder/smodules_repository_builder.rs b/mps-cli-rs/src/builder/smodules_repository_builder.rs index 1305bad..301691e 100644 --- a/mps-cli-rs/src/builder/smodules_repository_builder.rs +++ b/mps-cli-rs/src/builder/smodules_repository_builder.rs @@ -3,7 +3,6 @@ use std::path::PathBuf; use std::time::Instant; use walkdir::WalkDir; -use std::rc::Rc; use crate::builder::slanguage_builder::SLanguageBuilder; use crate::builder::smodel_builder_file_per_root_persistency::SModelBuilderCache; @@ -97,7 +96,6 @@ mod tests { assert_eq!(do_not_gen_models.len(), 1); assert!(repository.find_solution_by_name("mps.cli.lanuse.library_top").is_some()); - //assert!(repository.get_model_by_uuid("r:ec5f093b-9d83-43a1-9b41-b5952da8b1ed").is_some()); } diff --git a/mps-cli-rs/src/builder/ssolution_builder.rs b/mps-cli-rs/src/builder/ssolution_builder.rs index a98fbf6..5f6608d 100644 --- a/mps-cli-rs/src/builder/ssolution_builder.rs +++ b/mps-cli-rs/src/builder/ssolution_builder.rs @@ -5,7 +5,7 @@ use std::time::Instant; use std::io::Read; use walkdir::WalkDir; -use crate::builder::smodel_builder_file_per_root_persistency::SModelBuilderFilePerRootPersistency; +use crate::builder::smodel_builder_file_per_root_persistency::build_model; use crate::builder::slanguage_builder::SLanguageBuilder; use crate::model::slanguage::SLanguage; use crate::model::ssolution::SSolution; @@ -25,7 +25,7 @@ pub(crate) fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_id_to_ for model_entry in model_dir.into_iter() { let path = model_entry.unwrap().into_path(); if path.is_dir() { - let model = SModelBuilderFilePerRootPersistency::build_model(path, language_id_to_slanguage, language_builder, model_builder_cache); + let model = build_model(path, language_id_to_slanguage, language_builder, model_builder_cache); models.push(model) } else { println!("ERROR: model entry {} is a file not a directory. Cannot be parsed as only file per root persistency is supported.", path.to_str().unwrap().to_string()) @@ -39,8 +39,6 @@ pub(crate) fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_id_to_ } fn extract_solution_core_info<'a>(path_to_msd_file: String) -> SSolution { - //let solution_file = SolutionFile::new(&path_to_msd_file); - let file = std::fs::File::open(path_to_msd_file.clone()); let mut s = String::new(); let _ = file.unwrap().read_to_string(&mut s); diff --git a/mps-cli-rs/src/model/sconcept.rs b/mps-cli-rs/src/model/sconcept.rs index d81eb47..a0891a6 100644 --- a/mps-cli-rs/src/model/sconcept.rs +++ b/mps-cli-rs/src/model/sconcept.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use std::cell::RefCell; use std::rc::Rc; -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq)] pub struct SConcept { pub name: String, pub id: String, @@ -12,19 +12,19 @@ pub struct SConcept { pub reference_links: RefCell>>, } -#[derive(PartialEq, Eq, Hash, Debug, Clone)] +#[derive(PartialEq, Eq, Hash, Debug)] pub struct SProperty { pub(crate) name: String, pub id: String, } -#[derive(PartialEq, Eq, Hash, Debug, Clone)] +#[derive(PartialEq, Eq, Hash, Debug)] pub struct SContainmentLink { pub(crate) name: String, id: String, } -#[derive(PartialEq, Eq, Hash, Debug, Clone)] +#[derive(PartialEq, Eq, Hash, Debug)] pub struct SReferenceLink { pub(crate) name: String, id: String, From 544bd23907e0c9fca74d6ddb22e154f0ce70ea40 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Sun, 28 Jul 2024 08:37:27 +0200 Subject: [PATCH 38/43] rs: extract common functionality for building models in smodel_builder_base --- mps-cli-rs/src/builder/mod.rs | 1 + mps-cli-rs/src/builder/smodel_builder_base.rs | 78 +++++++++++++++++++ ...model_builder_file_per_root_persistency.rs | 76 +----------------- .../builder/smodules_repository_builder.rs | 2 +- mps-cli-rs/src/builder/ssolution_builder.rs | 2 +- 5 files changed, 85 insertions(+), 74 deletions(-) create mode 100644 mps-cli-rs/src/builder/smodel_builder_base.rs diff --git a/mps-cli-rs/src/builder/mod.rs b/mps-cli-rs/src/builder/mod.rs index 25c2ff9..e14512d 100644 --- a/mps-cli-rs/src/builder/mod.rs +++ b/mps-cli-rs/src/builder/mod.rs @@ -1,5 +1,6 @@ pub(crate) mod smodules_repository_builder; mod ssolution_builder; +mod smodel_builder_base; mod smodel_builder_file_per_root_persistency; mod slanguage_builder; mod node_id_utils; diff --git a/mps-cli-rs/src/builder/smodel_builder_base.rs b/mps-cli-rs/src/builder/smodel_builder_base.rs new file mode 100644 index 0000000..6b087b3 --- /dev/null +++ b/mps-cli-rs/src/builder/smodel_builder_base.rs @@ -0,0 +1,78 @@ +use std::collections::HashMap; +use std::{cell::RefCell, rc::Rc}; +use roxmltree::Document; + +use crate::model::smodel::SModel; +use crate::model::sconcept::{SConcept, SContainmentLink, SProperty, SReferenceLink}; + +pub(crate) struct SModelBuilderCache { + pub index_2_concept: HashMap>, + pub index_2_property: HashMap>, + pub index_2_containment_link: HashMap>, + pub index_2_reference_link: HashMap>, + pub index_2_imported_model_uuid: HashMap, + pub index_2_model : HashMap>>, + pub current_model : Option>>, +} + +impl SModelBuilderCache { + pub(crate) fn new() -> Self { + SModelBuilderCache { + index_2_concept : HashMap::new(), + index_2_property : HashMap::new(), + index_2_containment_link : HashMap::new(), + index_2_reference_link : HashMap::new(), + index_2_imported_model_uuid : HashMap::new(), + index_2_model : HashMap::new(), + current_model : None, + } + } + + fn get_model(&mut self, name : String, uuid : String) -> Rc> { + if let Some(model) = self.index_2_model.get(&uuid) { + Rc::clone(&model) + } else { + let temp = Rc::new(RefCell::new(SModel::new(name.clone(), uuid.clone()))); + self.index_2_model.insert(uuid, temp.clone()); + temp.clone() + } + } +} + +pub(crate) fn do_extract_model_core_info(document: Document, model_builder_cache: &mut SModelBuilderCache, path_to_model_file: String) -> Rc> { + let model_element = document.root_element(); + let uuid_and_name = model_element.attributes().find(|a| a.name() == "ref").unwrap().value().to_string(); + + let left_parens_pos = uuid_and_name.find('(').unwrap(); + let right_parens_pos = uuid_and_name.find(')').unwrap(); + let uuid = uuid_and_name[0..left_parens_pos].to_string(); + let name = uuid_and_name[left_parens_pos + 1..right_parens_pos].to_string(); + + let mut is_do_not_generate = false; + let model_attributes_elements = model_element.children().filter(|c| (c.tag_name().name().to_string() == "attribute")); + let do_not_generate_attribute = (model_attributes_elements.clone()).find(|a| a.attributes().find(|aa| aa.value() == "doNotGenerate").is_some()); + if let Some(do_not_generate_attribute) = do_not_generate_attribute { + let do_not_generate_str = do_not_generate_attribute.attributes().find(|aa| aa.name() == "value").unwrap().value(); + if do_not_generate_str == "true" { is_do_not_generate = true; } + } + + let my_model = model_builder_cache.get_model(name, uuid); + my_model.as_ref().borrow_mut().path_to_model_file = path_to_model_file; + my_model.as_ref().borrow_mut().is_do_not_generate = is_do_not_generate; + my_model.as_ref().borrow_mut().is_file_per_root_persistency = true; + + let imports = model_element.children().find(|c| c.tag_name().name() == "imports").unwrap(); + for import in imports.children() { + let tag_name = import.tag_name(); + if tag_name.name() == "import" { + let uuid_att = import.attributes().find(|a| a.name() == "ref").unwrap().value(); + + let uuid = uuid_att.to_string()[0..uuid_att.find('(').unwrap()].to_string(); + let name = uuid_att.to_string()[uuid_att.find('(').unwrap()+1..uuid_att.find(')').unwrap()].to_string(); + let imported_model = model_builder_cache.get_model(name, uuid); + my_model.as_ref().borrow_mut().imported_models.push(imported_model.clone()); + } + } + + my_model.clone() +} \ No newline at end of file diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index 14a65ff..a00d881 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -8,50 +8,15 @@ use std::cell::RefCell; use walkdir::{DirEntry, WalkDir}; -use crate::model::sconcept::{SConcept, SContainmentLink, SProperty, SReferenceLink}; use crate::model::slanguage::SLanguage; use crate::model::smodel::SModel; use crate::model::snode::SNode; use super::slanguage_builder::SLanguageBuilder; use super::slanguage_builder::get_or_build_language; +use super::smodel_builder_base::do_extract_model_core_info; +use super::smodel_builder_base::SModelBuilderCache; -#[derive(Clone)] -pub struct SModelBuilderCache { - pub index_2_concept: HashMap>, - pub index_2_property: HashMap>, - pub index_2_containment_link: HashMap>, - pub index_2_reference_link: HashMap>, - pub index_2_imported_model_uuid: HashMap, - pub index_2_model : HashMap>>, - pub current_model : Option>>, -} - -impl SModelBuilderCache { - pub(crate) fn new() -> Self { - SModelBuilderCache { - index_2_concept : HashMap::new(), - index_2_property : HashMap::new(), - index_2_containment_link : HashMap::new(), - index_2_reference_link : HashMap::new(), - index_2_imported_model_uuid : HashMap::new(), - index_2_model : HashMap::new(), - current_model : None, - } - } - - fn get_model(&mut self, name : String, uuid : String) -> Rc> { - if let Some(model) = self.index_2_model.get(&uuid) { - Rc::clone(&model) - } else { - let temp = Rc::new(RefCell::new(SModel::new(name.clone(), uuid.clone()))); - self.index_2_model.insert(uuid, temp.clone()); - temp.clone() - } - } - -} - pub(crate) fn build_model<'a>(path_to_model: PathBuf, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> Rc> { let mut model_file = path_to_model.clone(); model_file.push(".model"); @@ -92,43 +57,10 @@ fn extract_model_core_info<'a>(path_to_model: PathBuf, model_builder_cache : &mu let parse_res = roxmltree::Document::parse(&s); let document = parse_res.unwrap(); - let model_element = document.root_element(); - let uuid_and_name = model_element.attributes().find(|a| a.name() == "ref").unwrap().value().to_string(); - - let left_parens_pos = uuid_and_name.find('(').unwrap(); - let right_parens_pos = uuid_and_name.find(')').unwrap(); - let uuid = uuid_and_name[0..left_parens_pos].to_string(); - let name = uuid_and_name[left_parens_pos + 1..right_parens_pos].to_string(); - - let mut is_do_not_generate = false; - let model_attributes_elements = model_element.children().filter(|c| (c.tag_name().name().to_string() == "attribute")); - let do_not_generate_attribute = (model_attributes_elements.clone()).find(|a| a.attributes().find(|aa| aa.value() == "doNotGenerate").is_some()); - if let Some(do_not_generate_attribute) = do_not_generate_attribute { - let do_not_generate_str = do_not_generate_attribute.attributes().find(|aa| aa.name() == "value").unwrap().value(); - if do_not_generate_str == "true" { is_do_not_generate = true; } - } - - let my_model = model_builder_cache.get_model(name, uuid); - my_model.as_ref().borrow_mut().path_to_model_file = path_to_model_file; - my_model.as_ref().borrow_mut().is_do_not_generate = is_do_not_generate; - my_model.as_ref().borrow_mut().is_file_per_root_persistency = true; - - let imports = model_element.children().find(|c| c.tag_name().name() == "imports").unwrap(); - for import in imports.children() { - let tag_name = import.tag_name(); - if tag_name.name() == "import" { - let uuid_att = import.attributes().find(|a| a.name() == "ref").unwrap().value(); - - let uuid = uuid_att.to_string()[0..uuid_att.find('(').unwrap()].to_string(); - let name = uuid_att.to_string()[uuid_att.find('(').unwrap()+1..uuid_att.find(')').unwrap()].to_string(); - let imported_model = model_builder_cache.get_model(name, uuid); - my_model.as_ref().borrow_mut().imported_models.push(imported_model.clone()); - } - } - - my_model.clone() + do_extract_model_core_info(document, model_builder_cache, path_to_model_file) } + fn build_root_node_from_file<'a>(dir_entry: DirEntry, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> Option> { let file = std::fs::File::open(dir_entry.path().as_os_str()); diff --git a/mps-cli-rs/src/builder/smodules_repository_builder.rs b/mps-cli-rs/src/builder/smodules_repository_builder.rs index 301691e..78b20ad 100644 --- a/mps-cli-rs/src/builder/smodules_repository_builder.rs +++ b/mps-cli-rs/src/builder/smodules_repository_builder.rs @@ -5,7 +5,7 @@ use std::time::Instant; use walkdir::WalkDir; use crate::builder::slanguage_builder::SLanguageBuilder; -use crate::builder::smodel_builder_file_per_root_persistency::SModelBuilderCache; +use crate::builder::smodel_builder_base::SModelBuilderCache; use crate::builder::ssolution_builder::build_solution; use crate::model::srepository::SRepository; use crate::model::ssolution::SSolution; diff --git a/mps-cli-rs/src/builder/ssolution_builder.rs b/mps-cli-rs/src/builder/ssolution_builder.rs index 5f6608d..75fddbc 100644 --- a/mps-cli-rs/src/builder/ssolution_builder.rs +++ b/mps-cli-rs/src/builder/ssolution_builder.rs @@ -10,7 +10,7 @@ use crate::builder::slanguage_builder::SLanguageBuilder; use crate::model::slanguage::SLanguage; use crate::model::ssolution::SSolution; -use super::smodel_builder_file_per_root_persistency::SModelBuilderCache; +use super::smodel_builder_base::SModelBuilderCache; pub(crate) fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> SSolution { let now = Instant::now(); From 512e1941f18ae6d982fbb8630f60845dbf8d76eb Mon Sep 17 00:00:00 2001 From: danielratiu Date: Sun, 28 Jul 2024 12:25:37 +0200 Subject: [PATCH 39/43] rs: initial step for support for default persistency --- mps-cli-rs/src/builder/mod.rs | 1 + mps-cli-rs/src/builder/smodel_builder_base.rs | 4 +-- .../smodel_builder_default_persistency.rs | 26 +++++++++++++++++++ ...model_builder_file_per_root_persistency.rs | 18 +++++-------- mps-cli-rs/src/builder/ssolution_builder.rs | 13 +++++----- 5 files changed, 42 insertions(+), 20 deletions(-) create mode 100644 mps-cli-rs/src/builder/smodel_builder_default_persistency.rs diff --git a/mps-cli-rs/src/builder/mod.rs b/mps-cli-rs/src/builder/mod.rs index e14512d..6699f3f 100644 --- a/mps-cli-rs/src/builder/mod.rs +++ b/mps-cli-rs/src/builder/mod.rs @@ -1,6 +1,7 @@ pub(crate) mod smodules_repository_builder; mod ssolution_builder; mod smodel_builder_base; +mod smodel_builder_default_persistency; mod smodel_builder_file_per_root_persistency; mod slanguage_builder; mod node_id_utils; diff --git a/mps-cli-rs/src/builder/smodel_builder_base.rs b/mps-cli-rs/src/builder/smodel_builder_base.rs index 6b087b3..a339c2d 100644 --- a/mps-cli-rs/src/builder/smodel_builder_base.rs +++ b/mps-cli-rs/src/builder/smodel_builder_base.rs @@ -12,7 +12,6 @@ pub(crate) struct SModelBuilderCache { pub index_2_reference_link: HashMap>, pub index_2_imported_model_uuid: HashMap, pub index_2_model : HashMap>>, - pub current_model : Option>>, } impl SModelBuilderCache { @@ -24,8 +23,7 @@ impl SModelBuilderCache { index_2_reference_link : HashMap::new(), index_2_imported_model_uuid : HashMap::new(), index_2_model : HashMap::new(), - current_model : None, - } + } } fn get_model(&mut self, name : String, uuid : String) -> Rc> { diff --git a/mps-cli-rs/src/builder/smodel_builder_default_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_default_persistency.rs new file mode 100644 index 0000000..85e3617 --- /dev/null +++ b/mps-cli-rs/src/builder/smodel_builder_default_persistency.rs @@ -0,0 +1,26 @@ +use std::{cell::RefCell, collections::HashMap, io::Read, path::PathBuf, rc::Rc}; + +use crate::model::{slanguage::SLanguage, smodel::SModel}; +use super::{slanguage_builder::SLanguageBuilder, smodel_builder_base::{do_extract_model_core_info, SModelBuilderCache}}; + +pub(crate) fn build_model<'a>(mps_file: PathBuf, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> Rc> { + let ext = mps_file.extension(); + if ext.unwrap().to_ascii_lowercase() != "mps" { + panic!("expected file with extension .mps but found '{}'", mps_file.to_str().unwrap()); + } + + let file = std::fs::File::open(mps_file.clone()); + if file.is_err() { + panic!("file not found '{}'", mps_file.to_str().unwrap()); + } + let mut s = String::new(); + let _ = file.unwrap().read_to_string(&mut s); + let parse_res = roxmltree::Document::parse(&s); + let document = parse_res.unwrap(); + + let model: Rc> = do_extract_model_core_info(document, model_builder_cache, mps_file.to_str().unwrap().to_string()); + + + + model +} \ No newline at end of file diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index a00d881..5dd9836 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -21,8 +21,7 @@ pub(crate) fn build_model<'a>(path_to_model: PathBuf, language_id_to_slanguage: let mut model_file = path_to_model.clone(); model_file.push(".model"); let model: Rc> = extract_model_core_info(model_file, model_builder_cache); - model_builder_cache.current_model = Some(Rc::clone(&model)); - + let mpsr_file_walker = WalkDir::new(path_to_model).min_depth(1).max_depth(1); let mpsr_files = mpsr_file_walker.into_iter().filter(|entry| { if entry.is_ok() { @@ -36,7 +35,7 @@ pub(crate) fn build_model<'a>(path_to_model: PathBuf, language_id_to_slanguage: let mut roots = vec!(); for mpsr_file in mpsr_files.into_iter() { let file = mpsr_file.unwrap(); - if let Some(r) = build_root_node_from_file(file, language_id_to_slanguage, language_builder, model_builder_cache) { + if let Some(r) = build_root_node_from_file(file, language_id_to_slanguage, language_builder, model_builder_cache, &model) { roots.push(r); } }; @@ -61,7 +60,7 @@ fn extract_model_core_info<'a>(path_to_model: PathBuf, model_builder_cache : &mu } -fn build_root_node_from_file<'a>(dir_entry: DirEntry, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> Option> { +fn build_root_node_from_file<'a>(dir_entry: DirEntry, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache, crt_model : &Rc>) -> Option> { let file = std::fs::File::open(dir_entry.path().as_os_str()); let mut s = String::new(); @@ -74,7 +73,7 @@ fn build_root_node_from_file<'a>(dir_entry: DirEntry, language_id_to_slanguage: let node = document.root_element().children().find(|it| it.tag_name().name() == "node"); let mut parent: Option> = None; - Some(parse_node(&mut parent, &node.unwrap(), language_builder, model_builder_cache)) + Some(parse_node(&mut parent, &node.unwrap(), language_builder, model_builder_cache, crt_model)) } fn parse_imports(document: &Document, model_builder_cache : &mut SModelBuilderCache) { @@ -145,7 +144,7 @@ fn parse_registry<'a>(document: &Document, language_id_to_slanguage: &'a mut Has } -fn parse_node<'a>(parent_node : &mut Option>, node: &Node, language_builder : &SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> Rc { +fn parse_node<'a>(parent_node : &mut Option>, node: &Node, language_builder : &SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache, crt_model : &'a Rc>) -> Rc { let node_attrs = node.attributes(); let concept_index = (node_attrs.clone()).into_iter().find(|a| a.name() == "concept").unwrap().value(); let node_id = (node_attrs.clone()).into_iter().find(|a| a.name() == "id").unwrap().value(); @@ -200,10 +199,7 @@ fn parse_node<'a>(parent_node : &mut Option>, node: &Node, language_bu model_id = String::from(mm.get(model_index).unwrap()); node_id = String::from(&to[index + 1..to.len()]); } else { - let crt_model = &model_builder_cache.current_model; - let m = crt_model.as_ref().unwrap(); - let m = m.as_ref().borrow(); - model_id = String::from(m.uuid.as_str()); + model_id = String::from(crt_model.borrow().uuid.as_str()); node_id = String::from(to); }; @@ -224,7 +220,7 @@ fn parse_node<'a>(parent_node : &mut Option>, node: &Node, language_bu let nodes = node.children().filter(|it| it.tag_name().name() == "node"); for node in nodes { - parse_node(&mut Some(Rc::clone(¤t_node_rc)), &node, language_builder, model_builder_cache); + parse_node(&mut Some(Rc::clone(¤t_node_rc)), &node, language_builder, model_builder_cache, crt_model); }; Rc::clone(¤t_node_rc) diff --git a/mps-cli-rs/src/builder/ssolution_builder.rs b/mps-cli-rs/src/builder/ssolution_builder.rs index 75fddbc..fd40143 100644 --- a/mps-cli-rs/src/builder/ssolution_builder.rs +++ b/mps-cli-rs/src/builder/ssolution_builder.rs @@ -5,7 +5,8 @@ use std::time::Instant; use std::io::Read; use walkdir::WalkDir; -use crate::builder::smodel_builder_file_per_root_persistency::build_model; +use crate::builder::smodel_builder_file_per_root_persistency; +use crate::builder::smodel_builder_default_persistency; use crate::builder::slanguage_builder::SLanguageBuilder; use crate::model::slanguage::SLanguage; use crate::model::ssolution::SSolution; @@ -24,12 +25,12 @@ pub(crate) fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_id_to_ let mut models = vec![]; for model_entry in model_dir.into_iter() { let path = model_entry.unwrap().into_path(); - if path.is_dir() { - let model = build_model(path, language_id_to_slanguage, language_builder, model_builder_cache); - models.push(model) + let model = if path.is_dir() { + smodel_builder_file_per_root_persistency::build_model(path, language_id_to_slanguage, language_builder, model_builder_cache) } else { - println!("ERROR: model entry {} is a file not a directory. Cannot be parsed as only file per root persistency is supported.", path.to_str().unwrap().to_string()) - } + smodel_builder_default_persistency::build_model(path, language_id_to_slanguage, language_builder, model_builder_cache) + }; + models.push(model) } solution.models.extend(models); From f0bfa9061704fec7cb21a0cceef27cf91f24d0c0 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Sun, 28 Jul 2024 13:13:43 +0200 Subject: [PATCH 40/43] rs: handling default persistency --- mps-cli-rs/src/builder/smodel_builder_base.rs | 171 ++++++++++++++++- .../smodel_builder_default_persistency.rs | 9 +- ...model_builder_file_per_root_persistency.rs | 176 +----------------- mps-cli-rs/tests/default_persistency_tests.rs | 9 + .../tests/file_per_root_persistency_tests.rs | 2 +- mps-cli-rs/tests/model_completeness_tests.rs | 18 +- ...ry_top.default_persistency.library_top.mps | 3 + 7 files changed, 207 insertions(+), 181 deletions(-) create mode 100644 mps-cli-rs/tests/default_persistency_tests.rs diff --git a/mps-cli-rs/src/builder/smodel_builder_base.rs b/mps-cli-rs/src/builder/smodel_builder_base.rs index a339c2d..a4c0ef2 100644 --- a/mps-cli-rs/src/builder/smodel_builder_base.rs +++ b/mps-cli-rs/src/builder/smodel_builder_base.rs @@ -1,9 +1,14 @@ +use std::borrow::BorrowMut; use std::collections::HashMap; use std::{cell::RefCell, rc::Rc}; -use roxmltree::Document; +use roxmltree::{Document, Node}; +use crate::model::slanguage::SLanguage; use crate::model::smodel::SModel; use crate::model::sconcept::{SConcept, SContainmentLink, SProperty, SReferenceLink}; +use crate::model::snode::SNode; + +use super::slanguage_builder::{get_or_build_language, SLanguageBuilder}; pub(crate) struct SModelBuilderCache { pub index_2_concept: HashMap>, @@ -37,7 +42,7 @@ impl SModelBuilderCache { } } -pub(crate) fn do_extract_model_core_info(document: Document, model_builder_cache: &mut SModelBuilderCache, path_to_model_file: String) -> Rc> { +pub(crate) fn do_extract_model_core_info(document: &Document, model_builder_cache: &mut SModelBuilderCache, path_to_model_file: String) -> Rc> { let model_element = document.root_element(); let uuid_and_name = model_element.attributes().find(|a| a.name() == "ref").unwrap().value().to_string(); @@ -73,4 +78,166 @@ pub(crate) fn do_extract_model_core_info(document: Document, model_builder_cache } my_model.clone() +} + +pub(crate) fn parse_imports(document: &Document, model_builder_cache : &mut SModelBuilderCache) { + let model_element = document.root_element(); + let imports_element = model_element.children().find(|c| c.tag_name().name() == "imports"); + match imports_element { + Some(imports) => { + for import in imports.children() { + let tag_name = import.tag_name(); + if tag_name.name() == "import" { + let index = import.attributes().find(|a| a.name() == "index").unwrap().value(); + let uuid = import.attributes().find(|a| a.name() == "ref").unwrap().value(); + + let uuid = uuid.to_string()[0..uuid.find('(').unwrap()].to_string(); + model_builder_cache.index_2_imported_model_uuid.insert(index.to_string(), uuid); + } + } + }, + _ => () + } +} + +pub(crate) fn parse_registry<'a>(document: &Document, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) { + let model_element = document.root_element(); + let registry_element = model_element.children().find(|c| c.tag_name().name() == "registry"); + match registry_element { + Some(registry) => { + for language in registry.children() { + if language.tag_name().name() != "language" { continue; } + + let language_id = language.attributes().find(|a| a.name() == "id").unwrap().value(); + let language_name = language.attributes().find(|a| a.name() == "name").unwrap().value(); + + let lang = get_or_build_language(&language_id.to_string(), &language_name.to_string(), language_id_to_slanguage); + for concept in language.children() { + if concept.tag_name().name() != "concept" { continue; } + + let concept_id = concept.attributes().find(|a| a.name() == "id").unwrap().value(); + let concept_name = concept.attributes().find(|a| a.name() == "name").unwrap().value(); + let concept_index = concept.attributes().find(|a| a.name() == "index").unwrap().value(); + let conc = language_builder.get_or_create_concept(lang, concept_id, concept_name); + model_builder_cache.index_2_concept.borrow_mut().insert(concept_index.to_string(), Rc::clone(&conc)); + + for properties_links_references in concept.children() { + if properties_links_references.tag_name().name() == "" { continue; } + + let tag_name = properties_links_references.tag_name().name(); + let id = properties_links_references.attributes().find(|a| a.name() == "id").unwrap().value(); + let name = properties_links_references.attributes().find(|a| a.name() == "name").unwrap().value(); + let index = properties_links_references.attributes().find(|a| a.name() == "index").unwrap().value(); + + if tag_name == "property" { + let prop = language_builder.get_or_create_property(Rc::clone(&conc),id.to_string(), name.to_string()); + model_builder_cache.index_2_property.borrow_mut().insert(index.to_string(), Rc::clone(&prop)); + } else if tag_name == "child" { + let child_link = language_builder.get_or_create_child(Rc::clone(&conc),id.to_string(), name.to_string()); + model_builder_cache.index_2_containment_link.borrow_mut().insert(index.to_string(), Rc::clone(&child_link)); + } else if tag_name == "reference" { + let ref_link = language_builder.get_or_create_reference(Rc::clone(&conc),id.to_string(), name.to_string()); + model_builder_cache.index_2_reference_link.borrow_mut().insert(index.to_string(), Rc::clone(&ref_link)); + } + } + } + }; + }, + _ => () + } +} + +pub(crate) fn do_build_root_nodes(document: &Document, model_builder_cache: &mut SModelBuilderCache, language_id_to_slanguage: &mut HashMap, language_builder: &mut SLanguageBuilder, crt_model: &Rc>) -> Vec> { + parse_imports(document, model_builder_cache); + parse_registry(document, language_id_to_slanguage, language_builder, model_builder_cache); + + let mut res = Vec::new(); + let nodes = document.root_element().children().filter(|it| it.tag_name().name() == "node"); + for node in nodes { + let mut parent: Option> = None; + res.push(parse_node(&mut parent, &node, language_builder, model_builder_cache, crt_model)); + } + res +} + +fn parse_node<'a>(parent_node : &mut Option>, node: &Node, language_builder : &SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache, crt_model : &'a Rc>) -> Rc { + let node_attrs = node.attributes(); + let concept_index = (node_attrs.clone()).into_iter().find(|a| a.name() == "concept").unwrap().value(); + let node_id = (node_attrs.clone()).into_iter().find(|a| a.name() == "id").unwrap().value(); + let role = (node_attrs.clone()).into_iter().find(|a| a.name() == "role"); + let role = if role.is_none() { None } else { Some(role.unwrap().value().to_string()) }; + + let index_2_concept = &model_builder_cache.index_2_concept; + + let my_concept = index_2_concept.get(concept_index).unwrap(); + let role_human_readable = match role.clone() { + Some(role_string) => { + let index_2_containment_link = &model_builder_cache.index_2_containment_link; + let r = index_2_containment_link.get(&role_string).unwrap(); + Some(String::from(&r.name)) + }, + None => None, + }; + let mut current_node = SNode::new(node_id.to_string(), Rc::clone(my_concept), role_human_readable); + + let properties = node.children().filter(|it| it.tag_name().name() == "property"); + for property in properties { + let role = property.attributes().find(|a| a.name() == "role").unwrap().value(); + let value = property.attributes().find(|a| a.name() == "value").unwrap().value(); + let index_2_properties = &model_builder_cache.index_2_property; + let prop = index_2_properties.get(role).unwrap(); + current_node.add_property(prop, value.to_string()); + }; + + let refs = node.children().filter(|it| it.tag_name().name() == "ref"); + for ref_ in refs { + let role = ref_.attributes().find(|a| a.name() == "role").unwrap().value(); + let to = ref_.attributes().find(|a| a.name() == "to"); + let to: &str = if let Some(t) = to { + t.value() + } else { + ref_.attributes().find(|a| a.name() == "node").unwrap().value() + }; + let resolve = if let Some(r) = ref_.attributes().find(|a| a.name() == "resolve") { + Some(String::from(r.value())) + } else { + None + }; + + let index_2_reference_links = &model_builder_cache.index_2_reference_link; + let reference_link = index_2_reference_links.get(&role.to_string()).unwrap(); + + let model_id : String; + let node_id : String; + if let Some(index) = to.find(":") { + let model_index = &to[0..index]; + let mm = &model_builder_cache.index_2_imported_model_uuid; + model_id = String::from(mm.get(model_index).unwrap()); + node_id = String::from(&to[index + 1..to.len()]); + } else { + model_id = String::from(crt_model.borrow().uuid.as_str()); + node_id = String::from(to); + }; + + current_node.add_reference(reference_link, model_id, node_id, resolve); + }; + + let current_node_rc : Rc; + + if let Some(parent) = parent_node { + let index_2_containment_link = &model_builder_cache.index_2_containment_link; + let cl = index_2_containment_link.get(&role.unwrap()); + current_node.set_parent(Rc::clone(parent)); + current_node_rc = Rc::new(current_node); + parent.borrow_mut().add_child(Rc::clone(cl.unwrap()), Rc::clone(¤t_node_rc)); + } else { + current_node_rc = Rc::new(current_node); + }; + + let nodes = node.children().filter(|it| it.tag_name().name() == "node"); + for node in nodes { + parse_node(&mut Some(Rc::clone(¤t_node_rc)), &node, language_builder, model_builder_cache, crt_model); + }; + + Rc::clone(¤t_node_rc) } \ No newline at end of file diff --git a/mps-cli-rs/src/builder/smodel_builder_default_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_default_persistency.rs index 85e3617..a049635 100644 --- a/mps-cli-rs/src/builder/smodel_builder_default_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_default_persistency.rs @@ -1,11 +1,11 @@ use std::{cell::RefCell, collections::HashMap, io::Read, path::PathBuf, rc::Rc}; use crate::model::{slanguage::SLanguage, smodel::SModel}; -use super::{slanguage_builder::SLanguageBuilder, smodel_builder_base::{do_extract_model_core_info, SModelBuilderCache}}; +use super::{slanguage_builder::SLanguageBuilder, smodel_builder_base::{do_build_root_nodes, do_extract_model_core_info, SModelBuilderCache}}; pub(crate) fn build_model<'a>(mps_file: PathBuf, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) -> Rc> { let ext = mps_file.extension(); - if ext.unwrap().to_ascii_lowercase() != "mps" { + if !ext.is_some_and(|e| e.eq_ignore_ascii_case("mps")) { panic!("expected file with extension .mps but found '{}'", mps_file.to_str().unwrap()); } @@ -18,9 +18,10 @@ pub(crate) fn build_model<'a>(mps_file: PathBuf, language_id_to_slanguage: &'a m let parse_res = roxmltree::Document::parse(&s); let document = parse_res.unwrap(); - let model: Rc> = do_extract_model_core_info(document, model_builder_cache, mps_file.to_str().unwrap().to_string()); + let model: Rc> = do_extract_model_core_info(&document, model_builder_cache, mps_file.to_str().unwrap().to_string()); - + let roots = do_build_root_nodes(&document, model_builder_cache, language_id_to_slanguage, language_builder, &model); + model.as_ref().borrow_mut().root_nodes.extend(roots); model } \ No newline at end of file diff --git a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs index 5dd9836..c5d44d0 100644 --- a/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs +++ b/mps-cli-rs/src/builder/smodel_builder_file_per_root_persistency.rs @@ -1,8 +1,7 @@ -use std::borrow::BorrowMut; use std::collections::HashMap; use std::path::PathBuf; use std::io::Read; -use roxmltree::{Document, Node}; +use roxmltree::Document; use std::rc::Rc; use std::cell::RefCell; @@ -12,8 +11,7 @@ use crate::model::slanguage::SLanguage; use crate::model::smodel::SModel; use crate::model::snode::SNode; use super::slanguage_builder::SLanguageBuilder; -use super::slanguage_builder::get_or_build_language; -use super::smodel_builder_base::do_extract_model_core_info; +use super::smodel_builder_base::{do_build_root_nodes, do_extract_model_core_info}; use super::smodel_builder_base::SModelBuilderCache; @@ -27,7 +25,7 @@ pub(crate) fn build_model<'a>(path_to_model: PathBuf, language_id_to_slanguage: if entry.is_ok() { let dir_entry = entry.as_ref().unwrap(); let extension = dir_entry.path().extension(); - return dir_entry.file_type().is_file() && extension.is_some_and(|e| e.eq("mpsr")); + return dir_entry.file_type().is_file() && extension.is_some_and(|e| e.eq_ignore_ascii_case("mpsr")); } return false; }); @@ -35,9 +33,8 @@ pub(crate) fn build_model<'a>(path_to_model: PathBuf, language_id_to_slanguage: let mut roots = vec!(); for mpsr_file in mpsr_files.into_iter() { let file = mpsr_file.unwrap(); - if let Some(r) = build_root_node_from_file(file, language_id_to_slanguage, language_builder, model_builder_cache, &model) { - roots.push(r); - } + let r= build_root_node_from_file(file, language_id_to_slanguage, language_builder, model_builder_cache, &model); + roots.extend(r); }; model.as_ref().borrow_mut().root_nodes.extend(roots); @@ -53,14 +50,14 @@ fn extract_model_core_info<'a>(path_to_model: PathBuf, model_builder_cache : &mu } let mut s = String::new(); let _ = file.unwrap().read_to_string(&mut s); - let parse_res = roxmltree::Document::parse(&s); + let parse_res = Document::parse(&s); let document = parse_res.unwrap(); - do_extract_model_core_info(document, model_builder_cache, path_to_model_file) + do_extract_model_core_info(&document, model_builder_cache, path_to_model_file) } -fn build_root_node_from_file<'a>(dir_entry: DirEntry, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache, crt_model : &Rc>) -> Option> { +fn build_root_node_from_file<'a>(dir_entry: DirEntry, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache, crt_model : &Rc>) -> Vec> { let file = std::fs::File::open(dir_entry.path().as_os_str()); let mut s = String::new(); @@ -68,162 +65,7 @@ fn build_root_node_from_file<'a>(dir_entry: DirEntry, language_id_to_slanguage: let parse_res = roxmltree::Document::parse(&s); let document = parse_res.unwrap(); - parse_imports(&document, model_builder_cache); - parse_registry(&document, language_id_to_slanguage, language_builder, model_builder_cache); - - let node = document.root_element().children().find(|it| it.tag_name().name() == "node"); - let mut parent: Option> = None; - Some(parse_node(&mut parent, &node.unwrap(), language_builder, model_builder_cache, crt_model)) -} - -fn parse_imports(document: &Document, model_builder_cache : &mut SModelBuilderCache) { - let model_element = document.root_element(); - let imports_element = model_element.children().find(|c| c.tag_name().name() == "imports"); - match imports_element { - Some(imports) => { - for import in imports.children() { - let tag_name = import.tag_name(); - if tag_name.name() == "import" { - let index = import.attributes().find(|a| a.name() == "index").unwrap().value(); - let uuid = import.attributes().find(|a| a.name() == "ref").unwrap().value(); - - let uuid = uuid.to_string()[0..uuid.find('(').unwrap()].to_string(); - model_builder_cache.index_2_imported_model_uuid.insert(index.to_string(), uuid); - } - } - }, - _ => () - } -} - -fn parse_registry<'a>(document: &Document, language_id_to_slanguage: &'a mut HashMap, language_builder : &mut SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache) { - let model_element = document.root_element(); - let registry_element = model_element.children().find(|c| c.tag_name().name() == "registry"); - match registry_element { - Some(registry) => { - for language in registry.children() { - if language.tag_name().name() != "language" { continue; } - - let language_id = language.attributes().find(|a| a.name() == "id").unwrap().value(); - let language_name = language.attributes().find(|a| a.name() == "name").unwrap().value(); - - let lang = get_or_build_language(&language_id.to_string(), &language_name.to_string(), language_id_to_slanguage); - for concept in language.children() { - if concept.tag_name().name() != "concept" { continue; } - - let concept_id = concept.attributes().find(|a| a.name() == "id").unwrap().value(); - let concept_name = concept.attributes().find(|a| a.name() == "name").unwrap().value(); - let concept_index = concept.attributes().find(|a| a.name() == "index").unwrap().value(); - let conc = language_builder.get_or_create_concept(lang, concept_id, concept_name); - model_builder_cache.index_2_concept.borrow_mut().insert(concept_index.to_string(), Rc::clone(&conc)); - - for properties_links_references in concept.children() { - if properties_links_references.tag_name().name() == "" { continue; } - - let tag_name = properties_links_references.tag_name().name(); - let id = properties_links_references.attributes().find(|a| a.name() == "id").unwrap().value(); - let name = properties_links_references.attributes().find(|a| a.name() == "name").unwrap().value(); - let index = properties_links_references.attributes().find(|a| a.name() == "index").unwrap().value(); - - if tag_name == "property" { - let prop = language_builder.get_or_create_property(Rc::clone(&conc),id.to_string(), name.to_string()); - model_builder_cache.index_2_property.borrow_mut().insert(index.to_string(), Rc::clone(&prop)); - } else if tag_name == "child" { - let child_link = language_builder.get_or_create_child(Rc::clone(&conc),id.to_string(), name.to_string()); - model_builder_cache.index_2_containment_link.borrow_mut().insert(index.to_string(), Rc::clone(&child_link)); - } else if tag_name == "reference" { - let ref_link = language_builder.get_or_create_reference(Rc::clone(&conc),id.to_string(), name.to_string()); - model_builder_cache.index_2_reference_link.borrow_mut().insert(index.to_string(), Rc::clone(&ref_link)); - } - } - } - }; - }, - _ => () - } -} - - -fn parse_node<'a>(parent_node : &mut Option>, node: &Node, language_builder : &SLanguageBuilder, model_builder_cache : &mut SModelBuilderCache, crt_model : &'a Rc>) -> Rc { - let node_attrs = node.attributes(); - let concept_index = (node_attrs.clone()).into_iter().find(|a| a.name() == "concept").unwrap().value(); - let node_id = (node_attrs.clone()).into_iter().find(|a| a.name() == "id").unwrap().value(); - let role = (node_attrs.clone()).into_iter().find(|a| a.name() == "role"); - let role = if role.is_none() { None } else { Some(role.unwrap().value().to_string()) }; - - let index_2_concept = &model_builder_cache.index_2_concept; - - let my_concept = index_2_concept.get(concept_index).unwrap(); - let role_human_readable = match role.clone() { - Some(role_string) => { - let index_2_containment_link = &model_builder_cache.index_2_containment_link; - let r = index_2_containment_link.get(&role_string).unwrap(); - Some(String::from(&r.name)) - }, - None => None, - }; - let mut current_node = SNode::new(node_id.to_string(), Rc::clone(my_concept), role_human_readable); - - let properties = node.children().filter(|it| it.tag_name().name() == "property"); - for property in properties { - let role = property.attributes().find(|a| a.name() == "role").unwrap().value(); - let value = property.attributes().find(|a| a.name() == "value").unwrap().value(); - let index_2_properties = &model_builder_cache.index_2_property; - let prop = index_2_properties.get(role).unwrap(); - current_node.add_property(prop, value.to_string()); - }; - - let refs = node.children().filter(|it| it.tag_name().name() == "ref"); - for ref_ in refs { - let role = ref_.attributes().find(|a| a.name() == "role").unwrap().value(); - let to = ref_.attributes().find(|a| a.name() == "to"); - let to: &str = if let Some(t) = to { - t.value() - } else { - ref_.attributes().find(|a| a.name() == "node").unwrap().value() - }; - let resolve = if let Some(r) = ref_.attributes().find(|a| a.name() == "resolve") { - Some(String::from(r.value())) - } else { - None - }; - - let index_2_reference_links = &model_builder_cache.index_2_reference_link; - let reference_link = index_2_reference_links.get(&role.to_string()).unwrap(); - - let model_id : String; - let node_id : String; - if let Some(index) = to.find(":") { - let model_index = &to[0..index]; - let mm = &model_builder_cache.index_2_imported_model_uuid; - model_id = String::from(mm.get(model_index).unwrap()); - node_id = String::from(&to[index + 1..to.len()]); - } else { - model_id = String::from(crt_model.borrow().uuid.as_str()); - node_id = String::from(to); - }; - - current_node.add_reference(reference_link, model_id, node_id, resolve); - }; - - let current_node_rc : Rc; - - if let Some(parent) = parent_node { - let index_2_containment_link = &model_builder_cache.index_2_containment_link; - let cl = index_2_containment_link.get(&role.unwrap()); - current_node.set_parent(Rc::clone(parent)); - current_node_rc = Rc::new(current_node); - parent.borrow_mut().add_child(Rc::clone(cl.unwrap()), Rc::clone(¤t_node_rc)); - } else { - current_node_rc = Rc::new(current_node); - }; - - let nodes = node.children().filter(|it| it.tag_name().name() == "node"); - for node in nodes { - parse_node(&mut Some(Rc::clone(¤t_node_rc)), &node, language_builder, model_builder_cache, crt_model); - }; - - Rc::clone(¤t_node_rc) + do_build_root_nodes(&document, model_builder_cache, language_id_to_slanguage, language_builder, crt_model) } diff --git a/mps-cli-rs/tests/default_persistency_tests.rs b/mps-cli-rs/tests/default_persistency_tests.rs new file mode 100644 index 0000000..598878d --- /dev/null +++ b/mps-cli-rs/tests/default_persistency_tests.rs @@ -0,0 +1,9 @@ +mod model_completeness_tests; +use mps_cli::build_repo_from_directory; + +#[test] +fn test_build_repository() { + let path = "../mps_test_projects/mps_cli_lanuse_default_persistency/"; + let repo = build_repo_from_directory(path.to_string()); + model_completeness_tests::check_model_completeness(&repo, "mps.cli.lanuse.library_top.default_persistency", "mps.cli.lanuse.library_second.default_persistency"); +} \ No newline at end of file diff --git a/mps-cli-rs/tests/file_per_root_persistency_tests.rs b/mps-cli-rs/tests/file_per_root_persistency_tests.rs index 49dd015..9b97504 100644 --- a/mps-cli-rs/tests/file_per_root_persistency_tests.rs +++ b/mps-cli-rs/tests/file_per_root_persistency_tests.rs @@ -5,5 +5,5 @@ use mps_cli::build_repo_from_directory; fn test_build_repository() { let path = "../mps_test_projects/mps_cli_lanuse_file_per_root/"; let repo = build_repo_from_directory(path.to_string()); - model_completeness_tests::check_model_completeness(&repo); + model_completeness_tests::check_model_completeness(&repo, "mps.cli.lanuse.library_top", "mps.cli.lanuse.library_second"); } \ No newline at end of file diff --git a/mps-cli-rs/tests/model_completeness_tests.rs b/mps-cli-rs/tests/model_completeness_tests.rs index ddeb108..5b7b8b1 100644 --- a/mps-cli-rs/tests/model_completeness_tests.rs +++ b/mps-cli-rs/tests/model_completeness_tests.rs @@ -3,14 +3,14 @@ use std::{cell::Ref, rc::Rc}; use mps_cli::model::{smodel::SModel, srepository::SRepository, snode::SNode}; #[cfg(test)] -pub (crate) fn check_model_completeness(repo : &SRepository) { +pub (crate) fn check_model_completeness(repo : &SRepository, library_top_solution_name : &str, library_second_solution_name : &str) { //library_first_solution - let library_first_solution = repo.find_solution_by_name("mps.cli.lanuse.library_top").unwrap(); + let library_first_solution = repo.find_solution_by_name(library_top_solution_name).unwrap(); assert_eq!(library_first_solution.models.len(), 2); - assert!(library_first_solution.find_model("mps.cli.lanuse.library_top.authors_top").is_some()); - assert!(library_first_solution.find_model("mps.cli.lanuse.library_top.library_top").is_some()); + assert!(library_first_solution.find_model((library_top_solution_name.to_owned() + ".authors_top").as_str()).is_some()); + assert!(library_first_solution.find_model((library_top_solution_name.to_owned() + ".library_top").as_str()).is_some()); - let library_top_model = repo.find_model_by_name("mps.cli.lanuse.library_top.library_top").unwrap(); + let library_top_model = repo.find_model_by_name((library_top_solution_name.to_owned() + ".library_top").as_str()).unwrap(); let library_top_model : Ref = library_top_model.try_borrow().ok().unwrap(); assert_eq!(library_top_model.root_nodes.len(), 2); let munich_library_root = library_top_model.root_nodes.first().unwrap(); @@ -35,12 +35,16 @@ pub (crate) fn check_model_completeness(repo : &SRepository) { let authors = tom_sawyer.get_children("authors"); let mark_twain = authors.first().unwrap().get_reference("person").unwrap(); assert_eq!(mark_twain.resolve_info, "Mark Twain"); - assert_eq!(mark_twain.model_id, "r:ec5f093b-9d83-43a1-9b41-b5952da8b1ed"); + if library_top_solution_name.contains("default_persistency") { + assert_eq!(mark_twain.model_id, "r:ca00da79-915e-4bdb-9c30-11a341daf779"); + } else { + assert_eq!(mark_twain.model_id, "r:ec5f093b-9d83-43a1-9b41-b5952da8b1ed"); + } assert_eq!(mark_twain.node_id, "4Yb5JA31NUv"); assert!(mark_twain.resolve(repo).is_some()); // library_second_solution - let library_second_solution = repo.find_solution_by_name("mps.cli.lanuse.library_second").unwrap(); + let library_second_solution = repo.find_solution_by_name(library_second_solution_name).unwrap(); assert_eq!(library_second_solution.models.len(), 1); // languages diff --git a/mps_test_projects/mps_cli_lanuse_default_persistency/solutions/mps.cli.lanuse.library_top.default_persistency/models/mps.cli.lanuse.library_top.default_persistency.library_top.mps b/mps_test_projects/mps_cli_lanuse_default_persistency/solutions/mps.cli.lanuse.library_top.default_persistency/models/mps.cli.lanuse.library_top.default_persistency.library_top.mps index f47c6c2..3717327 100644 --- a/mps_test_projects/mps_cli_lanuse_default_persistency/solutions/mps.cli.lanuse.library_top.default_persistency/models/mps.cli.lanuse.library_top.default_persistency.library_top.mps +++ b/mps_test_projects/mps_cli_lanuse_default_persistency/solutions/mps.cli.lanuse.library_top.default_persistency/models/mps.cli.lanuse.library_top.default_persistency.library_top.mps @@ -71,5 +71,8 @@ + + + From ea8cabbe7ccdff139d19b58091353174960531ac Mon Sep 17 00:00:00 2001 From: danielratiu Date: Sun, 28 Jul 2024 13:18:56 +0200 Subject: [PATCH 41/43] rs: fixed workflow --- .github/workflows/mps_cli_rs_build.yaml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/mps_cli_rs_build.yaml b/.github/workflows/mps_cli_rs_build.yaml index 95738d0..9ed744b 100644 --- a/.github/workflows/mps_cli_rs_build.yaml +++ b/.github/workflows/mps_cli_rs_build.yaml @@ -18,10 +18,8 @@ jobs: steps: - uses: actions/checkout@v3 - - name: setup toolchain - uses: hecrj/setup-rust-action@v1 - with: - rust-version: stable - - - name: cargo test - run: cargo test \ No newline at end of file + - uses: hecrj/setup-rust-action@v1 + with: + rust-version: stable + - name: Run tests + run: cargo test \ No newline at end of file From 8d79a914a05cbe0c8e936d35c2375670fdfc3a18 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Sun, 28 Jul 2024 13:23:10 +0200 Subject: [PATCH 42/43] rs: fixed workflow --- .github/workflows/mps_cli_rs_build.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/mps_cli_rs_build.yaml b/.github/workflows/mps_cli_rs_build.yaml index 9ed744b..528dee3 100644 --- a/.github/workflows/mps_cli_rs_build.yaml +++ b/.github/workflows/mps_cli_rs_build.yaml @@ -11,7 +11,7 @@ env: GITHUB_TOKEN: ${{ secrets.MPSCLI_GITHUB_PKG_REGISTRY }} jobs: - build_mps_cli_py: + build_mps_cli_rs: runs-on: ubuntu-latest env: DISPLAY: ':99' @@ -22,4 +22,5 @@ jobs: with: rust-version: stable - name: Run tests + working-directory: ./mps-cli-rs run: cargo test \ No newline at end of file From 20b8bc64269d699dc7992e1518668bdff93b2175 Mon Sep 17 00:00:00 2001 From: danielratiu Date: Sun, 28 Jul 2024 13:28:44 +0200 Subject: [PATCH 43/43] rs: fixed test --- mps-cli-rs/tests/model_completeness_tests.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mps-cli-rs/tests/model_completeness_tests.rs b/mps-cli-rs/tests/model_completeness_tests.rs index 5b7b8b1..86b26a3 100644 --- a/mps-cli-rs/tests/model_completeness_tests.rs +++ b/mps-cli-rs/tests/model_completeness_tests.rs @@ -13,8 +13,9 @@ pub (crate) fn check_model_completeness(repo : &SRepository, library_top_solutio let library_top_model = repo.find_model_by_name((library_top_solution_name.to_owned() + ".library_top").as_str()).unwrap(); let library_top_model : Ref = library_top_model.try_borrow().ok().unwrap(); assert_eq!(library_top_model.root_nodes.len(), 2); - let munich_library_root = library_top_model.root_nodes.first().unwrap(); - assert_eq!(munich_library_root.get_property("name"), Some(String::from("munich_library"))); + let munich_library_root = library_top_model.root_nodes.iter().find(|r| r.get_property("name") == Some(String::from("munich_library"))); + assert!(munich_library_root.is_some()); + let munich_library_root = munich_library_root.unwrap(); assert_eq!(SNode::get_descendants(Rc::clone(munich_library_root), true).len(), 8); assert_eq!(munich_library_root.get_children("entities").len(), 4);