yash_builtin/typeset/
set_functions.rs1use super::*;
18use std::rc::Rc;
19use yash_env::function::FunctionSet;
20
21impl SetFunctions {
22 pub fn execute<S>(self, functions: &mut FunctionSet<S>) -> Result<String, Vec<ExecuteError>> {
24 let mut errors = Vec::new();
25
26 for name in self.functions {
27 for &(attr, state) in &self.attrs {
28 match (attr, state) {
29 (FunctionAttr::ReadOnly, State::On) => {
30 match functions.unset(&name.value) {
31 Ok(None) => {
32 errors.push(ExecuteError::ModifyUnsetFunction(name.clone()));
33 }
34
35 Err(_) => { }
36
37 Ok(Some(mut function)) => {
38 Rc::make_mut(&mut function).read_only_location =
39 Some(name.origin.clone());
40 let define_result = functions.define(function);
41 debug_assert!(
45 define_result.is_ok(),
46 "the function should be defined successfully: {define_result:?}"
47 );
48 }
49 }
50 }
51
52 (FunctionAttr::ReadOnly, State::Off) => match functions.get(&name.value) {
53 None => errors.push(ExecuteError::ModifyUnsetFunction(name.clone())),
54
55 Some(function) => {
56 if let Some(read_only_location) = function.read_only_location.clone() {
57 errors.push(ExecuteError::UndoReadOnlyFunction(
58 UndoReadOnlyError {
59 name: name.clone(),
60 read_only_location,
61 },
62 ));
63 }
64 }
65 },
66 }
67 }
68 }
69
70 if errors.is_empty() {
71 Ok(String::new())
72 } else {
73 Err(errors)
74 }
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81 use assert_matches::assert_matches;
82 use yash_env::function::Function;
83 use yash_env::test_helper::function::FunctionBodyStub;
84
85 #[test]
86 fn making_existing_functions_readonly() {
87 let mut functions = FunctionSet::<()>::new();
88 let foo = Function::new(
89 "foo",
90 FunctionBodyStub::rc_dyn(),
91 Location::dummy("foo location"),
92 );
93 let bar = Function::new(
94 "bar",
95 FunctionBodyStub::rc_dyn(),
96 Location::dummy("bar location"),
97 )
98 .make_read_only(Location::dummy("bar readonly location"));
99 functions.define(foo.clone()).unwrap();
100 functions.define(bar.clone()).unwrap();
101 let sf = SetFunctions {
102 functions: Field::dummies(["foo", "bar"]),
103 attrs: vec![(FunctionAttr::ReadOnly, State::On)],
104 };
105 let foo_location = sf.functions[0].origin.clone();
106
107 let result = sf.execute(&mut functions);
108
109 assert_eq!(result, Ok("".to_string()));
110 assert_eq!(
111 **functions.get("foo").unwrap(),
112 foo.make_read_only(foo_location),
113 );
114 assert_eq!(**functions.get("bar").unwrap(), bar);
116 }
117
118 #[test]
119 fn unsetting_readonly_attribute_of_existing_functions() {
120 let mut functions = FunctionSet::<()>::new();
121 let foo = Function::new(
122 "foo",
123 FunctionBodyStub::rc_dyn(),
124 Location::dummy("foo location"),
125 );
126 let bar_location = Location::dummy("bar readonly location");
127 let bar = Function::new(
128 "bar",
129 FunctionBodyStub::rc_dyn(),
130 Location::dummy("bar location"),
131 )
132 .make_read_only(bar_location.clone());
133 functions.define(foo.clone()).unwrap();
134 functions.define(bar.clone()).unwrap();
135 let sf = SetFunctions {
136 functions: Field::dummies(["foo", "bar"]),
137 attrs: vec![(FunctionAttr::ReadOnly, State::Off)],
138 };
139 let arg_bar = sf.functions[1].clone();
140
141 let errors = sf.execute(&mut functions).unwrap_err();
142
143 assert_matches!(&errors[..], [ExecuteError::UndoReadOnlyFunction(error)] => {
144 assert_eq!(error.name, arg_bar);
145 assert_eq!(error.read_only_location, bar_location);
146 });
147 assert_eq!(**functions.get("foo").unwrap(), foo);
148 assert_eq!(**functions.get("bar").unwrap(), bar);
149 }
150
151 #[test]
152 fn making_non_existing_function_readonly() {
153 let mut functions = FunctionSet::<()>::new();
154 let sf = SetFunctions {
155 functions: Field::dummies(["foo"]),
156 attrs: vec![(FunctionAttr::ReadOnly, State::On)],
157 };
158 let arg_foo = sf.functions[0].clone();
159
160 let errors = sf.execute(&mut functions).unwrap_err();
161
162 assert_eq!(errors, [ExecuteError::ModifyUnsetFunction(arg_foo)]);
163 assert_eq!(functions.len(), 0);
164 }
165
166 #[test]
167 fn unsetting_readonly_attribute_of_non_existing_functions() {
168 let mut functions = FunctionSet::<()>::new();
169 let sf = SetFunctions {
170 functions: Field::dummies(["foo"]),
171 attrs: vec![(FunctionAttr::ReadOnly, State::Off)],
172 };
173 let arg_foo = sf.functions[0].clone();
174
175 let errors = sf.execute(&mut functions).unwrap_err();
176
177 assert_eq!(errors, [ExecuteError::ModifyUnsetFunction(arg_foo)]);
178 assert_eq!(functions.len(), 0);
179 }
180}