typr-core 0.5.11

Core type checking and transpilation logic for TypR - a typed superset of R
Documentation
#![allow(dead_code, unused_variables, unused_imports, unreachable_code, unused_assignments)]
use crate::components::context::Context;
use crate::components::language::var::Var;
use crate::components::language::Lang;
use crate::components::r#type::type_system::TypeSystem;
use crate::components::r#type::Type;
use crate::processes::parsing::parse2;
use crate::processes::transpiling::translatable::RTranslatable;
use crate::processes::type_checking::typing;
use crate::utils::builder;
use rpds::Vector;

#[derive(Debug, Clone)]
pub struct FluentParser {
    raw_code: Vector<String>,
    code: Vector<Lang>,
    new_code: Vector<Lang>,
    r_code: Vector<String>,
    logs: Vector<String>,
    pub context: Context,
    last_type: Type,
    pub saved_r: Vector<String>,
}

impl FluentParser {
    pub fn new() -> Self {
        FluentParser {
            raw_code: Vector::new(),
            code: Vector::new(),
            new_code: Vector::new(),
            r_code: Vector::new(),
            logs: Vector::new(),
            context: Context::empty(),
            last_type: builder::empty_type(),
            saved_r: Vector::new(),
        }
    }
}

impl Default for FluentParser {
    fn default() -> Self {
        Self::new()
    }
}

impl FluentParser {
    pub fn push(self, code: &str) -> Self {
        Self {
            raw_code: self.raw_code.push_back(code.to_string()),
            ..self
        }
    }

    pub fn push_log(self, log: &str) -> Self {
        Self {
            logs: self.logs.push_back(log.to_string()),
            ..self
        }
    }

    pub fn push_code(self, code: Lang) -> Self {
        Self {
            code: self.code.push_back(code),
            ..self
        }
    }

    fn drop_first_raw(self) -> Self {
        Self {
            raw_code: self.raw_code.iter().skip(1).cloned().collect(),
            ..self
        }
    }

    fn next_raw_code(self) -> Option<(String, Self)> {
        let val = self.clone().raw_code.first()?.clone();
        Some((val, self.drop_first_raw()))
    }

    /// Go from raw_code (String) to code (Lang)
    pub fn parse_next(self) -> Self {
        match self.clone().next_raw_code() {
            Some((line, rest)) => match parse2((&line[..]).into()) {
                Ok(code) => rest.push_code(code),
                Err(msg) => rest.push_log(&msg),
            },
            _ => self.push_log("No more raw line left"),
        }
    }

    pub fn clean_raw_code(self) -> Self {
        Self {
            raw_code: Vector::new(),
            ..self
        }
    }

    pub fn parse_all_lines(self) -> Self {
        self.clone()
            .raw_code
            .iter()
            .fold(self, |acc, x| match parse2(x[..].into()) {
                Ok(code) => acc.push_code(code),
                Err(msg) => acc.push_log(&msg),
            })
            .clean_raw_code()
    }

    fn drop_first_code(self) -> Self {
        Self {
            code: self.code.iter().skip(1).cloned().collect(),
            ..self
        }
    }

    pub fn next_code(self) -> Option<(Lang, Self)> {
        let lang = self.code.first()?.clone();
        Some((lang, self.drop_first_code()))
    }

    pub fn set_context(self, context: Context) -> Self {
        Self { context, ..self }
    }

    fn set_last_type(self, typ: Type) -> Self {
        Self { last_type: typ, ..self }
    }

    pub fn push_new_code(self, code: Lang) -> Self {
        Self {
            new_code: self.new_code.push_back(code),
            ..self
        }
    }

    /// Typing from code (Lang) to new code (Lang)
    pub fn type_next(self) -> Self {
        match self.clone().next_code() {
            Some((code, rest)) => {
                let (typ, lang, new_context) = typing(&self.context, &code).to_tuple();
                rest.set_context(new_context).push_new_code(lang).set_last_type(typ)
            }
            _ => self.push_log("No more Lang code left"),
        }
    }

    pub fn type_all(self) -> Self {
        let (new_context, new_type) =
            self.clone()
                .code
                .iter()
                .fold((self.clone().context, builder::empty_type()), |(cont, typ), x| {
                    let (new_type, _, new_cont) = typing(&cont, x).to_tuple();
                    (new_cont, new_type)
                });
        self.set_context(new_context).set_last_type(new_type)
    }

    /// Parsing from raw code (String) to new code (Lang)
    pub fn parse_type_next(self) -> Self {
        self.parse_next().type_next()
    }

    pub fn parse_type_all(self) -> Self {
        self.parse_all_lines().type_all()
    }

    pub fn type_of(&self, symbol: &str) -> Vec<Type> {
        let var = Var::from_name(symbol);
        vec![self.context.get_type_from_existing_variable(var)]
    }

    pub fn view_logs(&self) -> String {
        self.logs.iter().cloned().collect::<Vec<_>>().join("\n")
    }

