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
//! Function support for shells.
use crate::{
ExecutionParameters, commands, error, extensions, functions, results::ExecutionWaitResult,
};
impl<SE: extensions::ShellExtensions> crate::Shell<SE> {
/// Returns the function definition environment for this shell.
pub const fn funcs(&self) -> &functions::FunctionEnv {
&self.funcs
}
/// Returns a mutable reference to the function definition environment for this shell.
pub const fn funcs_mut(&mut self) -> &mut functions::FunctionEnv {
&mut self.funcs
}
/// Tries to undefine a function in the shell's environment. Returns whether or
/// not a definition was removed.
///
/// # Arguments
///
/// * `name` - The name of the function to undefine.
pub fn undefine_func(&mut self, name: &str) -> bool {
self.funcs.remove(name).is_some()
}
/// Defines a function in the shell's environment. If a function already exists
/// with the given name, it is replaced with the new definition.
///
/// # Arguments
///
/// * `name` - The name of the function to define.
/// * `definition` - The function's definition.
/// * `source_info` - Source information for the function definition.
pub fn define_func(
&mut self,
name: impl Into<String>,
definition: brush_parser::ast::FunctionDefinition,
source_info: &crate::SourceInfo,
) {
let reg = functions::Registration::new(definition, source_info);
self.funcs.update(name.into(), reg);
}
/// Tries to return a mutable reference to the registration for a named function.
/// Returns `None` if no such function was found.
///
/// # Arguments
///
/// * `name` - The name of the function to lookup
pub fn func_mut(&mut self, name: &str) -> Option<&mut functions::Registration> {
self.funcs.get_mut(name)
}
/// Tries to define a function in the shell's environment using the given
/// string as its body.
///
/// # Arguments
///
/// * `name` - The name of the function
/// * `body_text` - The body of the function, expected to start with "()".
pub fn define_func_from_str(
&mut self,
name: impl Into<String>,
body_text: &str,
) -> Result<(), error::Error> {
let name = name.into();
let mut parser =
super::parsing::create_parser(body_text.as_bytes(), &self.parser_options());
let func_body = parser.parse_function_parens_and_body().map_err(|e| {
error::Error::from(error::ErrorKind::FunctionParseError(name.clone(), e))
})?;
let def = brush_parser::ast::FunctionDefinition {
fname: name.clone().into(),
body: func_body,
};
self.define_func(name, def, &crate::SourceInfo::default());
Ok(())
}
/// Invokes a function defined in this shell, returning the resulting exit status.
///
/// # Arguments
///
/// * `name` - The name of the function to invoke.
/// * `args` - The arguments to pass to the function.
/// * `params` - Execution parameters to use for the invocation.
pub async fn invoke_function<N: AsRef<str>, I: IntoIterator<Item = A>, A: AsRef<str>>(
&mut self,
name: N,
args: I,
params: &ExecutionParameters,
) -> Result<u8, error::Error> {
let name = name.as_ref();
let command_name = String::from(name);
let func_registration = self
.funcs
.get(name)
.ok_or_else(|| error::ErrorKind::FunctionNotFound(name.to_owned()))?
.to_owned();
let context = commands::ExecutionContext {
shell: self,
command_name,
params: params.clone(),
};
let command_args = args
.into_iter()
.map(|s| commands::CommandArg::String(String::from(s.as_ref())))
.collect::<Vec<_>>();
let result =
commands::invoke_shell_function(func_registration, context, &command_args).await?;
match result.wait().await? {
ExecutionWaitResult::Completed(result) => Ok(result.exit_code.into()),
ExecutionWaitResult::Stopped(..) => {
error::unimp("stopped child from function invocation")
}
}
}
}