diff --git a/src/main.rs b/src/main.rs index 2e933d3..3bbba49 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,3 @@ - // tokenizer mod token; // ro parse a queue of tokens into functions with expressions @@ -7,18 +6,19 @@ mod parser; // designed for a virtual stack machiene mod inter; -use token::*; -use parser::*; use colored::Colorize; +use parser::*; +use token::*; -pub fn message(typ: MessageType, msg: String) { - println!("{}: {}", typ.to_colored(), msg.bold().bright_white()); +pub fn message(typ: MessageType, msg: S) +where + S: Into, +{ + println!("{}: {}", typ.to_colored(), msg.into().bold().bright_white()); } fn main() { - - let source = -r" + let source = r" # this is pi pi = rat 5.1415926535 @@ -50,5 +50,7 @@ main() = int { } "; - parse(&mut tokenize(source), source); + let diagnostics = parse(&mut tokenize(source), source); + + println!("{}", diagnostics); } diff --git a/src/parser/data.rs b/src/parser/data.rs index 9a69b52..c98ed97 100644 --- a/src/parser/data.rs +++ b/src/parser/data.rs @@ -1,14 +1,74 @@ -use core::panic; -use std::collections::{VecDeque}; -use crate::token::{Token, DebugErr}; +use crate::token::{DebugInfo, DebugNotice, Token}; use crate::Prim; +use core::panic; +use std::collections::VecDeque; pub struct Diagnostics<'a> { /// terminating factor on error - err: Option>, + err: Option>, /// additional warning and informations /// all non critical - hints: Vec> + hints: Vec>, + /// source string + source: &'a str, +} + +impl<'a> Diagnostics<'a> { + pub fn new(source: &'a str) -> Self { + Self { + err: None, + hints: vec![], + source, + } + } + + 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() { + panic!("Error already set"); + } + + let info: DebugInfo = source.clone().into(); + + self.err = Some(DebugNotice { + info, + msg: message, + ext: ext.into(), + source: self.source, + }); + } + + 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(); + + self.hints.push(DebugNotice { + info, + msg: message, + ext: ext.into(), + source: self.source, + }); + } +} + +impl<'a> std::fmt::Display for Diagnostics<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for hint in self.hints.iter() { + 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)] @@ -37,7 +97,7 @@ pub struct Declr<'a> { /// if the function returns a single value pub results: bool, /// type of result - pub result_typ: Option + pub result_typ: Option, } impl<'a> Declr<'a> { @@ -46,7 +106,7 @@ impl<'a> Declr<'a> { name: None, args: None, results: false, - result_typ: None + result_typ: None, } } } @@ -85,7 +145,7 @@ pub enum Expr<'a> { /// group of more expressions Block(Block<'a>), /// single term - Term(VecDeque>) + Term(VecDeque>), } pub struct Scope<'a> { @@ -97,7 +157,7 @@ pub struct Scope<'a> { pub yields: bool, /// if the last expr yielded a result pub expr_yield: bool, - pub cond_count: usize + pub cond_count: usize, } impl<'a> Scope<'a> { @@ -112,7 +172,7 @@ impl<'a> Scope<'a> { pub fn decl_var(&mut self, name: String, typ: Option) { self.vars.last_mut().unwrap().push((name, typ)) } - + pub fn is_arg(&self, name: &'a str) -> bool { if let Some(args) = self.args { for arg in args.iter() { @@ -124,7 +184,7 @@ impl<'a> Scope<'a> { false } - pub fn get_arg_type(&self, name: &'a str) -> Prim { + pub fn get_arg_type(&self, name: &'a str) -> Prim { if let Some(args) = self.args { for arg in args.iter() { if arg.0 == name { @@ -135,7 +195,7 @@ impl<'a> Scope<'a> { panic!("No argument of name: {name}"); } - pub fn get_var_type(&self, name: &'a str) -> Prim { + pub fn get_var_type(&self, name: &'a str) -> Prim { // create an owned version of the string let owned = &name.to_owned(); @@ -152,7 +212,7 @@ impl<'a> Scope<'a> { pub fn is_var(&self, name: &'a 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() { @@ -171,7 +231,7 @@ impl<'a> Scope<'a> { func_return_typ: None, expr_yield: false, yields: false, - cond_count: 0 + cond_count: 0, } } } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index a2a4b18..dcada0b 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1,6 +1,6 @@ -use core::{panic}; -use std::{collections::{VecDeque}, vec}; -use crate::token::{Token, Operator, Assoc, Prim, MessageType, Keyword}; +use crate::token::{Assoc, DebugInfo, Keyword, Operator, Prim, Token}; +use core::panic; +use std::{collections::VecDeque, vec}; pub mod data; pub mod msg; @@ -8,7 +8,10 @@ pub mod msg; use data::*; /// simple brace-counting parser to detect functions -fn discover_functions<'a>(tokens: &mut VecDeque>, source: &str) -> (Vec>, Vec>) { +fn discover_functions<'a>( + tokens: &mut VecDeque>, + diagnostics: &mut data::Diagnostics, +) -> Result<(Vec>, Vec>), ()> { let mut funcs = Vec::new(); let mut declrs = Vec::new(); @@ -17,21 +20,25 @@ fn discover_functions<'a>(tokens: &mut VecDeque>, source: &str) let mut declr = Declr::new(); // count open brackets - let mut brace_cnt = 0; + let mut brace_cnt = 0; let mut paren_cnt = 0; let mut single_line = false; macro_rules! finish_func { - ($dbginf:expr) => { + ($token:expr) => { if declrs.contains(&declr) { - println!("{}", $dbginf.make_msg_w_ext(crate::msg::ERR10, format!("Multiple definitions: {declr}"))); - panic!() + diagnostics.set_err( + $token, + crate::msg::ERR10, + format!("Multiple definitions: {declr}"), + ); + return Err(()); } if declr.results && declr.result_typ.is_none() { - println!("{}", $dbginf.make_msg_w_ext(crate::msg::ERR11, format!("for function {declr}"))); - panic!(); + diagnostics.set_err($token, crate::msg::ERR11, format!("for function {declr}")); + return Err(()); } funcs.push(func); @@ -43,7 +50,6 @@ fn discover_functions<'a>(tokens: &mut VecDeque>, source: &str) } while let Some(top) = tokens.pop_front() { - // function body detection // has highest priority match &top { @@ -54,102 +60,107 @@ fn discover_functions<'a>(tokens: &mut VecDeque>, source: &str) // we have an found open function body if brace_cnt == 1 { if declr.name.is_none() { - println!("{}", dbginf.make_msg(crate::msg::ERR12)); - panic!(); + diagnostics.set_err(&top, crate::msg::ERR12, ""); + return Err(()); } - - if paren_cnt > 0 { - println!("{}", dbginf.make_msg(crate::msg::ERR13)); - panic!(); + + if paren_cnt > 0 { + diagnostics.set_err(&top, crate::msg::ERR13, ""); + return Err(()); } single_line = false; func.raw = Some(VecDeque::new()); continue; } - }, + } '}' => { brace_cnt -= 1; // we closed one to much if brace_cnt < 0 { - println!("{}", dbginf.make_msg(crate::msg::ERR14)); - panic!(); + diagnostics.set_err(&top, crate::msg::ERR14, ""); + return Err(()); } // end of function body if brace_cnt == 0 { - finish_func!(dbginf); + finish_func!(&top); continue; } } - _ => () - } - - Token::Type(typ, dbginf) => if declr.result_typ.is_none() { - if declr.results { - declr.result_typ = Some(*typ); - continue; - } else { - println!("{}", dbginf.make_msg(crate::msg::ERR16)); - panic!(); - } + _ => (), }, - - Token::LineBreak(dbginf) => if single_line { - finish_func!(dbginf); - continue; + + Token::Type(typ, dbginf) => { + if declr.result_typ.is_none() { + if declr.results { + declr.result_typ = Some(*typ); + continue; + } else { + diagnostics.set_err(&top, crate::msg::ERR16, ""); + return Err(()); + } + } } - _ => if single_line && func.raw.is_none() { - func.raw = Some(VecDeque::new()); + Token::LineBreak(dbginf) => { + if single_line { + finish_func!(&top); + continue; + } + } + + _ => { + if single_line && func.raw.is_none() { + func.raw = Some(VecDeque::new()); + } } } - + if func.raw.is_none() { match &top { Token::Operator(op, dbginf) => match op { Operator::Assign => { if declr.results { - println!("{}", dbginf.make_msg(crate::msg::ERR17)); - panic!(); + diagnostics.set_err(&top, crate::msg::ERR17, ""); + return Err(()); } if declr.name.is_none() { - println!("{}", dbginf.make_msg(crate::msg::ERR12)); - panic!(); + diagnostics.set_err(&top, crate::msg::ERR12, ""); + return Err(()); } declr.results = true; single_line = true; continue; } - _ => () - } + _ => (), + }, Token::Word(text, dbginf) => { - if declr.name.is_some() { if declr.args.is_none() { - println!("{}", dbginf.make_msg(crate::msg::ERR18)); - panic!(); + diagnostics.set_err(&top, crate::msg::ERR18, ""); + return Err(()); } } else if brace_cnt > 0 { - println!("{}", dbginf.make_msg(crate::msg::ERR13)); - panic!(); + diagnostics.set_err(&top, crate::msg::ERR13, ""); + return Err(()); } else { declr.name = Some(text); continue; } - }, + } Token::Assign(name, _, dbginf) => { if declr.results { - println!("{}", dbginf.make_msg(crate::msg::ERR17)); - panic!(); + diagnostics.set_err(&top, crate::msg::ERR17, ""); + return Err(()); } if declr.name.is_some() { - println!("{}", dbginf.make_msg(crate::msg::ERR18)); - panic!(); + diagnostics.set_err(&top, crate::msg::ERR18, ""); + return Err(()); } func.raw = Some(VecDeque::new()); @@ -158,54 +169,52 @@ fn discover_functions<'a>(tokens: &mut VecDeque>, source: &str) single_line = true; continue; } - + Token::Delemiter(char, dbginf) => match char { - - '(' => if func.raw.is_none() { - paren_cnt += 1; - if paren_cnt == 1 { - - if declr.args.is_some() { - println!("{}", dbginf.make_msg(crate::msg::ERR19)); - panic!(); + '(' => { + if func.raw.is_none() { + paren_cnt += 1; + if paren_cnt == 1 { + if declr.args.is_some() { + diagnostics.set_err(&top, crate::msg::ERR19, ""); + return Err(()); + } + + declr.args = Some(Vec::new()); + continue; } - - declr.args = Some(Vec::new()); - continue; } - }, + } ')' => { paren_cnt -= 1; if paren_cnt == 0 { continue; } } - _ => () - } - _ => () + _ => (), + }, + _ => (), } } if let Some(body) = &mut func.raw { body.push_back(top); continue; - } - else if let Some(args) = &mut declr.args { - + } else if let Some(args) = &mut declr.args { if paren_cnt == 0 { - println!("{}", top.create_msg(crate::msg::ERR20)); - panic!(); + diagnostics.set_err(&top, crate::msg::ERR20, ""); + return Err(()); } match &top { Token::Decl(name, typ, _dbginf) => args.push((name, *typ)), Token::Word(_, dbginf) => { - println!("{}", dbginf.make_msg(crate::msg::ERR21)); - panic!() - }, + diagnostics.set_err(&top, crate::msg::ERR21, ""); + return Err(()); + } _ => { - println!("{}", top.create_msg(crate::msg::ERR23)); - panic!() + diagnostics.set_err(&top, crate::msg::ERR23, ""); + return Err(()); } } continue; @@ -215,79 +224,94 @@ fn discover_functions<'a>(tokens: &mut VecDeque>, source: &str) match &top { Token::LineBreak(_) | Token::Terminator(_) => (), // valid whitespace _ => { - println!("{}", top.create_msg(crate::msg::ERR22)); - panic!() + diagnostics.set_err(&top, crate::msg::ERR22, ""); + return Err(()); } } } if let Some(raw) = func.raw { if let Some(front) = raw.front() { - println!("{}", front.create_msg(crate::msg::ERR15)); - panic!(); + diagnostics.set_err(front, crate::msg::ERR15, ""); + return Err(()); } } - - (funcs, declrs) + + Ok((funcs, declrs)) } /// parse the functions raw content to expr for easy compilation using a brace-counter. /// - ```{...}``` surround a block /// - line breaks seperate expressions -fn discover_exprs<'a>(functions: &mut Vec>, _: &Vec>, source: &'a str) { +fn discover_exprs<'a>( + functions: &mut Vec>, + _: &Vec>, + diagnostics: &mut data::Diagnostics, +) { for func in functions.iter_mut() { - let mut blocks = vec![Block::new()]; let mut expr = VecDeque::new(); - - while let Some(top) = func.raw.as_mut().unwrap().pop_front() { + while let Some(top) = func.raw.as_mut().unwrap().pop_front() { match &top { - Token::LineBreak(dbginf) | Token::Terminator(dbginf) => if !expr.is_empty() { - blocks.last_mut().unwrap_or_else(|| { - println!("{}", dbginf.make_msg(crate::msg::ERR41)); - panic!() - }).push_back(Expr::Term(expr)); - expr = VecDeque::new(); - continue; + Token::LineBreak(dbginf) | Token::Terminator(dbginf) => { + if !expr.is_empty() { + if let Some(blocks) = blocks.last_mut() { + blocks.push_back(Expr::Term(expr)) + } else { + diagnostics.set_err(&top, crate::msg::ERR41, ""); + return; + } + expr = VecDeque::new(); + continue; + } } Token::Delemiter(char, dbginf) => match char { '{' => { - blocks.last_mut().unwrap_or_else(|| { - println!("{}", dbginf.make_msg(crate::msg::ERR41)); - panic!() - }).push_back(Expr::Term(expr)); + blocks + .last_mut() + .unwrap_or_else(|| { + diagnostics.set_err(&top, crate::msg::ERR41, ""); + panic!() + }) + .push_back(Expr::Term(expr)); expr = VecDeque::new(); blocks.push(Block::new()); continue; - }, + } '}' => { // pop topmost block of the stack, storing it in the next lower block if let Some(block) = blocks.pop() { - blocks.last_mut().unwrap_or_else(|| { - println!("{}", dbginf.make_msg(crate::msg::ERR41)); - panic!() - }).push_back(Expr::Block(block)); + blocks + .last_mut() + .unwrap_or_else(|| { + //println!("{}", dbginf.make_msg(crate::msg::ERR41)); + panic!() + }) + .push_back(Expr::Block(block)); } else { - println!("{}", dbginf.make_msg(crate::msg::ERR40)); + //println!("{}", dbginf.make_msg(crate::msg::ERR40)); panic!() } continue; - }, - _ => () + } + _ => (), }, - _ => () + _ => (), } - + expr.push_back(top) } if !expr.is_empty() { - blocks.last_mut().unwrap_or_else(|| { - println!("{}", expr.back().unwrap().create_msg(crate::msg::ERR40)); - panic!() - }).push_back(Expr::Term(expr)); + blocks + .last_mut() + .unwrap_or_else(|| { + diagnostics.set_err(expr.back().unwrap(), crate::msg::ERR40, ""); + panic!() + }) + .push_back(Expr::Term(expr)); } if let Some(block) = blocks.pop() { @@ -298,103 +322,150 @@ fn discover_exprs<'a>(functions: &mut Vec>, _: &Vec>, source: } } -fn check_var_typ(typ: &mut Option, operands: &mut Vec, dbginf: &crate::token::DebugInfo, source: &str) { - +fn check_var_typ( + typ: &mut Option, + operands: &mut Vec, + info: &crate::token::DebugInfo, + diagnostics: &mut data::Diagnostics, +) -> Result<(), ()> { if let Some(value) = operands.pop() { if !operands.is_empty() { - println!("{}", dbginf.make_msg(crate::msg::ERR50)); - panic!(); + diagnostics.set_err(info, crate::msg::ERR50, ""); + return Err(()); } if let Some(typ) = typ { if !typ.is_equal(value) { - println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR51, format!("needed {:?} got {:?}", typ, value) )); - panic!(); + diagnostics.set_err( + info, + crate::msg::ERR51, + format!("needed {:?} got {:?}", typ, value), + ); + return Err(()); } } else { - // assign a type to untyped variable - println!("{}", dbginf.make_msg_w_ext(crate::msg::INF51, format!("gessed type: {:?}", value) )); + diagnostics.hint(info, crate::msg::INF51, format!("gessed type: {:?}", value)); *typ = Some(value); } - } else { - println!("{}", dbginf.make_msg(crate::msg::ERR52)); - panic!(); + diagnostics.set_err(info, crate::msg::ERR52, ""); + return Err(()); } + Ok(()) } -fn process_keyword(keyword: Keyword, _: &Vec, scope: &mut Scope, operands: &mut Vec, dbginf: &crate::token::DebugInfo, source: &str) { +fn process_keyword( + info: &DebugInfo, + keyword: Keyword, + scope: &mut Scope, + operands: &mut Vec, + diagnostics: &mut data::Diagnostics, +) -> Result<(), ()> { match keyword { Keyword::If | Keyword::While => { if operands.len() != 1 { - println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR53, format!("got {:?} values", operands.len()) )); - panic!(); + diagnostics.set_err( + info, + crate::msg::ERR53, + format!("got {:?} values", operands.len()), + ); + return Err(()); } if let Some(operand) = operands.pop() { match operand { Prim::Bool => (), _ => { - println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR53, format!("got {:?}", operand) )); - panic!(); + diagnostics.set_err(info, crate::msg::ERR53, format!("got {:?}", operand)); + return Err(()); } } } - }, + } Keyword::Return => { if scope.func_return_typ.is_some() { - println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR54, "perhaps use `yield`" )); - panic!(); + diagnostics.set_err(info, crate::msg::ERR54, "perhaps use `yield`"); + return Err(()); } } Keyword::Yield => { if operands.len() != 1 { - println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR55, format!("got {:?} instead of 1", operands.len()) )); - panic!(); + diagnostics.set_err( + info, + crate::msg::ERR55, + format!("got {:?} instead of 1", operands.len()), + ); + return Err(()); } if let Some(operand) = operands.pop() { if let Some(typ) = scope.func_return_typ { if typ != operand { - println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR59, format!("expected {:?} got {:?}", typ, operand) )); - panic!(); + diagnostics.set_err( + info, + crate::msg::ERR59, + format!("expected {:?} got {:?}", typ, operand), + ); + return Err(()); } - println!("{}", scope.cond_count); scope.yields = scope.cond_count == 1; } else { - println!("{}", dbginf.make_msg(crate::msg::ERR57)); - panic!(); + diagnostics.set_err(info, crate::msg::ERR57, ""); + return Err(()); } } else { - println!("{}", dbginf.make_msg(crate::msg::ERR58)); - panic!(); + diagnostics.set_err(info, crate::msg::ERR58, ""); + return Err(()); } } - _ => () + _ => (), } + + Ok(()) } -fn collapse_operation(operation: &mut Token, declrs: &Vec, scope: &mut Scope, operands: &mut Vec, source: &str) { +fn collapse_operation( + operation: &mut Token, + declrs: &Vec, + scope: &mut Scope, + operands: &mut Vec, + diagnostics: &mut data::Diagnostics, +) -> Result<(), ()> { match operation { - Token::Operator(op, dbginf) => op.operate(operands, &dbginf, source), + Token::Operator(op, dbginf) => op.operate(operands, &dbginf, diagnostics), Token::Assign(name, mut typ, dbginf) => { - check_var_typ(&mut typ, operands, &dbginf, source); + check_var_typ(&mut typ, operands, &dbginf, diagnostics)?; scope.decl_var((*name).to_owned(), typ); - }, - Token::Func(name, dbginf) => call_func(name, declrs, scope, operands, &dbginf, source), - Token::Keyword(keyword, dbginf) => process_keyword(*keyword, declrs, scope, operands, &dbginf, source), - _ => () + } + Token::Func(name, dbginf) => call_func(name, declrs, scope, operands, &dbginf, diagnostics), + Token::Keyword(keyword, dbginf) => { + process_keyword(dbginf, *keyword, scope, operands, diagnostics)? + } + _ => (), } + Ok(()) } -fn call_func(name: &str, declrs: &Vec, _: &mut Scope, operands: &mut Vec, dbginf: &crate::token::DebugInfo, source: &str) { +fn call_func( + name: &str, + declrs: &Vec, + _: &mut Scope, + operands: &mut Vec, + dbginf: &crate::token::DebugInfo, + diagnostics: &mut data::Diagnostics, +) { for declr in declrs { if declr.name.is_some() && declr.name.unwrap() == name { - if let Some(args) = &declr.args { - if args.len() > operands.len() { - println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR60, format!("expected {:?} got {:?}", args.len(), operands.len()) )); + /* + println!( + "{}", + dbginf.make_msg_w_ext( + crate::msg::ERR60, + format!("expected {:?} got {:?}", args.len(), operands.len()) + ) + );*/ panic!() } @@ -402,7 +473,14 @@ fn call_func(name: &str, declrs: &Vec, _: &mut Scope, operands: &mut Vec< let operand = operands.first().unwrap(); if !operand.is_equal(arg.1) { - println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR61, format!("expected {:?} got {:?}", arg, operand) )); + /* + println!( + "{}", + dbginf.make_msg_w_ext( + crate::msg::ERR61, + format!("expected {:?} got {:?}", arg, operand) + ) + );*/ panic!() } @@ -414,19 +492,23 @@ fn call_func(name: &str, declrs: &Vec, _: &mut Scope, operands: &mut Vec< operands.push(typ); } - break + break; } } } /// parse a single term using a modified shunting yard -fn parse_term<'a>(term: &mut VecDeque>, declrs: &Vec>, scope: &mut Scope, source: & str) { +fn parse_term<'a>( + term: &mut VecDeque>, + declrs: &Vec>, + scope: &mut Scope, + diagnostics: &mut data::Diagnostics, +) { let mut op_stack = vec![]; let mut output = VecDeque::with_capacity(term.len()); let mut value_stack = vec![]; - 'outer: - while let Some(token) = term.pop_front() { + 'outer: while let Some(token) = term.pop_front() { match &token { Token::Word(text, dbginf) => { if is_func(declrs, text) { @@ -441,102 +523,130 @@ fn parse_term<'a>(term: &mut VecDeque>, declrs: &Vec>, scope output.push_back(Token::Var(text, *dbginf)); continue; } - println!("{}", dbginf.make_msg(crate::msg::ERR62)); + //println!("{}", dbginf.make_msg(crate::msg::ERR62)); panic!() } Token::Bool(_, _) => { output.push_back(token); value_stack.push(Prim::Bool) - }, + } Token::Number(_, hint, _) => { output.push_back(token.clone()); - value_stack.push(Prim::UntypedNum(*hint)) - }, + value_stack.push(Prim::Num(*hint)) + } Token::Assign(_, _, _) => { op_stack.push(token); - }, + } Token::Keyword(_, _) => op_stack.push(token), - Token::Delemiter(char, dbginf) => { - match char { - '(' => op_stack.push(token), - ')' => { - while let Some(mut token) = op_stack.pop() { - match &token { - Token::Delemiter(char, _) => if *char == '(' { + Token::Delemiter(char, dbginf) => match char { + '(' => op_stack.push(token), + ')' => { + while let Some(mut token) = op_stack.pop() { + match &token { + Token::Delemiter(char, _) => { + if *char == '(' { if let Some(next) = op_stack.last() { match &next { Token::Func(_, _) => { let mut token = op_stack.pop().unwrap(); - collapse_operation(&mut token, declrs, scope, &mut value_stack, source); + collapse_operation( + &mut token, + declrs, + scope, + &mut value_stack, + diagnostics, + ); output.push_back(token); - }, - _ => () + } + _ => (), } } continue 'outer; - }, - _ => { - collapse_operation(&mut token, declrs, scope, &mut value_stack, source); - output.push_back(token) } } + _ => { + collapse_operation( + &mut token, + declrs, + scope, + &mut value_stack, + diagnostics, + ); + output.push_back(token) + } } - println!("{}", dbginf.make_msg(crate::msg::ERR64)); - panic!(); - }, - _ => { - println!("{}", dbginf.make_msg(crate::msg::ERR65)); - panic!() } + //println!("{}", dbginf.make_msg(crate::msg::ERR64)); + panic!(); } - } + _ => { + //println!("{}", dbginf.make_msg(crate::msg::ERR65)); + panic!() + } + }, Token::Operator(op, _) => { let prec0 = op.prec(); - while let Some(mut top) = op_stack.last_mut(){ + while let Some(mut top) = op_stack.last_mut() { match &top { Token::Operator(op1, _) => { let prec1 = op1.prec(); if prec1 > prec0 || prec0 == prec1 && op.assoc() == Assoc::Left { - collapse_operation(&mut top, declrs, scope, &mut value_stack, source); + collapse_operation( + &mut top, + declrs, + scope, + &mut value_stack, + diagnostics, + ); output.push_back(op_stack.pop().unwrap()); - continue + continue; } - break - }, - _ => break + break; + } + _ => break, } } op_stack.push(token); } - _ => () + _ => (), } } while let Some(mut token) = op_stack.pop() { match &token { - Token::Delemiter(char, dbginf) => if *char == '(' { - println!("{}", dbginf.make_msg(crate::msg::ERR63)); - }, + Token::Delemiter(char, dbginf) => { + if *char == '(' { + //println!("{}", dbginf.make_msg(crate::msg::ERR63)); + } + } _ => { - collapse_operation(&mut token, declrs, scope, &mut value_stack, source); + collapse_operation(&mut token, declrs, scope, &mut value_stack, diagnostics); output.push_back(token) } } } if value_stack.len() > 1 { - println!("{}", output[0].create_msg(crate::msg::ERR50)); - panic!(); + diagnostics.set_err(&output[0], crate::msg::ERR50, ""); + return; } scope.expr_yield = value_stack.len() == 1; if scope.expr_yield { let yielded = value_stack.pop().unwrap(); if !yielded.is_equal(scope.func_return_typ.unwrap()) { - println!("{}", output[0].create_msg_w_ext(crate::msg::ERR59, format!("expected: {:?} got {:?}", scope.func_return_typ.unwrap(), yielded) )); + diagnostics.set_err( + &output[0], + crate::msg::ERR59, + format!( + "expected {:?} got {:?}", + scope.func_return_typ.unwrap(), + yielded + ), + ); panic!(); } } @@ -553,20 +663,29 @@ fn is_func(declrs: &[Declr], text: &str) -> bool { return false; } -fn parse_block<'a>(block: &mut Block<'a>, declrs: &Vec>, scope: &mut Scope, source: &str) { +fn parse_block<'a>( + block: &mut Block<'a>, + declrs: &Vec>, + scope: &mut Scope, + diagnostics: &mut data::Diagnostics, +) { scope.cond_count += 1; scope.alloc_scope(); for expr in block.iter_mut() { match expr { - Expr::Block(block) => parse_block(block, declrs, scope, source), - Expr::Term(term) => parse_term(term, declrs, scope, source) + Expr::Block(block) => parse_block(block, declrs, scope, diagnostics), + Expr::Term(term) => parse_term(term, declrs, scope, diagnostics), } } scope.pop_scope(); scope.cond_count -= 1; } -fn parse_exprs<'a>(funcs: &mut Vec>, declrs: &Vec>, source: &'a str) { +fn parse_exprs<'a>( + funcs: &mut Vec>, + declrs: &Vec>, + diagnostics: &mut data::Diagnostics, +) { let mut scope = Scope::new(); for (x, func) in funcs.iter_mut().enumerate() { @@ -576,15 +695,15 @@ fn parse_exprs<'a>(funcs: &mut Vec>, declrs: &Vec>, source: & scope.func_return_typ = declrs[x].result_typ; scope.yields = false; scope.cond_count = 0; - - parse_block(block, declrs, &mut scope, source); + + parse_block(block, declrs, &mut scope, diagnostics); if scope.func_return_typ.is_some() && !scope.yields && !scope.expr_yield { //token.create_msg_w_ext(crate::msg::ERR56, format!("at function {}", declrs[x])); panic!(); } - }, - _ => panic!("Fatal-Compilier-Error: function must have a block") + } + _ => panic!("Fatal-Compilier-Error: function must have a block"), } } } @@ -592,14 +711,16 @@ fn parse_exprs<'a>(funcs: &mut Vec>, declrs: &Vec>, source: & /// reorder and organize a listing of instructions to a RPN based format: /// any program is made out of functions. /// A function has a name followed by an optional parameter list, followed by an optional equal sign and block. -pub fn parse<'a>(tokens: &mut VecDeque>, source: &'a str) -> Vec> { - let (mut funcs, declrs) = discover_functions(tokens, source); - - // make all of this shit return a mutable diagnostics struct. - discover_exprs(&mut funcs, &declrs, source); - parse_exprs(&mut funcs, &declrs, source); +pub fn parse<'a>(tokens: &mut VecDeque>, source: &'a str) -> Diagnostics<'a> { + let mut dias = data::Diagnostics::new(source); - crate::inter::convert_to_erpn(&mut funcs, &declrs); - - funcs + if let Ok((mut funcs, declrs)) = discover_functions(tokens, &mut dias) { + // make all of this shit return a mutable diagnostics struct. + discover_exprs(&mut funcs, &declrs, &mut dias); + parse_exprs(&mut funcs, &declrs, &mut dias); + + crate::inter::convert_to_erpn(&mut funcs, &declrs); + } + + dias } diff --git a/src/parser/msg.rs b/src/parser/msg.rs index 9f85354..bdbe4d9 100644 --- a/src/parser/msg.rs +++ b/src/parser/msg.rs @@ -1,50 +1,200 @@ - use crate::token::DebugMsg; use crate::token::MessageType::Error; -use crate::token::MessageType::Warning; use crate::token::MessageType::Info; +use crate::token::MessageType::Warning; -pub const ERR10: &DebugMsg = &DebugMsg { typ: Error, code: 10, msg: "Function defined multiple times" }; -pub const ERR11: &DebugMsg = &DebugMsg { typ: Error, code: 11, msg: "Function missing return type" }; -pub const ERR12: &DebugMsg = &DebugMsg { typ: Error, code: 12, msg: "Function missing name" }; -pub const ERR13: &DebugMsg = &DebugMsg { typ: Error, code: 13, msg: "Open parameter list" }; -pub const ERR14: &DebugMsg = &DebugMsg { typ: Error, code: 14, msg: "Closed non existant function body" }; -pub const ERR15: &DebugMsg = &DebugMsg { typ: Error, code: 15, msg: "Open function body" }; -pub const ERR16: &DebugMsg = &DebugMsg { typ: Error, code: 16, msg: "Missing assign for return type" }; -pub const ERR17: &DebugMsg = &DebugMsg { typ: Error, code: 17, msg: "Double function assign" }; -pub const ERR18: &DebugMsg = &DebugMsg { typ: Error, code: 18, msg: "Function has multiple names" }; -pub const ERR19: &DebugMsg = &DebugMsg { typ: Error, code: 19, msg: "Multiple parameter lists" }; -pub const ERR20: &DebugMsg = &DebugMsg { typ: Error, code: 20, msg: "not a valid parameter" }; -pub const ERR21: &DebugMsg = &DebugMsg { typ: Error, code: 21, msg: "type declaration missing for parameter" }; -pub const ERR22: &DebugMsg = &DebugMsg { typ: Error, code: 22, msg: "token outside of function definition" }; -pub const ERR23: &DebugMsg = &DebugMsg { typ: Error, code: 23, msg: "token must be declaration" }; +pub const ERR10: &DebugMsg = &DebugMsg { + typ: Error, + code: 10, + msg: "Function defined multiple times", +}; +pub const ERR11: &DebugMsg = &DebugMsg { + typ: Error, + code: 11, + msg: "Function missing return type", +}; +pub const ERR12: &DebugMsg = &DebugMsg { + typ: Error, + code: 12, + msg: "Function missing name", +}; +pub const ERR13: &DebugMsg = &DebugMsg { + typ: Error, + code: 13, + msg: "Open parameter list", +}; +pub const ERR14: &DebugMsg = &DebugMsg { + typ: Error, + code: 14, + msg: "Closed non existant function body", +}; +pub const ERR15: &DebugMsg = &DebugMsg { + typ: Error, + code: 15, + msg: "Open function body", +}; +pub const ERR16: &DebugMsg = &DebugMsg { + typ: Error, + code: 16, + msg: "Missing assign for return type", +}; +pub const ERR17: &DebugMsg = &DebugMsg { + typ: Error, + code: 17, + msg: "Double function assign", +}; +pub const ERR18: &DebugMsg = &DebugMsg { + typ: Error, + code: 18, + msg: "Function has multiple names", +}; +pub const ERR19: &DebugMsg = &DebugMsg { + typ: Error, + code: 19, + msg: "Multiple parameter lists", +}; +pub const ERR20: &DebugMsg = &DebugMsg { + typ: Error, + code: 20, + msg: "not a valid parameter", +}; +pub const ERR21: &DebugMsg = &DebugMsg { + typ: Error, + code: 21, + msg: "type declaration missing for parameter", +}; +pub const ERR22: &DebugMsg = &DebugMsg { + typ: Error, + code: 22, + msg: "token outside of function definition", +}; +pub const ERR23: &DebugMsg = &DebugMsg { + typ: Error, + code: 23, + msg: "token must be declaration", +}; -pub const ERR40: &DebugMsg = &DebugMsg { typ: Error, code: 40, msg: "Open block" }; -pub const ERR41: &DebugMsg = &DebugMsg { typ: Error, code: 41, msg: "Closed non existant block" }; +pub const ERR40: &DebugMsg = &DebugMsg { + typ: Error, + code: 40, + msg: "Open block", +}; +pub const ERR41: &DebugMsg = &DebugMsg { + typ: Error, + code: 41, + msg: "Closed non existant block", +}; -pub const INF51: &DebugMsg = &DebugMsg { typ: Info, code: 51, msg: "No variable type provided" }; +pub const INF51: &DebugMsg = &DebugMsg { + typ: Info, + code: 51, + msg: "No variable type provided", +}; -pub const ERR50: &DebugMsg = &DebugMsg { typ: Error, code: 50, msg: "Expression has multiple values" }; -pub const ERR51: &DebugMsg = &DebugMsg { typ: Error, code: 51, msg: "Missmatched variable types" }; -pub const ERR52: &DebugMsg = &DebugMsg { typ: Error, code: 52, msg: "Unable to assign variable type" }; -pub const ERR53: &DebugMsg = &DebugMsg { typ: Error, code: 53, msg: "Expected single boolean value" }; -pub const ERR54: &DebugMsg = &DebugMsg { typ: Error, code: 54, msg: "Cannot return from function without result" }; -pub const ERR55: &DebugMsg = &DebugMsg { typ: Error, code: 55, msg: "Expected single value" }; -pub const ERR56: &DebugMsg = &DebugMsg { typ: Error, code: 56, msg: "Function missing return value" }; -pub const ERR57: &DebugMsg = &DebugMsg { typ: Error, code: 57, msg: "Function does not return anything" }; -pub const ERR58: &DebugMsg = &DebugMsg { typ: Error, code: 58, msg: "Yield must return a value" }; -pub const ERR59: &DebugMsg = &DebugMsg { typ: Error, code: 59, msg: "Missmatched function return type" }; +pub const ERR50: &DebugMsg = &DebugMsg { + typ: Error, + code: 50, + msg: "Expression has multiple values", +}; +pub const ERR51: &DebugMsg = &DebugMsg { + typ: Error, + code: 51, + msg: "Missmatched variable types", +}; +pub const ERR52: &DebugMsg = &DebugMsg { + typ: Error, + code: 52, + msg: "Unable to assign variable type", +}; +pub const ERR53: &DebugMsg = &DebugMsg { + typ: Error, + code: 53, + msg: "Expected single boolean value", +}; +pub const ERR54: &DebugMsg = &DebugMsg { + typ: Error, + code: 54, + msg: "Cannot return from function without result", +}; +pub const ERR55: &DebugMsg = &DebugMsg { + typ: Error, + code: 55, + msg: "Expected single value", +}; +pub const ERR56: &DebugMsg = &DebugMsg { + typ: Error, + code: 56, + msg: "Function missing return value", +}; +pub const ERR57: &DebugMsg = &DebugMsg { + typ: Error, + code: 57, + msg: "Function does not return anything", +}; +pub const ERR58: &DebugMsg = &DebugMsg { + typ: Error, + code: 58, + msg: "Yield must return a value", +}; +pub const ERR59: &DebugMsg = &DebugMsg { + typ: Error, + code: 59, + msg: "Missmatched function return type", +}; -pub const ERR60: &DebugMsg = &DebugMsg { typ: Error, code: 60, msg: "Missmatched parameter count" }; -pub const ERR61: &DebugMsg = &DebugMsg { typ: Error, code: 61, msg: "Missmatched parameter type" }; -pub const ERR62: &DebugMsg = &DebugMsg { typ: Error, code: 62, msg: "Unknown symbol" }; -pub const ERR63: &DebugMsg = &DebugMsg { typ: Error, code: 63, msg: "Missing left parenthesis" }; -pub const ERR64: &DebugMsg = &DebugMsg { typ: Error, code: 64, msg: "Missing right parenthesis" }; -pub const ERR65: &DebugMsg = &DebugMsg { typ: Error, code: 65, msg: "Missplaced character" }; - -pub const ERR70: &DebugMsg = &DebugMsg { typ: Error, code: 70, msg: "Unknown type declaration"}; -pub const ERR71: &DebugMsg = &DebugMsg { typ: Error, code: 71, msg: "Unable to identify characters as token"}; -pub const ERR72: &DebugMsg = &DebugMsg { typ: Error, code: 72, msg: "Unknown operator"}; -pub const ERR73: &DebugMsg = &DebugMsg { typ: Error, code: 73, msg: "Missmatched types for operation"}; -pub const ERR74: &DebugMsg = &DebugMsg { typ: Error, code: 74, msg: "Missing operands"}; +pub const ERR60: &DebugMsg = &DebugMsg { + typ: Error, + code: 60, + msg: "Missmatched parameter count", +}; +pub const ERR61: &DebugMsg = &DebugMsg { + typ: Error, + code: 61, + msg: "Missmatched parameter type", +}; +pub const ERR62: &DebugMsg = &DebugMsg { + typ: Error, + code: 62, + msg: "Unknown symbol", +}; +pub const ERR63: &DebugMsg = &DebugMsg { + typ: Error, + code: 63, + msg: "Missing left parenthesis", +}; +pub const ERR64: &DebugMsg = &DebugMsg { + typ: Error, + code: 64, + msg: "Missing right parenthesis", +}; +pub const ERR65: &DebugMsg = &DebugMsg { + typ: Error, + code: 65, + msg: "Missplaced character", +}; +pub const ERR70: &DebugMsg = &DebugMsg { + typ: Error, + code: 70, + msg: "Unknown type declaration", +}; +pub const ERR71: &DebugMsg = &DebugMsg { + typ: Error, + code: 71, + msg: "Unable to identify characters as token", +}; +pub const ERR72: &DebugMsg = &DebugMsg { + typ: Error, + code: 72, + msg: "Unknown operator", +}; +pub const ERR73: &DebugMsg = &DebugMsg { + typ: Error, + code: 73, + msg: "Missmatched types for operation", +}; +pub const ERR74: &DebugMsg = &DebugMsg { + typ: Error, + code: 74, + msg: "Missing operands", +}; diff --git a/src/token/mod.rs b/src/token/mod.rs index fc8bc4f..a4eb903 100644 --- a/src/token/mod.rs +++ b/src/token/mod.rs @@ -1,12 +1,14 @@ +use colored::{ColoredString, Colorize}; use std::collections::VecDeque; -use colored::{Colorize, ColoredString}; #[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)] pub enum Operator { + // bitwise boolean operations Or, And, Xor, + // comparisons Eq, Lt, Gt, @@ -14,20 +16,48 @@ pub enum Operator { LtEq, NotEq, + // arithmetic Add, Sub, Mul, Div, - Assign + Assign, } #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Assoc { Right, - Left + Left, } +const ARITHMETIC_TYPES: &'static [(&[Prim], Prim)] = &[ + (&[Prim::Int, Prim::Int], Prim::Int), + (&[Prim::Rat, Prim::Rat], Prim::Rat), + (&[Prim::Num(NumHint::Int), Prim::Int], Prim::Int), + (&[Prim::Num(NumHint::Int), Prim::Rat], Prim::Rat), + (&[Prim::Num(NumHint::Rat), Prim::Rat], Prim::Rat), + (&[Prim::Int, Prim::Num(NumHint::Int)], Prim::Int), + (&[Prim::Rat, Prim::Num(NumHint::Rat)], Prim::Rat), + (&[Prim::Rat, Prim::Num(NumHint::Int)], Prim::Rat), + ( + &[Prim::Num(NumHint::Rat), Prim::Num(NumHint::Rat)], + Prim::Rat, + ), + ( + &[Prim::Num(NumHint::Int), Prim::Num(NumHint::Rat)], + Prim::Rat, + ), + ( + &[Prim::Num(NumHint::Rat), Prim::Num(NumHint::Int)], + Prim::Rat, + ), + ( + &[Prim::Num(NumHint::Int), Prim::Num(NumHint::Int)], + Prim::Int, + ), +]; + impl Operator { pub fn parse<'a>(str: &'a str) -> Self { return match str { @@ -36,8 +66,8 @@ impl Operator { "^" => Operator::Xor, "==" => Operator::Eq, - "<" => Operator::Lt, - ">" => Operator::Gt, + "<" => Operator::Lt, + ">" => Operator::Gt, "<=" => Operator::LtEq, ">=" => Operator::GtEq, "!=" => Operator::NotEq, @@ -48,7 +78,10 @@ impl Operator { "/" => Operator::Div, "=" => Operator::Assign, - _ => panic!("Unspecified operator") + _ => { + crate::message(MessageType::Critical, "Unknown operator"); + panic!(); + } }; } @@ -57,6 +90,7 @@ impl Operator { Operator::Eq => 2, Operator::Lt => 2, Operator::Gt => 2, + Operator::NotEq => 2, Operator::LtEq => 2, Operator::GtEq => 2, @@ -66,113 +100,152 @@ impl Operator { Operator::Add => 3, Operator::Sub => 3, - Operator::Mul => 4, Operator::Div => 4, - _ => 0 - } + Operator::Assign => 0, + }; } pub fn assoc(&self) -> Assoc { match self { - _ => Assoc::Right + _ => Assoc::Right, } } - fn present_types(operands: &[Prim], types: &[Prim], r#yield: Prim, dbginf: &DebugInfo, source: &str) -> Option { + fn present_types( + operands: &[Prim], + types: &[Prim], + r#yield: Prim, + dbginf: &DebugInfo, + diagnostics: &mut crate::parser::data::Diagnostics, + ) -> Option { if operands.len() < types.len() { - println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR74, format!("required {} got {}", types.len() - operands.len(), operands.len()))); + /* + println!( + "{}", + dbginf.make_msg_w_ext( + crate::msg::ERR74, + format!( + "required {} got {}", + types.len() - operands.len(), + operands.len() + ) + ) + );*/ panic!() } for (x, typ) in types.iter().enumerate() { if typ != &operands[x] { - return None + return None; } } Some(r#yield) } - fn check_types(operands: &[Prim], types: &[(Vec, Prim)], dbginf: &DebugInfo, source: &str) -> Option { + fn check_types( + operands: &[Prim], + types: &[(&[Prim], Prim)], + dbginf: &DebugInfo, + diagnostics: &mut crate::parser::data::Diagnostics, + ) -> Option { for combination in types.iter() { - - if let Some(result) = Self::present_types(operands, &combination.0, combination.1, dbginf, source) { + if let Some(result) = + Self::present_types(operands, combination.0, combination.1, dbginf, diagnostics) + { return Some(result); } } None } - pub fn operate(&self, operands: &mut Vec, dbginf: &DebugInfo, source: &str) { + pub fn operate( + &self, + operands: &mut Vec, + dbginf: &DebugInfo, + diagnostics: &mut crate::parser::data::Diagnostics, + ) { match self { - Operator::Add | Operator::Sub | Operator::Mul | Operator::Div=> { - let types_valid = Self::check_types(operands, &[ - // +------------------------------------------------------------------------------------+---------------------------------+ - // | Parameter list of types | result type | - // +------------------------------------------------------------------------------------+---------------------------------+ - (vec![Prim::Int, Prim::Int ], Prim::Int), - (vec![Prim::Rat, Prim::Rat ], Prim::Rat), - (vec![Prim::UntypedNum(NumberClassHint::Int), Prim::Int ], Prim::Int), - (vec![Prim::UntypedNum(NumberClassHint::Int), Prim::Rat ], Prim::Rat), - (vec![Prim::UntypedNum(NumberClassHint::Rat), Prim::Rat ], Prim::Rat), - (vec![Prim::Int, Prim::UntypedNum(NumberClassHint::Int)], Prim::Int), - (vec![Prim::Rat, Prim::UntypedNum(NumberClassHint::Rat)], Prim::Rat), - (vec![Prim::Rat, Prim::UntypedNum(NumberClassHint::Int)], Prim::Rat), - (vec![Prim::UntypedNum(NumberClassHint::Rat), Prim::UntypedNum(NumberClassHint::Rat)], Prim::Rat), - (vec![Prim::UntypedNum(NumberClassHint::Int), Prim::UntypedNum(NumberClassHint::Rat)], Prim::Rat), - (vec![Prim::UntypedNum(NumberClassHint::Rat), Prim::UntypedNum(NumberClassHint::Int)], Prim::Rat), - (vec![Prim::UntypedNum(NumberClassHint::Int), Prim::UntypedNum(NumberClassHint::Int)], Prim::Int) - ], dbginf, source); + Operator::Add | Operator::Sub | Operator::Mul | Operator::Div => { + let types_valid = + Self::check_types(operands, ARITHMETIC_TYPES, dbginf, diagnostics); if let Some(result) = types_valid { operands.pop(); operands.pop(); operands.push(result); } else { - println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR73, "expected two numbers")); + /* + println!( + "{}", + dbginf.make_msg_w_ext(crate::msg::ERR73, "expected two numbers") + );*/ panic!() } - }, + } Operator::And | Operator::Or | Operator::Xor => { - let types_valid = Self::check_types(operands, &[ - (vec![Prim::Bool, Prim::Bool ], Prim::Bool), - ], dbginf, source); + let types_valid = Self::check_types( + operands, + &[(&[Prim::Bool, Prim::Bool], Prim::Bool)], + dbginf, + diagnostics, + ); if let Some(result) = types_valid { operands.pop(); operands.pop(); operands.push(result); } else { - println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR73, "expected two booleans")); + /* + println!( + "{}", + dbginf.make_msg_w_ext(crate::msg::ERR73, "expected two booleans") + );*/ panic!() } - }, - Operator::Eq | Operator::NotEq | Operator::Lt | Operator::Gt | Operator::GtEq | Operator::LtEq => { - let types_valid = Self::check_types(operands, &[ - // +------------------------------------------------------------------------------------+---------------------------------+ - // | Parameter list of types | result type | - // +------------------------------------------------------------------------------------+---------------------------------+ - (vec![Prim::Int, Prim::Int ], Prim::Bool ), - (vec![Prim::Rat, Prim::Rat ], Prim::Bool ), - (vec![Prim::UntypedNum(NumberClassHint::Int), Prim::Int ], Prim::Bool ), - (vec![Prim::UntypedNum(NumberClassHint::Rat), Prim::Rat ], Prim::Bool ), - (vec![Prim::Int, Prim::UntypedNum(NumberClassHint::Int)], Prim::Bool ), - (vec![Prim::Rat, Prim::UntypedNum(NumberClassHint::Rat)], Prim::Bool ), - (vec![Prim::UntypedNum(NumberClassHint::Rat), Prim::UntypedNum(NumberClassHint::Rat)], Prim::Bool ), - (vec![Prim::UntypedNum(NumberClassHint::Int), Prim::UntypedNum(NumberClassHint::Int)], Prim::Bool ) - ], dbginf, source); + } + Operator::Eq + | Operator::NotEq + | Operator::Lt + | Operator::Gt + | Operator::GtEq + | Operator::LtEq => { + let types_valid = Self::check_types( + operands, + &[ + (&[Prim::Int, Prim::Int], Prim::Bool), + (&[Prim::Rat, Prim::Rat], Prim::Bool), + (&[Prim::Num(NumHint::Int), Prim::Int], Prim::Bool), + (&[Prim::Num(NumHint::Rat), Prim::Rat], Prim::Bool), + (&[Prim::Int, Prim::Num(NumHint::Int)], Prim::Bool), + (&[Prim::Rat, Prim::Num(NumHint::Rat)], Prim::Bool), + ( + &[Prim::Num(NumHint::Rat), Prim::Num(NumHint::Rat)], + Prim::Bool, + ), + ( + &[Prim::Num(NumHint::Int), Prim::Num(NumHint::Int)], + Prim::Bool, + ), + ], + dbginf, + diagnostics, + ); if let Some(result) = types_valid { - operands.pop(); operands.pop(); operands.push(result); } else { - println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR73, "expected two numbers")); + /* + println!( + "{}", + dbginf.make_msg_w_ext(crate::msg::ERR73, "expected two numbers") + );*/ panic!() } - }, + } _ => { panic!("Unknown operator"); } @@ -204,25 +277,30 @@ impl Keyword { "ret" => Keyword::Return, "yield" => Keyword::Yield, "please" => Keyword::Please, - _ => panic!("Text not a known keyword {text}") - } + _ => { + crate::message( + MessageType::Critical, + format!("not a known keyword: {}", text), + ); + panic!() + } + }; } } #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum NumberClassHint { +pub enum NumHint { Int, - Rat + Rat, } -impl NumberClassHint { - - pub fn from(str: &str) -> NumberClassHint { +impl NumHint { + pub fn from(str: &str) -> NumHint { if str.parse::().is_err() { - return NumberClassHint::Rat; + return NumHint::Rat; } - NumberClassHint::Int + NumHint::Int } } @@ -232,44 +310,51 @@ pub enum Prim { Int, Rat, Bool, - UntypedNum(NumberClassHint) + Num(NumHint), } impl Prim { - fn from<'a>(text: &'a str, dbginf: &DebugInfo, source: &str) -> Prim { + fn from<'a>(text: &'a str, dbginf: &DebugInfo) -> Prim { return match text { "int" => Prim::Int, "rat" => Prim::Rat, "bool" => Prim::Bool, - _ => { - println!("{}", dbginf.make_msg(&crate::msg::ERR70)); + //println!("{}", dbginf.make_msg(&crate::msg::ERR70)); panic!() } - } + }; } pub fn is_equal(&self, value: Prim) -> bool { return match self { Prim::Bool => *self == value, - Prim::Rat => return match value { - Prim::UntypedNum(NumberClassHint::Int) => true, - Prim::UntypedNum(NumberClassHint::Rat) => true, - _ => *self == value, - }, - Prim::Int => return match value { - Prim::UntypedNum(NumberClassHint::Int) => true, - _ => *self == value, - }, - Prim::UntypedNum(NumberClassHint::Rat) => return match value { - Prim::Rat | Prim::Int => true, - _ => *self == value, - }, - Prim::UntypedNum(NumberClassHint::Int) => return match value { - Prim::Int => true, - _ => *self == value, - }, - } + Prim::Rat => { + return match value { + Prim::Num(NumHint::Int) => true, + Prim::Num(NumHint::Rat) => true, + _ => *self == value, + } + } + Prim::Int => { + return match value { + Prim::Num(NumHint::Int) => true, + _ => *self == value, + } + } + Prim::Num(NumHint::Rat) => { + return match value { + Prim::Rat | Prim::Int => true, + _ => *self == value, + } + } + Prim::Num(NumHint::Int) => { + return match value { + Prim::Int => true, + _ => *self == value, + } + } + }; } } @@ -279,90 +364,89 @@ pub struct DebugMsg { pub msg: &'static str, } -pub struct DebugErr<'a> { - info: DebugInfo<'a>, +pub struct DebugNotice<'a> { + pub info: DebugInfo, /// generic error description - msg: &'static DebugMsg, + pub msg: &'static DebugMsg, /// extra message which is case specific - ext: Option, + pub ext: String, + pub source: &'a str, } -impl<'a> std::fmt::Display for DebugErr<'a> { +impl<'a> std::fmt::Display for DebugNotice<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // write header as: // `Error (56) some syntax error message in line 5:` - f.write_fmt(format_args!("{} ({}) {} in line {}: {}\n", + f.write_fmt(format_args!( + "{} ({}) {} in line {}: {}\n", self.msg.typ.to_colored(), self.msg.code, self.msg.msg.bold().bright_white(), self.info.line, - self.ext.as_ref().unwrap_or(&String::new()) + self.ext )); // write additional information - f.write_fmt(format_args!("{}", self.info)) + f.write_fmt(format_args!( + " somewhere in here:\n --> `{}`\n", + self.source + .lines() + .nth(self.info.line) + .unwrap() + .trim() + .bold() + .bright_white() + )) + .unwrap(); + + (0..self.info.start + 6) + .into_iter() + .for_each(|_| f.write_str(" ").unwrap()); + (self.info.start..self.info.end) + .into_iter() + .for_each(|_| f.write_str("^").unwrap()); + + Ok(()) } } #[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub struct DebugInfo<'a> { +pub struct DebugInfo { /// index in source string where the token begins in the current line - start: usize, + pub start: usize, /// index in source string where the token ends in the current line - end: usize, + pub end: usize, /// line number where the line in which the token is begins - line: usize, - - source: &'a str -} - -impl<'a> DebugInfo<'a> { - pub fn make_msg(&self, msg: &'static DebugMsg) -> DebugErr { - DebugErr { - info: self.clone(), - msg, - ext: None - } - } - - pub fn make_msg_w_ext(&self, msg: &'static DebugMsg, ext: T) -> DebugErr where T: Into { - DebugErr { - info: self.clone(), - msg, - ext: Some(ext.into()) - } - } + pub line: usize, } #[derive(Debug)] pub enum MessageType { + /// For internal compiler critical error + Critical, + /// compile errors that won't allow for further compilation Error, Warning, - Info + Info, } impl MessageType { /// return a colorized string representation: /// - Error (in red) /// - Warning (in yellow) - /// - Info (in blue) + /// - Info (in blue) pub fn to_colored(&self) -> ColoredString { let raw = format!("{:#?}", self); return match self { + MessageType::Critical => raw.on_red().bold(), MessageType::Error => raw.red().bold(), MessageType::Warning => raw.yellow().bold(), - MessageType::Info => raw.blue().bold() + MessageType::Info => raw.blue().bold(), }; } } -impl<'a> std::fmt::Display for DebugInfo<'a> { +impl std::fmt::Display for DebugInfo { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_fmt(format_args!(" somewhere in here:\n --> `{}`\n", - self.source.lines().nth(self.line).unwrap().trim().bold().bright_white())).unwrap(); - - (0..self.start + 6).into_iter().for_each(|_| f.write_str(" ").unwrap()); - (self.start..self.end).into_iter().for_each(|_| f.write_str("^").unwrap()); - Ok(()) } } @@ -372,27 +456,27 @@ impl<'a> std::fmt::Display for DebugInfo<'a> { /// They give a meaning to patterns of chars allowing to interpret them. pub enum Token<'a> { // base tokens that can simply be split to from raw source code - Word(&'a str, DebugInfo<'a>), + Word(&'a str, DebugInfo), /// Single symbol delemiter like ```(```,```}``` - Delemiter(char, DebugInfo<'a>), - Operator(Operator, DebugInfo<'a>), - Number(&'a str, NumberClassHint, DebugInfo<'a>), - LineBreak(DebugInfo<'a>), - Func(&'a str, DebugInfo<'a>), + Delemiter(char, DebugInfo), + Operator(Operator, DebugInfo), + Number(&'a str, NumHint, DebugInfo), + LineBreak(DebugInfo), + Func(&'a str, DebugInfo), /// Variable - Var(&'a str, DebugInfo<'a>), + Var(&'a str, DebugInfo), /// Function argument - Arg(&'a str, DebugInfo<'a>), + Arg(&'a str, DebugInfo), /// Variable assignment in the form of ```name = ``` - Assign(&'a str, Option, DebugInfo<'a>), + Assign(&'a str, Option, DebugInfo), /// Variable type declaration in the form of ```name:type``` - Decl(&'a str, Prim, DebugInfo<'a>), - Bool(bool, DebugInfo<'a>), + Decl(&'a str, Prim, DebugInfo), + Bool(bool, DebugInfo), /// Keywords like ```if```,```break```,```while``` - Keyword(Keyword, DebugInfo<'a>), - Type(Prim, DebugInfo<'a>), + Keyword(Keyword, DebugInfo), + Type(Prim, DebugInfo), /// Semicolon - Terminator(DebugInfo<'a>) + Terminator(DebugInfo), } impl<'a> std::fmt::Display for Token<'a> { @@ -416,8 +500,8 @@ impl<'a> std::fmt::Display for Token<'a> { } } -impl<'a> Token<'a> { - fn debug_info(&self) -> &DebugInfo { +impl<'a> Into for Token<'a> { + fn into(self) -> DebugInfo { match self { Token::Type(_, d) => d, Token::Word(_, d) => d, @@ -435,14 +519,6 @@ impl<'a> Token<'a> { Token::Terminator(d) => d, } } - - pub fn create_msg(&self, msg: &'static DebugMsg) -> DebugErr { - DebugErr { info: self.debug_info().clone(), msg, ext: None } - } - - pub fn create_msg_w_ext(&self, msg: &'static DebugMsg, ext: T) -> DebugErr where T: Into { - DebugErr { info: self.debug_info().clone(), msg, ext: Some(ext.into()) } - } } const TOKEN_REGEX_SRC: &'static str = r"(#.*|--.*)|(unless|while|loop|break|cont|ret|yield|please)|(int|rat|bool)|(true|false|ye|no|maybe)|([A-Za-z_]+)\s*(?::\s*([a-zA-Z0-9]+))?\s*=|([A-Za-z_]+)\s*(?::\s*([a-zA-Z0-9]+))|([A-Za-z_]+)|(\d*\.?\d+)|(!=|==|<=|<=|[&|+\-*/<>=])|([(){}])|(\n)|(;)"; @@ -452,18 +528,18 @@ lazy_static::lazy_static! { } /// creates a vector of tokens from the specified str. -pub fn tokenize<'a>(source: &'a str) -> VecDeque> { +pub fn tokenize(source: &str) -> VecDeque { let mut tokens = VecDeque::new(); let mut line_count = 0; let mut line_start = 0; - for cap in TOKEN_REGEX.captures_iter(source) { + for cap in TOKEN_REGEX.captures_iter(source.as_ref()) { let mut enumerator = cap.iter().enumerate(); loop { let next = enumerator.next(); if next.is_none() { - break + break; } let (i, group) = next.unwrap(); @@ -477,43 +553,41 @@ pub fn tokenize<'a>(source: &'a str) -> VecDeque> { // if we have a match, save it as token if let Some(mat) = group { let debug_info = DebugInfo { - source, start: mat.start() - line_start, end: mat.end() - line_start, - line: line_count + line: line_count, }; tokens.push_back(match i { 2 => Token::Keyword(Keyword::parse(mat.as_str()), debug_info), - 3 => { - Token::Type(Prim::from(mat.as_str(), &debug_info, source), debug_info) - }, + 3 => Token::Type(Prim::from(mat.as_str(), &debug_info), debug_info), 4 => Token::Bool(parse_bool(mat.as_str()), debug_info), 5 => { let var_type = if let Some(mat) = enumerator.next().unwrap().1 { - Some(Prim::from(mat.as_str(), &debug_info, source)) + Some(Prim::from(mat.as_str(), &debug_info)) } else { None }; Token::Assign(mat.as_str(), var_type, debug_info) - }, + } 7 => { - let var_type = Prim::from(enumerator.next().unwrap().1.unwrap().as_str(), &debug_info, source); + let var_type = + Prim::from(enumerator.next().unwrap().1.unwrap().as_str(), &debug_info); Token::Decl(mat.as_str(), var_type, debug_info) - }, + } 9 => Token::Word(mat.as_str(), debug_info), - 10 => Token::Number(mat.as_str(), NumberClassHint::from(mat.as_str()), debug_info), + 10 => Token::Number(mat.as_str(), NumHint::from(mat.as_str()), debug_info), 11 => Token::Operator(Operator::parse(mat.as_str()), debug_info), 12 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap(), debug_info), 13 => { line_count += 1; line_start = mat.start(); Token::LineBreak(debug_info) - }, + } 14 => Token::Terminator(debug_info), _ => { - println!("{}", debug_info.make_msg(crate::msg::ERR71)); + //println!("{}", debug_info.make_msg(crate::msg::ERR71)); panic!() } }); @@ -528,8 +602,8 @@ pub fn tokenize<'a>(source: &'a str) -> VecDeque> { fn parse_bool(text: &str) -> bool { return match text { "true" | "ye" => true, - "false" |"no" => false, + "false" | "no" => false, "maybe" => rand::random(), - _ => panic!("Not a recognized boolean {text}") - } + _ => panic!("Not a recognized boolean {text}"), + }; }