Skip to main content

r/interpreter/
control_flow.rs

1//! Control-flow and namespace evaluation helpers.
2
3use crate::interpreter::environment::Environment;
4use crate::interpreter::value::*;
5use crate::interpreter::Interpreter;
6use crate::parser::ast::Expr;
7
8impl Interpreter {
9    pub(super) fn eval_pipe(
10        &self,
11        lhs: &Expr,
12        rhs: &Expr,
13        env: &Environment,
14    ) -> Result<RValue, RFlow> {
15        let left_val = self.eval_in(lhs, env)?;
16        match rhs {
17            Expr::Call { func, args, .. } => {
18                let f = self.eval_in(func, env)?;
19
20                // Check if any argument uses `_` or `.` as a placeholder for the LHS.
21                // `_` is R 4.2+ native pipe syntax; `.` is magrittr compatibility.
22                let is_placeholder = |s: &str| s == "_" || s == ".";
23                let has_placeholder = args.iter().any(|arg| {
24                    matches!(
25                        &arg.value,
26                        Some(Expr::Symbol(s)) if is_placeholder(s)
27                    )
28                });
29
30                let mut eval_args = Vec::new();
31                let mut named_args = Vec::new();
32
33                if has_placeholder {
34                    // Replace `_` with the LHS value
35                    for arg in args {
36                        if let Some(name) = &arg.name {
37                            if let Some(val_expr) = &arg.value {
38                                let val = if matches!(val_expr, Expr::Symbol(s) if is_placeholder(s))
39                                {
40                                    left_val.clone()
41                                } else {
42                                    self.eval_in(val_expr, env)?
43                                };
44                                named_args.push((name.clone(), val));
45                            }
46                        } else if let Some(val_expr) = &arg.value {
47                            let val = if matches!(val_expr, Expr::Symbol(s) if is_placeholder(s)) {
48                                left_val.clone()
49                            } else {
50                                self.eval_in(val_expr, env)?
51                            };
52                            eval_args.push(val);
53                        }
54                    }
55                } else {
56                    // No placeholder — prepend LHS as first positional arg (R 4.1 behavior)
57                    eval_args.push(left_val);
58                    for arg in args {
59                        if let Some(name) = &arg.name {
60                            if let Some(val_expr) = &arg.value {
61                                named_args.push((name.clone(), self.eval_in(val_expr, env)?));
62                            }
63                        } else if let Some(val_expr) = &arg.value {
64                            eval_args.push(self.eval_in(val_expr, env)?);
65                        }
66                    }
67                }
68
69                self.call_function(&f, &eval_args, &named_args, env)
70            }
71            Expr::Symbol(name) => {
72                let f = env
73                    .get(name)
74                    .ok_or_else(|| RError::new(RErrorKind::Name, name.clone()))?;
75                self.call_function(&f, &[left_val], &[], env)
76            }
77            _ => Err(RError::other("invalid use of pipe".to_string()).into()),
78        }
79    }
80
81    pub(super) fn eval_if(
82        &self,
83        condition: &Expr,
84        then_body: &Expr,
85        else_body: Option<&Expr>,
86        env: &Environment,
87    ) -> Result<RValue, RFlow> {
88        let cond = self.eval_in(condition, env)?;
89        let test = match &cond {
90            RValue::Vector(v) => v.as_logical_scalar(),
91            _ => None,
92        };
93        match test {
94            Some(true) => self.eval_in(then_body, env),
95            Some(false) | None => {
96                if let Some(else_expr) = else_body {
97                    self.eval_in(else_expr, env)
98                } else {
99                    Ok(RValue::Null)
100                }
101            }
102        }
103    }
104
105    pub(super) fn eval_while(
106        &self,
107        condition: &Expr,
108        body: &Expr,
109        env: &Environment,
110    ) -> Result<RValue, RFlow> {
111        loop {
112            self.check_interrupt()?;
113            let cond = self.eval_in(condition, env)?;
114            let test = match &cond {
115                RValue::Vector(v) => v.as_logical_scalar().unwrap_or(false),
116                _ => false,
117            };
118            if !test {
119                break;
120            }
121            match self.eval_in(body, env) {
122                Err(RFlow::Signal(RSignal::Break)) => break,
123                Err(RFlow::Signal(RSignal::Next)) => continue,
124                Err(err) => return Err(err),
125                _ => {}
126            }
127        }
128        Ok(RValue::Null)
129    }
130
131    pub(super) fn eval_repeat(&self, body: &Expr, env: &Environment) -> Result<RValue, RFlow> {
132        loop {
133            self.check_interrupt()?;
134            match self.eval_in(body, env) {
135                Err(RFlow::Signal(RSignal::Break)) => break,
136                Err(RFlow::Signal(RSignal::Next)) => continue,
137                Err(err) => return Err(err),
138                _ => {}
139            }
140        }
141        Ok(RValue::Null)
142    }
143
144    pub(super) fn eval_ns_get(
145        &self,
146        namespace: &Expr,
147        name: &str,
148        env: &Environment,
149    ) -> Result<RValue, RFlow> {
150        // Extract namespace name from the expression
151        let ns_name = match namespace {
152            crate::parser::ast::Expr::Symbol(s) => s.as_str(),
153            _ => "",
154        };
155
156        if !ns_name.is_empty() {
157            // Check loaded package namespaces first (for pkg::name resolution)
158            {
159                let loaded = self.loaded_namespaces.borrow();
160                if let Some(ns) = loaded.get(ns_name) {
161                    // For :: use exports env, for ::: use namespace env
162                    // (both NsGet and NsGetInt come through here; NsGetInt
163                    // is internal access but we don't distinguish yet)
164                    if let Some(val) = ns.exports_env.get(name) {
165                        return Ok(val);
166                    }
167                    if let Some(val) = ns.namespace_env.get(name) {
168                        return Ok(val);
169                    }
170                }
171            }
172
173            // Try to auto-load the namespace if not loaded yet
174            if self.find_package_dir(ns_name).is_some() {
175                if let Ok(_ns_env) = self.load_namespace(ns_name) {
176                    let loaded = self.loaded_namespaces.borrow();
177                    if let Some(ns) = loaded.get(ns_name) {
178                        if let Some(val) = ns.exports_env.get(name) {
179                            return Ok(val);
180                        }
181                        if let Some(val) = ns.namespace_env.get(name) {
182                            return Ok(val);
183                        }
184                    }
185                }
186            }
187
188            // Check builtin registry for namespace::name
189            if let Some(descriptor) = crate::interpreter::builtins::find_builtin_ns(ns_name, name) {
190                return Ok(RValue::Function(RFunction::Builtin {
191                    name: descriptor.name.to_string(),
192                    implementation: descriptor.implementation,
193                    min_args: descriptor.min_args,
194                    max_args: descriptor.max_args,
195                    formals: descriptor.formals,
196                }));
197            }
198        }
199
200        // Fall back to environment lookup
201        env.get(name)
202            .or_else(|| self.global_env.get(name))
203            .ok_or_else(|| RError::new(RErrorKind::Name, format!("{}::{}", ns_name, name)).into())
204    }
205
206    pub(super) fn eval_for(
207        &self,
208        var: &str,
209        iter_val: &RValue,
210        body: &Expr,
211        env: &Environment,
212    ) -> Result<RValue, RFlow> {
213        match iter_val {
214            RValue::Vector(v) => {
215                let len = v.len();
216                for i in 0..len {
217                    self.check_interrupt()?;
218                    let elem = match &v.inner {
219                        Vector::Raw(vals) => RValue::vec(Vector::Raw(vec![vals[i]])),
220                        Vector::Double(vals) => {
221                            RValue::vec(Vector::Double(vec![vals.get_opt(i)].into()))
222                        }
223                        Vector::Integer(vals) => {
224                            RValue::vec(Vector::Integer(vec![vals.get_opt(i)].into()))
225                        }
226                        Vector::Logical(vals) => RValue::vec(Vector::Logical(vec![vals[i]].into())),
227                        Vector::Complex(vals) => RValue::vec(Vector::Complex(vec![vals[i]].into())),
228                        Vector::Character(vals) => {
229                            RValue::vec(Vector::Character(vec![vals[i].clone()].into()))
230                        }
231                    };
232                    env.set(var.to_string(), elem);
233                    match self.eval_in(body, env) {
234                        Ok(_) => {}
235                        Err(RFlow::Signal(RSignal::Next)) => continue,
236                        Err(RFlow::Signal(RSignal::Break)) => break,
237                        Err(err) => return Err(err),
238                    }
239                }
240            }
241            RValue::List(list) => {
242                for (_, val) in &list.values {
243                    self.check_interrupt()?;
244                    env.set(var.to_string(), val.clone());
245                    match self.eval_in(body, env) {
246                        Ok(_) => {}
247                        Err(RFlow::Signal(RSignal::Next)) => continue,
248                        Err(RFlow::Signal(RSignal::Break)) => break,
249                        Err(err) => return Err(err),
250                    }
251                }
252            }
253            RValue::Null => {}
254            _ => {
255                return Err(RError::new(
256                    RErrorKind::Type,
257                    "invalid for() loop sequence".to_string(),
258                )
259                .into());
260            }
261        }
262        Ok(RValue::Null)
263    }
264}