procc_ll/
context.rs

1use std::cell::RefCell;
2use std::collections::HashMap;
3use std::rc::Rc;
4use std::sync::Arc;
5use crate::token::Token;
6use crate::Program;
7use crate::Values;
8/// structure that contains all the data at the count level, saves the variables, tokens, functions and keys
9/// Use example :
10/// ```
11///  use procc_ll::context::Context;
12///  let mut context = Context::new();
13///  context.push_key("key".to_owned(), |token, prog| {
14///     prog.exec(&token);
15///     procc_ll::Values::Null
16///  });
17/// ```
18#[derive(Clone)]
19pub struct Context {
20    pub(crate) tokens: Rc<RefCell<Vec<Rc<RefCell<Box<dyn Token + 'static>>>>>>,
21    pub(crate) functions: Rc<RefCell<HashMap<String, Arc<dyn Fn(Vec<Values>, &mut Program) -> Values>>>>,
22    pub(crate) memory: Rc<RefCell<HashMap<String , Values>>>,
23    pub(crate) keys: Rc<RefCell<HashMap<String, Arc<dyn Fn(String, &mut Program) -> Values>>>>,
24    pub(crate) sub_context: Option<Box<Context>>
25}
26
27impl Context {
28    /// Create a new instance of Context
29    pub fn new<'b>() -> Context {
30        Context {
31            tokens: Rc::new(RefCell::new(Vec::new())),
32            memory: Rc::new(RefCell::new(HashMap::new())),
33            keys: Rc::new(RefCell::new(HashMap::new())),
34            functions: Rc::new(RefCell::new(HashMap::new())),
35            sub_context: None
36        }
37    }
38    /// Localize the index in the list of tokens of the token
39    ///
40    /// # PANICS
41    /// Return a panic if the token is not registered on the context
42    pub fn token_index(&self, tok: &str) -> Option<usize> {
43        for ix in 0..self.tokens.borrow().len() {
44            let def_tok = &self.tokens.borrow()[ix];
45            if def_tok.borrow().is_token(&tok) { return Some(ix); }
46        }
47        None
48    }
49    /// Register a new token in te context
50    pub fn push_token(&mut self, tok: Box<dyn Token>) {
51        self.tokens.borrow_mut().push(Rc::new(RefCell::new(tok)));
52    }
53    /// Push a new data on the memory
54    pub fn push_memory(&mut self, key: &str, tok: Values) {
55        if !self.memory.borrow().contains_key(key) {
56            if let Some(subc) = &mut self.sub_context {
57                subc.push_memory(key, tok);
58                return;
59            }
60        }
61        self.memory.borrow_mut().insert(key.to_owned(),tok);
62    }
63    /// Register a new key
64    pub fn push_key(&mut self, key: String, tok: impl Fn(String, &mut Program) -> Values + 'static) {
65        self.keys.borrow_mut().insert(key, Arc::new(tok));
66    }
67    /// Add a new function
68    pub fn push_function(&mut self, name: String, func: impl Fn(Vec<Values>, &mut Program) -> Values + 'static) {
69        if let Some(subc) = &mut self.sub_context {
70            if !self.functions.borrow().contains_key(&name) {
71                subc.push_function(name, func);
72                return;
73            }
74        }
75        self.functions.borrow_mut().insert(name, Arc::new(func));
76    }
77    pub fn get_token(&self, idx: usize) -> Rc<RefCell<Box<dyn Token + 'static>>> {
78        self.tokens.borrow().get(idx).unwrap().clone()
79    }
80    pub fn get_memory(&self, key: &str) -> Values {
81        if !self.memory.borrow().contains_key(key) {
82            if let Some(subc) = &self.sub_context {
83                if subc.memory.borrow().contains_key(key) {
84                    return subc.get_memory(key);
85                } else {
86                    panic!("Memory \"{}\" no longer exists", key);
87                }
88            } else {
89                panic!("Memory {} not pushed", key);
90            }
91        }
92        self.memory.borrow().get(key).unwrap().clone()
93    }
94    pub fn get_key(&self, key: &str) -> Arc<dyn Fn(String, &mut Program) -> Values> {
95        self.keys.borrow().get(key).unwrap().clone()
96    }
97    pub fn get_function(&self, key: &str) -> Arc<dyn Fn(Vec<Values>, &mut Program) -> Values> {
98        if !self.functions.borrow().contains_key(key) {
99            if let Some(subc) = &self.sub_context {
100                if subc.functions.borrow().contains_key(key) {
101                    return subc.get_function(key);
102                } else {
103                    panic!("Function \"{}\" no longer exists", key);
104                }
105            } else {
106                panic!("Function {} not pushed", key);
107            }
108        }
109        self.functions.borrow().get(key).unwrap().clone()
110    }
111
112
113    pub fn has_token(&self, idx: usize) -> bool {
114        self.tokens.borrow().len() > idx
115    }
116    pub fn has_memory(&self, key: &str) -> bool {
117        let has_sub_context = {
118            if let Some(subc) = &self.sub_context {
119                subc.has_memory(key)
120            } else {
121                false
122            }
123        };
124        self.memory.borrow().contains_key(key) || has_sub_context
125    }
126    pub fn has_key(&self, key: &str) -> bool {
127        self.keys.borrow().contains_key(key)
128    }
129    pub fn has_function(&self, key: &str) -> bool {
130        let has_sub_context = {
131            if let Some(subc) = &self.sub_context {
132                subc.has_function(key)
133            } else {
134                false
135            }
136        };
137        self.functions.borrow().contains_key(key) || has_sub_context
138    }
139
140    pub fn gifs_token(&self, idx: usize) -> Option<Rc<RefCell<Box<dyn Token + 'static>>>> {
141        if self.has_token(idx) {
142           Some(self.get_token(idx))
143        } else { None }
144    }
145    pub fn gifs_memory(&self, key: &str) -> Option<Values> {
146        if self.has_memory(key) {
147            Some(self.get_memory(key))
148        } else { None }
149    }
150    pub fn gifs_key(&self, key: &str) -> Option<Arc<dyn Fn(String, &mut Program) -> Values>> {
151        if self.has_memory(key) {
152            Some(self.get_key(key))
153        } else { None }
154    }
155    pub fn gifs_function(&self, key: &str) -> Option<Arc<dyn Fn(String, &mut Program) -> Values>> {
156        if self.has_memory(key) {
157            Some(self.get_key(key))
158        } else { None }
159    }
160}