stuart_core/functions/parsers/
ifdefined.rs1use crate::functions::{Function, FunctionParser};
2use crate::parse::{ParseError, RawFunction};
3use crate::process::stack::StackFrame;
4use crate::process::{ProcessError, Scope};
5use crate::{quiet_assert, TracebackError};
6
7use humphrey_json::Value;
8
9pub struct IfDefinedParser;
11
12#[derive(Debug, Clone)]
13pub struct IfDefinedFunction {
14 variable_name: String,
15}
16
17impl FunctionParser for IfDefinedParser {
18 fn name(&self) -> &'static str {
19 "ifdefined"
20 }
21
22 fn parse(&self, raw: RawFunction) -> Result<Box<dyn Function>, ParseError> {
23 quiet_assert!(raw.positional_args.len() == 1)?;
24 quiet_assert!(raw.named_args.is_empty())?;
25
26 let variable_name = raw.positional_args[0]
27 .as_variable()
28 .ok_or(ParseError::InvalidArgument)?;
29
30 Ok(Box::new(IfDefinedFunction {
31 variable_name: variable_name.to_string(),
32 }))
33 }
34}
35
36impl Function for IfDefinedFunction {
37 fn name(&self) -> &'static str {
38 "ifdefined"
39 }
40
41 fn execute(&self, scope: &mut Scope) -> Result<(), TracebackError<ProcessError>> {
42 let self_token = scope.tokens.current().unwrap().clone();
43
44 let mut defined = scope
45 .get_variable(&self.variable_name)
46 .map(|v| !matches!(v, Value::Null))
47 .unwrap_or(false);
48
49 let frame = StackFrame::new(format!("ifdefined:{}", self.variable_name));
50
51 let stack_height = scope.stack.len();
52 scope.stack.push(frame);
53
54 while scope.stack.len() > stack_height {
55 let token = scope
56 .tokens
57 .next()
58 .ok_or_else(|| self_token.traceback(ProcessError::UnexpectedEndOfFile))?;
59
60 let function_name = token.as_function().map(|f| f.name().to_string());
61
62 if defined
63 || ((function_name == Some("end".to_string())
64 || function_name == Some("else".to_string()))
65 && scope.stack.len() == stack_height + 1)
66 {
67 token.process(scope)?;
68
69 if function_name == Some("else".to_string()) {
70 defined = !defined;
71 }
72 }
73 }
74
75 Ok(())
76 }
77}