clash_brush_core/shell/
callstack.rs1use crate::{ExecutionParameters, callstack, env, error, functions, trace_categories};
4
5impl<SE: crate::extensions::ShellExtensions> crate::Shell<SE> {
6 pub fn in_sourced_script(&self) -> bool {
8 self.call_stack.in_sourced_script()
9 }
10
11 pub fn in_function(&self) -> bool {
13 self.call_stack.in_function()
14 }
15
16 pub fn start_interactive_session(&mut self) -> Result<(), error::Error> {
19 self.call_stack.push_interactive_session();
20 Ok(())
21 }
22
23 pub fn end_interactive_session(&mut self) -> Result<(), error::Error> {
26 if self
27 .call_stack
28 .current_frame()
29 .is_none_or(|frame| !frame.frame_type.is_interactive_session())
30 {
31 return Err(error::ErrorKind::NotInInteractiveSession.into());
32 }
33
34 self.call_stack.pop();
35
36 Ok(())
37 }
38
39 pub fn start_command_string_mode(&mut self) {
42 self.call_stack.push_command_string();
43 }
44
45 pub fn end_command_string_mode(&mut self) -> Result<(), error::Error> {
48 if self
49 .call_stack
50 .current_frame()
51 .is_none_or(|frame| !frame.frame_type.is_command_string())
52 {
53 return Err(error::ErrorKind::NotExecutingCommandString.into());
54 }
55
56 self.call_stack.pop();
57
58 Ok(())
59 }
60
61 pub(crate) fn enter_trap_handler(&mut self, handler: Option<&crate::traps::TrapHandler>) {
62 self.call_stack.push_trap_handler(handler);
63 }
64
65 pub(crate) fn leave_trap_handler(&mut self) {
66 self.call_stack.pop();
67 }
68
69 pub(crate) fn enter_function(
79 &mut self,
80 name: &str,
81 function: &functions::Registration,
82 args: impl IntoIterator<Item = String>,
83 _params: &ExecutionParameters,
84 ) -> Result<(), error::Error> {
85 if let Some(max_call_depth) = self.options.max_function_call_depth
86 && self.call_stack.function_call_depth() >= max_call_depth
87 {
88 return Err(error::ErrorKind::MaxFunctionCallDepthExceeded.into());
89 }
90
91 if tracing::enabled!(target: trace_categories::FUNCTIONS, tracing::Level::DEBUG) {
92 let depth = self.call_stack.function_call_depth();
93 let prefix = repeated_char_str(' ', depth);
94 tracing::debug!(target: trace_categories::FUNCTIONS, "Entering func [depth={depth}]: {prefix}{name}");
95 }
96
97 self.call_stack.push_function(name, function, args);
98 self.env.push_scope(env::EnvironmentScope::Local);
99
100 Ok(())
101 }
102
103 pub(crate) fn leave_function(&mut self) -> Result<(), error::Error> {
106 self.env.pop_scope(env::EnvironmentScope::Local)?;
107
108 if let Some(exited_call) = self.call_stack.pop() {
109 if let callstack::FrameType::Function(func_call) = exited_call.frame_type {
110 if tracing::enabled!(target: trace_categories::FUNCTIONS, tracing::Level::DEBUG) {
111 let depth = self.call_stack.function_call_depth();
112 let prefix = repeated_char_str(' ', depth);
113 tracing::debug!(target: trace_categories::FUNCTIONS, "Exiting func [depth={depth}]: {prefix}{}", func_call.function_name);
114 }
115 } else {
116 let err: error::Error =
117 error::ErrorKind::InternalError("mismatched call stack state".to_owned())
118 .into();
119 return Err(err.into_fatal());
120 }
121 }
122
123 Ok(())
124 }
125
126 pub fn current_shell_args(&self) -> &[String] {
129 for frame in self.call_stack.iter() {
130 match frame.frame_type {
131 crate::callstack::FrameType::Function(..) => return &frame.args,
133 _ if frame.frame_type.is_run_script() => return &frame.args,
135 _ if frame.frame_type.is_sourced_script() => {
137 if !frame.args.is_empty() {
138 return &frame.args;
139 }
140 }
141 _ => (),
142 }
143 }
144
145 self.args.as_slice()
146 }
147
148 pub fn current_shell_args_mut(&mut self) -> &mut Vec<String> {
151 for frame in self.call_stack.iter_mut() {
152 match frame.frame_type {
153 crate::callstack::FrameType::Function(..) => return &mut frame.args,
155 _ if frame.frame_type.is_run_script() => return &mut frame.args,
157 _ if frame.frame_type.is_sourced_script() => {
159 if !frame.args.is_empty() {
160 return &mut frame.args;
161 }
162 }
163 _ => (),
164 }
165 }
166
167 &mut self.args
168 }
169}
170
171fn repeated_char_str(c: char, count: usize) -> String {
172 (0..count).map(|_| c).collect()
173}