    pub fn get_code(self) -> Vector<Lang> {
        self.code
    }

    pub fn get_new_code(self) -> Vector<Lang> {
        self.new_code
    }

    pub fn get_r_code(self) -> Vector<String> {
        self.r_code
    }

    pub fn get_log(&self, id: i32) -> String {
        let id = id as usize;
        if self.logs.len() > id {
            self.logs[id].clone()
        } else {
            format!("There aren't any log at index {}", id)
        }
    }

    pub fn get_last_log(&self) -> String {
        if !self.logs.is_empty() {
            self.logs.iter().next_back().unwrap().clone()
        } else {
            "The logs are empty".to_string()
        }
    }

    pub fn get_last_type(&self) -> Type {
        self.last_type.clone()
    }

    fn drop_first_new_code(self) -> Self {
        Self {
            new_code: self.new_code.iter().skip(1).cloned().collect(),
            ..self
        }
    }

    pub fn next_new_code(self) -> Option<(Lang, Self)> {
        let lang = self.new_code.first()?.clone();
        Some((lang, self.drop_first_new_code()))
    }

    pub fn push_r_code(self, r_code: String) -> Self {
        Self {
            r_code: self.r_code.push_back(r_code),
            ..self
        }
    }

    fn save_r_code(self, r_code: &str) -> Self {
        Self {
            saved_r: self.saved_r.push_back(r_code.to_string()),
            ..self
        }
    }

    pub fn get_saved_r_code(&self) -> String {
        self.saved_r
            .iter()
            .cloned()
            .reduce(|acc, x| format!("{}\n{}", acc, &x))
            .unwrap_or("".to_string())
    }

    fn get_let_definitions(v: Vector<Lang>, context: &Context) -> Vec<String> {
        v.iter()
            .filter(|x| x.save_in_memory())
            .map(|x| x.to_r(context).0)
            .collect()
    }

    pub fn transpile_next(self) -> Self {
        match self.clone().next_new_code() {
            Some((code, rest)) => {
                let (r_code, new_context) = code.to_r(&self.context);
                let res = rest.set_context(new_context).push_r_code(r_code);
                Self::get_let_definitions(self.new_code, &self.context)
                    .iter()
                    .fold(res, |acc, x| acc.save_r_code(x))
            }
            _ => self.push_log("No more Lang code left"),
        }
    }

    /// from raw code (String) to r code (String)
    /// Do the same as .run() methode
    pub fn parse_type_transpile_next(self) -> Self {
        self.parse_next().type_next().transpile_next()
    }

    /// from raw code (String) to r code (String)
    /// Call parse_type_transpile_next
    pub fn run(self) -> Self {
        self.parse_type_transpile_next()
    }

    fn drop_first_r_code(self) -> Self {
        Self {
            r_code: self.r_code.iter().skip(1).cloned().collect(),
            ..self
        }
    }

    pub fn next_r_code(self) -> Option<(String, Self)> {
        let lang = self.r_code.first()?.clone();
        Some((lang, self.drop_first_r_code()))
    }

    pub fn display_context(&self) -> String {
        self.context.display_typing_context()
    }

    pub fn get_context(self) -> Context {
        self.context
    }

    pub fn check_parsing(self, s: &str) -> Vector<Lang> {
        self.push(s).parse_next().get_code()
    }

    pub fn check_typing(self, s: &str) -> Type {
        self.push(s).parse_type_next().get_last_type()
    }

    pub fn check_transpiling(self, s: &str) -> Vector<String> {
        self.push(s).parse_type_transpile_next().get_r_code()
    }
}

use std::fmt;
impl fmt::Display for FluentParser {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let res = format!(
            "raw_code: {}\ncode: {}\nnew_code: {}\nr_code: {}\nlast_type: {}",
            self.raw_code.iter().cloned().collect::<Vec<_>>().join(" | "),
            self.code
                .iter()
                .map(|x| x.simple_print())
                .collect::<Vec<_>>()
                .join(" | "),
            self.new_code
                .iter()
                .map(|x| x.simple_print())
                .collect::<Vec<_>>()
                .join(" | "),
            self.r_code.iter().cloned().collect::<Vec<_>>().join(" | "),
            self.last_type.pretty()
        );
        write!(f, "{}", res)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_fluent_parser0() {
        let typ = FluentParser::new().push("8").parse_type_next().get_last_type();
        assert_eq!(typ, builder::integer_type(8))
    }

    #[test]
    fn test_fluent_parser1() {
        let typ = FluentParser::new()
            .push("let df <- 8;")
            .parse_type_next()
            .push("9")
            .parse_type_next()
            .get_last_type();
        assert_eq!(typ, builder::integer_type(9))
    }

    #[test]
    fn test_fluent_transpiler1() {
        let fp = FluentParser::new().push("8").run();
        assert_eq!(fp.next_r_code().unwrap().0, "8L |> as.Integer()")
    }
}