1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//! Module dedicated to Use semantic analysis.
use super::common::Node;
use super::script::Script;
use crate::text::Use as TextUse;
use crate::ScriptError;
use crate::{path::Path, ScriptResult};
use melodium_common::descriptor::{Identifier, IdentifierRequirement, Version, VersionReq};
use std::collections::HashMap;
use std::sync::{Arc, RwLock, Weak};
/// Structure managing and describing semantic of a use.
///
/// It owns the whole [text use](Use).
#[derive(Debug, Clone)]
pub struct Use {
pub text: TextUse,
pub script: Weak<RwLock<Script>>,
pub path: Path,
pub element: String,
pub r#as: String,
pub identifier: Option<IdentifierRequirement>,
}
impl Use {
/// Create a new semantic use, based on textual use.
///
/// * `script`: the parent script that "owns" this use.
/// * `text`: the textual use.
///
/// # Note
/// Only parent-child relationships are made at this step. Other references can be made afterwards using the [Node trait](Node).
///
pub fn new(
script: Arc<RwLock<Script>>,
text: TextUse,
version: Version,
) -> ScriptResult<Arc<RwLock<Self>>> {
let mut result = ScriptResult::new_success(());
let r#as;
if let Some(ps) = text.r#as.clone() {
r#as = ps;
} else {
r#as = text.element.clone();
}
{
let borrowed_script = script.read().unwrap();
let r#use = borrowed_script.find_use(&r#as.string);
if r#use.is_some() {
result = result.and_degrade_failure(ScriptResult::new_failure(
ScriptError::already_used_name(108, r#as.clone()),
));
}
}
let path = Path::new(
version,
text.path.iter().map(|i| i.string.clone()).collect(),
);
result.and_then(|_| {
ScriptResult::new_success(Arc::<RwLock<Self>>::new(RwLock::new(Self {
script: Arc::downgrade(&script),
path,
element: text.element.string.clone(),
r#as: r#as.string.clone(),
text,
identifier: None,
})))
})
}
}
impl Node for Use {
fn make_references(
&mut self,
path: &Path,
versions: &HashMap<String, VersionReq>,
) -> ScriptResult<()> {
if !self.path.is_valid() {
ScriptResult::new_failure(ScriptError::invalid_root(
107,
self.text.element.clone(),
self.path.root(),
))
} else {
match self.path.root().as_str() {
"root" => {
// "Root" package case
let mut steps = vec![path.root()];
self.path
.path()
.iter()
.skip(1)
.for_each(|s| steps.push(s.clone()));
self.identifier = Some(
(&Identifier::new_versionned(path.version(), steps, &self.element)).into(),
);
ScriptResult::new_success(())
}
"local" => {
// "Local" case
let mut steps = path.path().clone();
self.path
.path()
.iter()
.skip(1)
.for_each(|s| steps.push(s.clone()));
self.identifier = Some(
(&Identifier::new_versionned(path.version(), steps, &self.element)).into(),
);
ScriptResult::new_success(())
}
_ => {
// "Non-local" case
if let Some(version_req) = versions.get(&self.path.root()).cloned() {
self.identifier = Some(IdentifierRequirement::new(
version_req,
self.path.path().clone(),
&self.element,
));
ScriptResult::new_success(())
} else {
ScriptResult::new_failure(ScriptError::unexisting_dependency(
184,
self.text.element.clone(),
self.path.root(),
))
}
}
}
}
}
}