use std::{collections::HashMap, collections::VecDeque, num::ParseFloatError};
use crate::{
context::Function,
parser::{Command, CommandType},
};
#[derive(Clone, Debug)]
pub struct Scope<'a> {
pub(crate) parent: Option<&'a Scope<'a>>,
pub(crate) functions: HashMap<String, Function>,
// TODO: Use a weakref here for less cloning.
pub(crate) list: Vec<String>,
pub(crate) commands: VecDeque<Command>,
}
impl Scope<'_> {
pub(crate) fn child(&self, commands: Vec<Command>) -> Scope {
let body;
if let Some(command) = commands.first() {
if let CommandType::Chain(c) = &command.kind {
body = c
} else {
body = &commands
}
} else {
body = &commands
}
Scope {
parent: Some(self),
functions: HashMap::new(),
list: vec![],
commands: VecDeque::from(body.clone()),
}
}
pub(crate) fn as_numbers(&mut self) -> Result<Vec<f64>, String> {
self.list
.iter()
.map(|a| a.parse::<f64>())
.collect::<Result<Vec<f64>, ParseFloatError>>()
// TODO: Add function name, parameter index and name to error.
.map_err(|_| "Couldn't parse numbers".to_string())
}
pub(crate) fn get_arg(&mut self) -> Option<Command> {
self.commands.pop_front()
}
pub(crate) fn get_func(&self, name: &str) -> Option<&Function> {
self.functions.get(name)
}
pub fn new() -> Self {
Scope {
functions: HashMap::new(),
list: Vec::new(),
parent: None,
commands: VecDeque::new(),
}
}
}
impl Default for Scope<'_> {
fn default() -> Self {
Scope::new()
}
}