melodium_lang/semantic/
script.rs

1//! Module dedicated to Script semantic analysis.
2
3use melodium_common::descriptor::Version;
4
5use super::common::Node;
6use super::model::Model;
7use super::r#use::Use;
8use super::treatment::Treatment;
9use crate::text::Script as TextScript;
10use crate::ScriptResult;
11use std::collections::HashMap;
12use std::sync::{Arc, RwLock};
13
14/// Structure managing and describing semantic of a script.
15///
16/// Matches the concept of a script file content.
17/// It owns the whole [text script](TextScript), as well as references to semantical contained [Uses](Use), [Models](Model), and [Treatments](Treatment).
18/// There is a logical coherence equivalent to the one expressed in the text script, but this coherence, as in the text, may be _incomplete_ or _broken_.
19#[derive(Debug)]
20pub struct Script {
21    pub text: TextScript,
22
23    pub uses: Vec<Arc<RwLock<Use>>>,
24    pub models: HashMap<String, Arc<RwLock<Model>>>,
25    pub treatments: HashMap<String, Arc<RwLock<Treatment>>>,
26}
27
28impl Script {
29    /// Create a new semantic script, based on textual script.
30    ///
31    /// * `address`: the literal string specifiyng the script location (i.e. the filepath).
32    /// * `text`: the textual script.
33    ///
34    /// # Note
35    /// Only parent-child relationships are made at this step. Other references can be made afterwards using the [Node trait](Node).
36    ///
37    pub fn new(text: TextScript, version: Version) -> ScriptResult<Arc<RwLock<Self>>> {
38        let script = Arc::<RwLock<Self>>::new(RwLock::new(Self {
39            text: text.clone(),
40            uses: Vec::new(),
41            models: HashMap::new(),
42            treatments: HashMap::new(),
43        }));
44        let mut result = ScriptResult::new_success(script.clone());
45
46        for u in text.uses {
47            if let Some(r#use) = result.merge_degrade_failure(Use::new(
48                Arc::clone(&script),
49                u.clone(),
50                version.clone(),
51            )) {
52                script.write().unwrap().uses.push(r#use);
53            }
54        }
55
56        for m in text.models {
57            if let Some(model) =
58                result.merge_degrade_failure(Model::new(Arc::clone(&script), m.clone()))
59            {
60                let name = model.read().unwrap().name.clone();
61                script.write().unwrap().models.insert(name, model);
62            }
63        }
64
65        for s in text.treatments {
66            if let Some(treatment) =
67                result.merge_degrade_failure(Treatment::new(Arc::clone(&script), s.clone()))
68            {
69                let name = treatment.read().unwrap().name.clone();
70                script.write().unwrap().treatments.insert(name, treatment);
71            }
72        }
73
74        result
75    }
76
77    /// Search for an element imported through a use.
78    /// This search using the `as` property.
79    ///
80    pub fn find_use(&self, element_as: &str) -> Option<&Arc<RwLock<Use>>> {
81        self.uses
82            .iter()
83            .find(|&u| u.read().unwrap().r#as == element_as)
84    }
85
86    /// Search for a model.
87    pub fn find_model(&self, name: &str) -> Option<&Arc<RwLock<Model>>> {
88        self.models.get(name)
89    }
90
91    /// Search for a treatment.
92    pub fn find_treatment(&self, name: &str) -> Option<&Arc<RwLock<Treatment>>> {
93        self.treatments.get(name)
94    }
95}
96
97impl Node for Script {
98    fn children(&self) -> Vec<Arc<RwLock<dyn Node>>> {
99        let mut children: Vec<Arc<RwLock<dyn Node>>> = Vec::new();
100
101        self.uses
102            .iter()
103            .for_each(|u| children.push(Arc::clone(&u) as Arc<RwLock<dyn Node>>));
104        self.models
105            .iter()
106            .for_each(|(_, m)| children.push(Arc::clone(&m) as Arc<RwLock<dyn Node>>));
107        self.treatments
108            .iter()
109            .for_each(|(_, s)| children.push(Arc::clone(&s) as Arc<RwLock<dyn Node>>));
110
111        children
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    /*
118    use crate::script::semantic::common::Tree;
119    use crate::script_file::ScriptFile;
120
121    #[test]
122    fn test_simple_semantic() {
123
124        let address = "melodium-tests/semantic/simple_build.mel";
125
126        let mut script_file = ScriptFile::new(address);
127
128        script_file.load().unwrap();
129        script_file.parse().unwrap();
130
131        let semantic_tree = Tree::new(script_file.script().clone()).unwrap();
132        semantic_tree.make_references().unwrap();
133
134        assert_eq!(semantic_tree.script.borrow().treatments.len(), 4);
135    }*/
136}