Skip to main content

r/interpreter/builtins/
args.rs

1//! Shared decoding helpers for builtin positional and named arguments.
2
3use crate::interpreter::environment::Environment;
4use crate::interpreter::value::{RError, RErrorKind, RValue};
5
6pub(crate) struct CallArgs<'a> {
7    positional: &'a [RValue],
8    named: &'a [(String, RValue)],
9}
10
11impl<'a> CallArgs<'a> {
12    pub(crate) fn new(positional: &'a [RValue], named: &'a [(String, RValue)]) -> Self {
13        Self { positional, named }
14    }
15
16    pub(crate) fn positional(&self, index: usize) -> Option<&'a RValue> {
17        self.positional.get(index)
18    }
19
20    pub(crate) fn named(&self, name: &str) -> Option<&'a RValue> {
21        self.named
22            .iter()
23            .find(|(candidate, _)| candidate == name)
24            .map(|(_, value)| value)
25    }
26
27    pub(crate) fn value(&self, name: &str, position: usize) -> Option<&'a RValue> {
28        self.named(name).or_else(|| self.positional(position))
29    }
30
31    pub(crate) fn string(&self, name: &str, position: usize) -> Result<String, RError> {
32        self.value(name, position)
33            .and_then(|value| value.as_vector()?.as_character_scalar())
34            .ok_or_else(|| RError::new(RErrorKind::Argument, format!("invalid '{name}' argument")))
35    }
36
37    pub(crate) fn optional_string(&self, name: &str, position: usize) -> Option<String> {
38        self.value(name, position)
39            .and_then(|value| value.as_vector()?.as_character_scalar())
40    }
41
42    pub(crate) fn named_string(&self, name: &str) -> Option<String> {
43        self.named(name)
44            .and_then(|value| value.as_vector()?.as_character_scalar())
45    }
46
47    pub(crate) fn logical_flag(&self, name: &str, position: usize, default: bool) -> bool {
48        self.value(name, position)
49            .and_then(|value| value.as_vector()?.as_logical_scalar())
50            .unwrap_or(default)
51    }
52
53    pub(crate) fn integer_or(&self, name: &str, position: usize, default: i64) -> i64 {
54        self.value(name, position)
55            .and_then(|value| value.as_vector()?.as_integer_scalar())
56            .unwrap_or(default)
57    }
58
59    pub(crate) fn environment_or(
60        &self,
61        name: &str,
62        position: usize,
63        default: &Environment,
64    ) -> Result<Environment, RError> {
65        match self.value(name, position) {
66            Some(RValue::Environment(env)) => Ok(env.clone()),
67            Some(_) => Err(RError::new(
68                RErrorKind::Argument,
69                format!("invalid '{name}' argument"),
70            )),
71            None => Ok(default.clone()),
72        }
73    }
74}