use std::cell::RefCell;
use std::rc::Rc;
use log::debug;
use regex::Regex;
use crate::context::Context;
use crate::token::Token;
use crate::values::Values;
pub mod context;
pub mod values;
pub mod token;
#[cfg(test)]
mod tests;
#[macro_export]
macro_rules! measure_time_debug {
($expression:expr) => {{
use std::time::Instant;
let start = Instant::now();
let result = $expression; let duration = start.elapsed();
debug!("Run Time: {:?}", duration);
result }};
}
#[macro_export]
macro_rules! measure_time {
($expression:expr) => {{
use std::time::Instant;
let start = Instant::now();
let result = $expression; let duration = start.elapsed();
println!("Run Time: {:?}", duration);
result }};
}
lazy_static::lazy_static! {
static ref FUNC_REGEX: Regex = Regex::new(r"(.+)\((.+)\)").unwrap();
}
#[derive(Clone)]
pub struct Program {
pub context: crate::context::Context,
}
impl Program {
pub fn new() -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(Program { context: crate::context::Context::new() }))
}
pub fn new_from_context(context: crate::context::Context) -> Self {
Program { context }
}
pub fn exec(&mut self, token: &str) -> Values {
let token = token.trim();
let token = token.replace("\n", "");
debug!("[E] split token");
let split: Vec<String> = measure_time_debug!({token.to_owned().split_whitespace() .map(|s| s.to_string()) .collect()}); if self.context.keys.borrow().contains_key(&split[0]) {
debug!("[V] token is has key");
let content = token.replace(&split[0], "").trim().to_string();
debug!("[E] getting function");
let func = measure_time_debug!({self.context.get_key(&split[0])});
return func(content, self);
}
debug!("[E] checking references");
if token.starts_with("$") {
debug!("[E] token is reference");
let name = token.replace("$", "").trim().to_string();
debug!("[E] getting memory value: {}", &name);
return self.context.get_memory(&name);
}
debug!("[E] checking function");
debug!("[REGEX] Matching regex");
if measure_time_debug!({FUNC_REGEX.is_match(&token)}) {
debug!("[V] token is function");
debug!("[E] getting function infos");
let (name, args): (String, String) = if let Some(cap) = FUNC_REGEX.captures(&token) {
debug!("[V] getting name");
let name = measure_time_debug!({cap.get(1).map_or("", |m| m.as_str()).to_string()});
debug!("[E] getting args");
let args = measure_time_debug!({cap.get(2).map_or("", |m| m.as_str()).to_string()});
(name, args)
} else { ("".to_owned(), "".to_owned()) };
debug!("[INF] infos {} {}", name, args);
if !self.context.functions.borrow().contains_key(&name) { panic!("Function {} not found", name); }
let func = { self.context.get_function(&name) };
let args = args.split(",").map(|s| self.exec(s)).collect::<Vec<Values>>();
return (func)(args, self);
}
debug!("[E] other tokens definition");
debug!("[E] getting token definition index");
let index = measure_time_debug!({self.context.token_index(&token)});
debug!("[E] getting token");
let def_tok = measure_time_debug!({self.context.get_token(index)});
debug!("[E] executing function");
let val = measure_time_debug!({def_tok.borrow().exec(&token, self).unwrap()});
val
}
pub fn push_internal_token(&mut self, token: Box<dyn Token>) {
self.context.push_token(token);
}
pub fn push_internal_key(&mut self, key: &str, func: impl Fn(String, &mut Program) -> Values + 'static) {
self.context.push_key(key.to_owned(), func);
}
pub fn push_internal_memory(&mut self, key: &str, val: Values) {
self.context.push_memory(key, val);
}
pub fn push_internal_function(&mut self, name: &str, func: impl Fn(Vec<Values>, &mut Program) -> Values + 'static) {
self.context.push_function(name.to_owned(), func);
}
pub fn new_depth_context(&mut self) -> Rc<RefCell<Program>> {
let mut clone = self.clone();
clone.context.sub_context = Some(Box::new(Context::new()));
Rc::new(RefCell::new(clone))
}
}