use rand::RngCore; use crate::conf::Settings; use crate::token::{DebugInfo, DebugNotice, Token, MessageType}; use crate::Prim; use core::panic; use std::collections::{VecDeque, HashMap}; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::path::Path; #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum LogLvl { /// print everything Info, /// print only errors and warning Warn, /// print only errors Err, } impl Default for LogLvl { fn default() -> Self { Self::Info } } pub struct Diagnostics { /// terminating factor on error err: Option, /// additional warning and informations /// all non critical hints: Vec, /// source hash and source string source: HashMap, /// flags loglvl: LogLvl, } impl Diagnostics { pub fn new(settings: &Settings) -> Diagnostics { Self { err: None, hints: vec![], source: HashMap::new(), loglvl: settings.loglvl() } } pub fn add_source_origin(&mut self, source: A, url: A) where A: Into + Hash { let mut hasher = DefaultHasher::new(); source.hash(&mut hasher); let origin = hasher.finish(); let string = url.into(); let file_name = Path::new(&string).file_name().expect("not a falid file path"); self.source.insert(origin, (file_name.to_str().unwrap().to_string(), source.into())); } pub fn set_err(&mut self, source: &S, message: &'static crate::token::DebugMsg, ext: T) where T: Into, S: Into + Clone, { if self.err.is_some() { crate::message(MessageType::Warning, "Multiple Errors occured during compilation"); return; } let info: DebugInfo = source.clone().into(); let origin = self.source.get(&info.origin).unwrap(); let context = origin.1 .lines() .nth(info.line) .unwrap() .trim(); self.err = Some(DebugNotice { info, msg: message, ext: ext.into(), source: context.to_string(), origin: origin.0.to_owned() }); } pub fn hint(&mut self, source: &S, message: &'static crate::token::DebugMsg, ext: T) where T: Into, S: Into + Clone, { let info: DebugInfo = source.clone().into(); let origin = self.source.get(&info.origin).unwrap(); let context = origin.1 .lines() .nth(info.line) .unwrap() .trim(); self.hints.push(DebugNotice { info, msg: message, ext: ext.into(), source: context.to_string(), origin: origin.0.to_owned() }); } } impl std::fmt::Display for Diagnostics { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { for hint in self.hints.iter() { match hint.msg.typ { MessageType::Info => if self.loglvl != LogLvl::Info { continue; }, MessageType::Warning => if self.loglvl == LogLvl::Err { continue; }, _ => (), } f.write_fmt(format_args!("{}\n\n", hint)).unwrap(); } if let Some(err) = self.err.as_ref() { f.write_fmt(format_args!("{}\n\n", err)).unwrap(); } Ok(()) } } #[derive(Debug, Clone)] pub struct Func<'a> { /// raw tokens pub raw: Option>>, /// parsed content pub expr: Option>, pub is_builtin:bool, } impl<'a> Func<'a> { pub fn new() -> Self { Self { raw: None, expr: None, is_builtin: false } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct Declr<'a> { /// name of this function pub name: Option<&'a str>, /// parameter names pub args: Option>, /// if the function returns a single value pub results: bool, /// type of result pub result_typ: Option, /// debug info pub info: Option, pub is_builtin: bool, uuid: u64 } impl<'a> Declr<'a> { pub fn generate_builtin(name: &'static str, args: Vec<(&'static str, Prim)>, ret: Option) -> Declr<'a> { Declr { name: Some(name), args: if args.is_empty() { None } else { Some(args) }, results: ret.is_some(), result_typ: ret, info: None, is_builtin: true, uuid: rand::thread_rng().next_u64() } } pub fn new() -> Self { Self { name: None, args: None, results: false, result_typ: None, info: None, is_builtin: false, uuid: 0, } } pub fn main() -> Self { let mut main = Declr { name: Some("main"), args: None, results: true, result_typ: Some(Prim::Int), info: None, is_builtin: false, uuid: 0 }; main.gen_uuid(); main } pub fn get_arg_ord(&self, name: &str) -> usize { if let Some(args) = self.args.as_ref() { for (x, arg) in args.iter().enumerate() { if arg.0 == name { return x; } } } return 0; } pub fn gen_uuid(&mut self) { let mut hasher = DefaultHasher::default(); self.name.unwrap().hash(&mut hasher); if let Some(args) = self.args.as_ref() { for arg in args.iter() { arg.0.hash(&mut hasher); arg.1.hash(&mut hasher); } } self.result_typ.hash(&mut hasher); self.uuid = hasher.finish() } pub fn uuid(&self) -> u64 { self.uuid } } impl<'a> std::fmt::Display for Declr<'a> { /// print this functions declaration in the form of ```foo(x,y) = {}``` fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_fmt(format_args!("{}", &self.name.unwrap()))?; // format the arguments if let Some(args) = &self.args { f.write_str("(")?; for (x, arg) in args.iter().enumerate() { if x == 0 { f.write_fmt(format_args!("{}", arg.0))?; continue; } f.write_fmt(format_args!(", {}", arg.0))?; } f.write_str(")")?; } if self.results { f.write_str(" =")?; } if let Some(typ) = self.result_typ { f.write_fmt(format_args!(" {:?}", typ))?; } f.write_str(" {}") } } pub type Block<'a> = VecDeque>; #[derive(Debug, Clone)] pub enum Expr<'a> { /// group of more expressions Block(Block<'a>), /// single term Term(VecDeque>), } pub struct Scope { pub declr: usize, /// stack of scoped block variables pub vars: Vec)>>, /// if we safely yielded sth pub yields: bool, /// if the last expr yielded a result pub expr_yield: bool, pub cond_count: usize, } impl Scope { pub fn alloc_scope(&mut self) { self.vars.push(Vec::new()) } pub fn pop_scope(&mut self) { self.vars.pop(); } pub fn decl_var(&mut self, name: String, typ: Option) { self.vars.last_mut().unwrap().push((name, typ)) } pub fn is_arg(&self, name: &str, declrs: &Vec) -> bool { if let Some(args) = &declrs[self.declr].args { for arg in args.iter() { if arg.0 == name { return true; } } } false } pub fn get_arg_type(&self, name: &str, declrs: &Vec) -> Prim { if let Some(args) = &declrs[self.declr].args { for arg in args.iter() { if arg.0 == name { return arg.1; } } } panic!("No argument of name: {name}"); } pub fn get_var_type(&self, name: &str) -> Prim { // create an owned version of the string let owned = &name.to_owned(); for vars in self.vars.iter() { for var in vars.iter() { if &var.0 == owned { return var.1.expect("Untyped variable"); } } } panic!("No variable of name: {name}"); } pub fn is_var(&self, name: &str) -> Option { // create an owned version of the string let owned = &name.to_owned(); // search for vars in self.vars.iter() { for var in vars.iter() { if &var.0 == owned { return var.1; } } } None } pub fn new() -> Scope { Scope { declr: 0, vars: vec![], expr_yield: false, yields: false, cond_count: 0, } } }