using results instead panic

This commit is contained in:
Sven Vogel 2022-11-23 21:28:13 +01:00
parent f262a5d92b
commit d3f121640a
5 changed files with 864 additions and 457 deletions

View File

@ -1,4 +1,3 @@
// tokenizer // tokenizer
mod token; mod token;
// ro parse a queue of tokens into functions with expressions // ro parse a queue of tokens into functions with expressions
@ -7,18 +6,19 @@ mod parser;
// designed for a virtual stack machiene // designed for a virtual stack machiene
mod inter; mod inter;
use token::*;
use parser::*;
use colored::Colorize; use colored::Colorize;
use parser::*;
use token::*;
pub fn message(typ: MessageType, msg: String) { pub fn message<S>(typ: MessageType, msg: S)
println!("{}: {}", typ.to_colored(), msg.bold().bright_white()); where
S: Into<String>,
{
println!("{}: {}", typ.to_colored(), msg.into().bold().bright_white());
} }
fn main() { fn main() {
let source = r"
let source =
r"
# this is pi # this is pi
pi = rat 5.1415926535 pi = rat 5.1415926535
@ -50,5 +50,7 @@ main() = int {
} }
"; ";
parse(&mut tokenize(source), source); let diagnostics = parse(&mut tokenize(source), source);
println!("{}", diagnostics);
} }

View File

@ -1,14 +1,74 @@
use core::panic; use crate::token::{DebugInfo, DebugNotice, Token};
use std::collections::{VecDeque};
use crate::token::{Token, DebugErr};
use crate::Prim; use crate::Prim;
use core::panic;
use std::collections::VecDeque;
pub struct Diagnostics<'a> { pub struct Diagnostics<'a> {
/// terminating factor on error /// terminating factor on error
err: Option<DebugErr<'a>>, err: Option<DebugNotice<'a>>,
/// additional warning and informations /// additional warning and informations
/// all non critical /// all non critical
hints: Vec<DebugErr<'a>> hints: Vec<DebugNotice<'a>>,
/// 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<T, S>(&mut self, source: &S, message: &'static crate::token::DebugMsg, ext: T)
where
T: Into<String>,
S: Into<DebugInfo> + 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<T, S>(&mut self, source: &S, message: &'static crate::token::DebugMsg, ext: T)
where
T: Into<String>,
S: Into<DebugInfo> + 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)] #[derive(Debug)]
@ -37,7 +97,7 @@ pub struct Declr<'a> {
/// if the function returns a single value /// if the function returns a single value
pub results: bool, pub results: bool,
/// type of result /// type of result
pub result_typ: Option<Prim> pub result_typ: Option<Prim>,
} }
impl<'a> Declr<'a> { impl<'a> Declr<'a> {
@ -46,7 +106,7 @@ impl<'a> Declr<'a> {
name: None, name: None,
args: None, args: None,
results: false, results: false,
result_typ: None result_typ: None,
} }
} }
} }
@ -85,7 +145,7 @@ pub enum Expr<'a> {
/// group of more expressions /// group of more expressions
Block(Block<'a>), Block(Block<'a>),
/// single term /// single term
Term(VecDeque<Token<'a>>) Term(VecDeque<Token<'a>>),
} }
pub struct Scope<'a> { pub struct Scope<'a> {
@ -97,7 +157,7 @@ pub struct Scope<'a> {
pub yields: bool, pub yields: bool,
/// if the last expr yielded a result /// if the last expr yielded a result
pub expr_yield: bool, pub expr_yield: bool,
pub cond_count: usize pub cond_count: usize,
} }
impl<'a> Scope<'a> { impl<'a> Scope<'a> {
@ -171,7 +231,7 @@ impl<'a> Scope<'a> {
func_return_typ: None, func_return_typ: None,
expr_yield: false, expr_yield: false,
yields: false, yields: false,
cond_count: 0 cond_count: 0,
} }
} }
} }

View File

@ -1,6 +1,6 @@
use core::{panic}; use crate::token::{Assoc, DebugInfo, Keyword, Operator, Prim, Token};
use std::{collections::{VecDeque}, vec}; use core::panic;
use crate::token::{Token, Operator, Assoc, Prim, MessageType, Keyword}; use std::{collections::VecDeque, vec};
pub mod data; pub mod data;
pub mod msg; pub mod msg;
@ -8,7 +8,10 @@ pub mod msg;
use data::*; use data::*;
/// simple brace-counting parser to detect functions /// simple brace-counting parser to detect functions
fn discover_functions<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &str) -> (Vec<Func<'a>>, Vec<Declr<'a>>) { fn discover_functions<'a>(
tokens: &mut VecDeque<crate::Token<'a>>,
diagnostics: &mut data::Diagnostics,
) -> Result<(Vec<Func<'a>>, Vec<Declr<'a>>), ()> {
let mut funcs = Vec::new(); let mut funcs = Vec::new();
let mut declrs = Vec::new(); let mut declrs = Vec::new();
@ -23,15 +26,19 @@ fn discover_functions<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &str)
let mut single_line = false; let mut single_line = false;
macro_rules! finish_func { macro_rules! finish_func {
($dbginf:expr) => { ($token:expr) => {
if declrs.contains(&declr) { if declrs.contains(&declr) {
println!("{}", $dbginf.make_msg_w_ext(crate::msg::ERR10, format!("Multiple definitions: {declr}"))); diagnostics.set_err(
panic!() $token,
crate::msg::ERR10,
format!("Multiple definitions: {declr}"),
);
return Err(());
} }
if declr.results && declr.result_typ.is_none() { if declr.results && declr.result_typ.is_none() {
println!("{}", $dbginf.make_msg_w_ext(crate::msg::ERR11, format!("for function {declr}"))); diagnostics.set_err($token, crate::msg::ERR11, format!("for function {declr}"));
panic!(); return Err(());
} }
funcs.push(func); funcs.push(func);
@ -43,7 +50,6 @@ fn discover_functions<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &str)
} }
while let Some(top) = tokens.pop_front() { while let Some(top) = tokens.pop_front() {
// function body detection // function body detection
// has highest priority // has highest priority
match &top { match &top {
@ -54,102 +60,107 @@ fn discover_functions<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &str)
// we have an found open function body // we have an found open function body
if brace_cnt == 1 { if brace_cnt == 1 {
if declr.name.is_none() { if declr.name.is_none() {
println!("{}", dbginf.make_msg(crate::msg::ERR12)); diagnostics.set_err(&top, crate::msg::ERR12, "");
panic!(); return Err(());
} }
if paren_cnt > 0 { if paren_cnt > 0 {
println!("{}", dbginf.make_msg(crate::msg::ERR13)); diagnostics.set_err(&top, crate::msg::ERR13, "");
panic!(); return Err(());
} }
single_line = false; single_line = false;
func.raw = Some(VecDeque::new()); func.raw = Some(VecDeque::new());
continue; continue;
} }
}, }
'}' => { '}' => {
brace_cnt -= 1; brace_cnt -= 1;
// we closed one to much // we closed one to much
if brace_cnt < 0 { if brace_cnt < 0 {
println!("{}", dbginf.make_msg(crate::msg::ERR14)); diagnostics.set_err(&top, crate::msg::ERR14, "");
panic!(); return Err(());
} }
// end of function body // end of function body
if brace_cnt == 0 { if brace_cnt == 0 {
finish_func!(dbginf); finish_func!(&top);
continue; continue;
} }
} }
_ => () _ => (),
} },
Token::Type(typ, dbginf) => if declr.result_typ.is_none() { Token::Type(typ, dbginf) => {
if declr.result_typ.is_none() {
if declr.results { if declr.results {
declr.result_typ = Some(*typ); declr.result_typ = Some(*typ);
continue; continue;
} else { } else {
println!("{}", dbginf.make_msg(crate::msg::ERR16)); diagnostics.set_err(&top, crate::msg::ERR16, "");
panic!(); return Err(());
}
}
} }
},
Token::LineBreak(dbginf) => if single_line { Token::LineBreak(dbginf) => {
finish_func!(dbginf); if single_line {
finish_func!(&top);
continue; continue;
} }
}
_ => if single_line && func.raw.is_none() { _ => {
if single_line && func.raw.is_none() {
func.raw = Some(VecDeque::new()); func.raw = Some(VecDeque::new());
} }
} }
}
if func.raw.is_none() { if func.raw.is_none() {
match &top { match &top {
Token::Operator(op, dbginf) => match op { Token::Operator(op, dbginf) => match op {
Operator::Assign => { Operator::Assign => {
if declr.results { if declr.results {
println!("{}", dbginf.make_msg(crate::msg::ERR17)); diagnostics.set_err(&top, crate::msg::ERR17, "");
panic!(); return Err(());
} }
if declr.name.is_none() { if declr.name.is_none() {
println!("{}", dbginf.make_msg(crate::msg::ERR12)); diagnostics.set_err(&top, crate::msg::ERR12, "");
panic!(); return Err(());
} }
declr.results = true; declr.results = true;
single_line = true; single_line = true;
continue; continue;
} }
_ => () _ => (),
} },
Token::Word(text, dbginf) => { Token::Word(text, dbginf) => {
if declr.name.is_some() { if declr.name.is_some() {
if declr.args.is_none() { if declr.args.is_none() {
println!("{}", dbginf.make_msg(crate::msg::ERR18)); diagnostics.set_err(&top, crate::msg::ERR18, "");
panic!(); return Err(());
} }
} else if brace_cnt > 0 { } else if brace_cnt > 0 {
println!("{}", dbginf.make_msg(crate::msg::ERR13)); diagnostics.set_err(&top, crate::msg::ERR13, "");
panic!(); return Err(());
} else { } else {
declr.name = Some(text); declr.name = Some(text);
continue; continue;
} }
}, }
Token::Assign(name, _, dbginf) => { Token::Assign(name, _, dbginf) => {
if declr.results { if declr.results {
println!("{}", dbginf.make_msg(crate::msg::ERR17)); diagnostics.set_err(&top, crate::msg::ERR17, "");
panic!(); return Err(());
} }
if declr.name.is_some() { if declr.name.is_some() {
println!("{}", dbginf.make_msg(crate::msg::ERR18)); diagnostics.set_err(&top, crate::msg::ERR18, "");
panic!(); return Err(());
} }
func.raw = Some(VecDeque::new()); func.raw = Some(VecDeque::new());
@ -160,52 +171,50 @@ fn discover_functions<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &str)
} }
Token::Delemiter(char, dbginf) => match char { Token::Delemiter(char, dbginf) => match char {
'(' => {
'(' => if func.raw.is_none() { if func.raw.is_none() {
paren_cnt += 1; paren_cnt += 1;
if paren_cnt == 1 { if paren_cnt == 1 {
if declr.args.is_some() { if declr.args.is_some() {
println!("{}", dbginf.make_msg(crate::msg::ERR19)); diagnostics.set_err(&top, crate::msg::ERR19, "");
panic!(); return Err(());
} }
declr.args = Some(Vec::new()); declr.args = Some(Vec::new());
continue; continue;
} }
}, }
}
')' => { ')' => {
paren_cnt -= 1; paren_cnt -= 1;
if paren_cnt == 0 { if paren_cnt == 0 {
continue; continue;
} }
} }
_ => () _ => (),
} },
_ => () _ => (),
} }
} }
if let Some(body) = &mut func.raw { if let Some(body) = &mut func.raw {
body.push_back(top); body.push_back(top);
continue; continue;
} } else if let Some(args) = &mut declr.args {
else if let Some(args) = &mut declr.args {
if paren_cnt == 0 { if paren_cnt == 0 {
println!("{}", top.create_msg(crate::msg::ERR20)); diagnostics.set_err(&top, crate::msg::ERR20, "");
panic!(); return Err(());
} }
match &top { match &top {
Token::Decl(name, typ, _dbginf) => args.push((name, *typ)), Token::Decl(name, typ, _dbginf) => args.push((name, *typ)),
Token::Word(_, dbginf) => { Token::Word(_, dbginf) => {
println!("{}", dbginf.make_msg(crate::msg::ERR21)); diagnostics.set_err(&top, crate::msg::ERR21, "");
panic!() return Err(());
}, }
_ => { _ => {
println!("{}", top.create_msg(crate::msg::ERR23)); diagnostics.set_err(&top, crate::msg::ERR23, "");
panic!() return Err(());
} }
} }
continue; continue;
@ -215,79 +224,94 @@ fn discover_functions<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &str)
match &top { match &top {
Token::LineBreak(_) | Token::Terminator(_) => (), // valid whitespace Token::LineBreak(_) | Token::Terminator(_) => (), // valid whitespace
_ => { _ => {
println!("{}", top.create_msg(crate::msg::ERR22)); diagnostics.set_err(&top, crate::msg::ERR22, "");
panic!() return Err(());
} }
} }
} }
if let Some(raw) = func.raw { if let Some(raw) = func.raw {
if let Some(front) = raw.front() { if let Some(front) = raw.front() {
println!("{}", front.create_msg(crate::msg::ERR15)); diagnostics.set_err(front, crate::msg::ERR15, "");
panic!(); return Err(());
} }
} }
(funcs, declrs) Ok((funcs, declrs))
} }
/// parse the functions raw content to expr for easy compilation using a brace-counter. /// parse the functions raw content to expr for easy compilation using a brace-counter.
/// - ```{...}``` surround a block /// - ```{...}``` surround a block
/// - line breaks seperate expressions /// - line breaks seperate expressions
fn discover_exprs<'a>(functions: &mut Vec<Func<'a>>, _: &Vec<Declr<'a>>, source: &'a str) { fn discover_exprs<'a>(
functions: &mut Vec<Func<'a>>,
_: &Vec<Declr<'a>>,
diagnostics: &mut data::Diagnostics,
) {
for func in functions.iter_mut() { for func in functions.iter_mut() {
let mut blocks = vec![Block::new()]; let mut blocks = vec![Block::new()];
let mut expr = VecDeque::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 { match &top {
Token::LineBreak(dbginf) | Token::Terminator(dbginf) => if !expr.is_empty() { Token::LineBreak(dbginf) | Token::Terminator(dbginf) => {
blocks.last_mut().unwrap_or_else(|| { if !expr.is_empty() {
println!("{}", dbginf.make_msg(crate::msg::ERR41)); if let Some(blocks) = blocks.last_mut() {
panic!() blocks.push_back(Expr::Term(expr))
}).push_back(Expr::Term(expr)); } else {
diagnostics.set_err(&top, crate::msg::ERR41, "");
return;
}
expr = VecDeque::new(); expr = VecDeque::new();
continue; continue;
} }
}
Token::Delemiter(char, dbginf) => match char { Token::Delemiter(char, dbginf) => match char {
'{' => { '{' => {
blocks.last_mut().unwrap_or_else(|| { blocks
println!("{}", dbginf.make_msg(crate::msg::ERR41)); .last_mut()
.unwrap_or_else(|| {
diagnostics.set_err(&top, crate::msg::ERR41, "");
panic!() panic!()
}).push_back(Expr::Term(expr)); })
.push_back(Expr::Term(expr));
expr = VecDeque::new(); expr = VecDeque::new();
blocks.push(Block::new()); blocks.push(Block::new());
continue; continue;
}, }
'}' => { '}' => {
// pop topmost block of the stack, storing it in the next lower block // pop topmost block of the stack, storing it in the next lower block
if let Some(block) = blocks.pop() { if let Some(block) = blocks.pop() {
blocks.last_mut().unwrap_or_else(|| { blocks
println!("{}", dbginf.make_msg(crate::msg::ERR41)); .last_mut()
.unwrap_or_else(|| {
//println!("{}", dbginf.make_msg(crate::msg::ERR41));
panic!() panic!()
}).push_back(Expr::Block(block)); })
.push_back(Expr::Block(block));
} else { } else {
println!("{}", dbginf.make_msg(crate::msg::ERR40)); //println!("{}", dbginf.make_msg(crate::msg::ERR40));
panic!() panic!()
} }
continue; continue;
}
_ => (),
}, },
_ => () _ => (),
},
_ => ()
} }
expr.push_back(top) expr.push_back(top)
} }
if !expr.is_empty() { if !expr.is_empty() {
blocks.last_mut().unwrap_or_else(|| { blocks
println!("{}", expr.back().unwrap().create_msg(crate::msg::ERR40)); .last_mut()
.unwrap_or_else(|| {
diagnostics.set_err(expr.back().unwrap(), crate::msg::ERR40, "");
panic!() panic!()
}).push_back(Expr::Term(expr)); })
.push_back(Expr::Term(expr));
} }
if let Some(block) = blocks.pop() { if let Some(block) = blocks.pop() {
@ -298,103 +322,150 @@ fn discover_exprs<'a>(functions: &mut Vec<Func<'a>>, _: &Vec<Declr<'a>>, source:
} }
} }
fn check_var_typ(typ: &mut Option<Prim>, operands: &mut Vec<Prim>, dbginf: &crate::token::DebugInfo, source: &str) { fn check_var_typ(
typ: &mut Option<Prim>,
operands: &mut Vec<Prim>,
info: &crate::token::DebugInfo,
diagnostics: &mut data::Diagnostics,
) -> Result<(), ()> {
if let Some(value) = operands.pop() { if let Some(value) = operands.pop() {
if !operands.is_empty() { if !operands.is_empty() {
println!("{}", dbginf.make_msg(crate::msg::ERR50)); diagnostics.set_err(info, crate::msg::ERR50, "");
panic!(); return Err(());
} }
if let Some(typ) = typ { if let Some(typ) = typ {
if !typ.is_equal(value) { if !typ.is_equal(value) {
println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR51, format!("needed {:?} got {:?}", typ, value) )); diagnostics.set_err(
panic!(); info,
crate::msg::ERR51,
format!("needed {:?} got {:?}", typ, value),
);
return Err(());
} }
} else { } else {
// assign a type to untyped variable diagnostics.hint(info, crate::msg::INF51, format!("gessed type: {:?}", value));
println!("{}", dbginf.make_msg_w_ext(crate::msg::INF51, format!("gessed type: {:?}", value) ));
*typ = Some(value); *typ = Some(value);
} }
} else { } else {
println!("{}", dbginf.make_msg(crate::msg::ERR52)); diagnostics.set_err(info, crate::msg::ERR52, "");
panic!(); return Err(());
} }
Ok(())
} }
fn process_keyword(keyword: Keyword, _: &Vec<Declr>, scope: &mut Scope, operands: &mut Vec<Prim>, dbginf: &crate::token::DebugInfo, source: &str) { fn process_keyword(
info: &DebugInfo,
keyword: Keyword,
scope: &mut Scope,
operands: &mut Vec<Prim>,
diagnostics: &mut data::Diagnostics,
) -> Result<(), ()> {
match keyword { match keyword {
Keyword::If | Keyword::While => { Keyword::If | Keyword::While => {
if operands.len() != 1 { if operands.len() != 1 {
println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR53, format!("got {:?} values", operands.len()) )); diagnostics.set_err(
panic!(); info,
crate::msg::ERR53,
format!("got {:?} values", operands.len()),
);
return Err(());
} }
if let Some(operand) = operands.pop() { if let Some(operand) = operands.pop() {
match operand { match operand {
Prim::Bool => (), Prim::Bool => (),
_ => { _ => {
println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR53, format!("got {:?}", operand) )); diagnostics.set_err(info, crate::msg::ERR53, format!("got {:?}", operand));
panic!(); return Err(());
}
} }
} }
} }
},
Keyword::Return => { Keyword::Return => {
if scope.func_return_typ.is_some() { if scope.func_return_typ.is_some() {
println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR54, "perhaps use `yield`" )); diagnostics.set_err(info, crate::msg::ERR54, "perhaps use `yield`");
panic!(); return Err(());
} }
} }
Keyword::Yield => { Keyword::Yield => {
if operands.len() != 1 { if operands.len() != 1 {
println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR55, format!("got {:?} instead of 1", operands.len()) )); diagnostics.set_err(
panic!(); info,
crate::msg::ERR55,
format!("got {:?} instead of 1", operands.len()),
);
return Err(());
} }
if let Some(operand) = operands.pop() { if let Some(operand) = operands.pop() {
if let Some(typ) = scope.func_return_typ { if let Some(typ) = scope.func_return_typ {
if typ != operand { if typ != operand {
println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR59, format!("expected {:?} got {:?}", typ, operand) )); diagnostics.set_err(
panic!(); info,
crate::msg::ERR59,
format!("expected {:?} got {:?}", typ, operand),
);
return Err(());
} }
println!("{}", scope.cond_count);
scope.yields = scope.cond_count == 1; scope.yields = scope.cond_count == 1;
} else { } else {
println!("{}", dbginf.make_msg(crate::msg::ERR57)); diagnostics.set_err(info, crate::msg::ERR57, "");
panic!(); return Err(());
} }
} else { } else {
println!("{}", dbginf.make_msg(crate::msg::ERR58)); diagnostics.set_err(info, crate::msg::ERR58, "");
panic!(); return Err(());
} }
} }
_ => () _ => (),
}
} }
fn collapse_operation(operation: &mut Token, declrs: &Vec<Declr>, scope: &mut Scope, operands: &mut Vec<Prim>, source: &str) { Ok(())
}
fn collapse_operation(
operation: &mut Token,
declrs: &Vec<Declr>,
scope: &mut Scope,
operands: &mut Vec<Prim>,
diagnostics: &mut data::Diagnostics,
) -> Result<(), ()> {
match operation { 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) => { 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); 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<Declr>, _: &mut Scope, operands: &mut Vec<Prim>, dbginf: &crate::token::DebugInfo, source: &str) { fn call_func(
name: &str,
declrs: &Vec<Declr>,
_: &mut Scope,
operands: &mut Vec<Prim>,
dbginf: &crate::token::DebugInfo,
diagnostics: &mut data::Diagnostics,
) {
for declr in declrs { for declr in declrs {
if declr.name.is_some() && declr.name.unwrap() == name { if declr.name.is_some() && declr.name.unwrap() == name {
if let Some(args) = &declr.args { if let Some(args) = &declr.args {
if args.len() > operands.len() { 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!() panic!()
} }
@ -402,7 +473,14 @@ fn call_func(name: &str, declrs: &Vec<Declr>, _: &mut Scope, operands: &mut Vec<
let operand = operands.first().unwrap(); let operand = operands.first().unwrap();
if !operand.is_equal(arg.1) { 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!() panic!()
} }
@ -414,19 +492,23 @@ fn call_func(name: &str, declrs: &Vec<Declr>, _: &mut Scope, operands: &mut Vec<
operands.push(typ); operands.push(typ);
} }
break break;
} }
} }
} }
/// parse a single term using a modified shunting yard /// parse a single term using a modified shunting yard
fn parse_term<'a>(term: &mut VecDeque<Token<'a>>, declrs: &Vec<Declr<'a>>, scope: &mut Scope, source: & str) { fn parse_term<'a>(
term: &mut VecDeque<Token<'a>>,
declrs: &Vec<Declr<'a>>,
scope: &mut Scope,
diagnostics: &mut data::Diagnostics,
) {
let mut op_stack = vec![]; let mut op_stack = vec![];
let mut output = VecDeque::with_capacity(term.len()); let mut output = VecDeque::with_capacity(term.len());
let mut value_stack = vec![]; let mut value_stack = vec![];
'outer: 'outer: while let Some(token) = term.pop_front() {
while let Some(token) = term.pop_front() {
match &token { match &token {
Token::Word(text, dbginf) => { Token::Word(text, dbginf) => {
if is_func(declrs, text) { if is_func(declrs, text) {
@ -441,56 +523,68 @@ fn parse_term<'a>(term: &mut VecDeque<Token<'a>>, declrs: &Vec<Declr<'a>>, scope
output.push_back(Token::Var(text, *dbginf)); output.push_back(Token::Var(text, *dbginf));
continue; continue;
} }
println!("{}", dbginf.make_msg(crate::msg::ERR62)); //println!("{}", dbginf.make_msg(crate::msg::ERR62));
panic!() panic!()
} }
Token::Bool(_, _) => { Token::Bool(_, _) => {
output.push_back(token); output.push_back(token);
value_stack.push(Prim::Bool) value_stack.push(Prim::Bool)
}, }
Token::Number(_, hint, _) => { Token::Number(_, hint, _) => {
output.push_back(token.clone()); output.push_back(token.clone());
value_stack.push(Prim::UntypedNum(*hint)) value_stack.push(Prim::Num(*hint))
}, }
Token::Assign(_, _, _) => { Token::Assign(_, _, _) => {
op_stack.push(token); op_stack.push(token);
}, }
Token::Keyword(_, _) => op_stack.push(token), Token::Keyword(_, _) => op_stack.push(token),
Token::Delemiter(char, dbginf) => { Token::Delemiter(char, dbginf) => match char {
match char {
'(' => op_stack.push(token), '(' => op_stack.push(token),
')' => { ')' => {
while let Some(mut token) = op_stack.pop() { while let Some(mut token) = op_stack.pop() {
match &token { match &token {
Token::Delemiter(char, _) => if *char == '(' { Token::Delemiter(char, _) => {
if *char == '(' {
if let Some(next) = op_stack.last() { if let Some(next) = op_stack.last() {
match &next { match &next {
Token::Func(_, _) => { Token::Func(_, _) => {
let mut token = op_stack.pop().unwrap(); 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); output.push_back(token);
}, }
_ => () _ => (),
} }
} }
continue 'outer; continue 'outer;
}, }
}
_ => { _ => {
collapse_operation(&mut token, declrs, scope, &mut value_stack, source); collapse_operation(
&mut token,
declrs,
scope,
&mut value_stack,
diagnostics,
);
output.push_back(token) output.push_back(token)
} }
} }
} }
println!("{}", dbginf.make_msg(crate::msg::ERR64)); //println!("{}", dbginf.make_msg(crate::msg::ERR64));
panic!(); panic!();
}, }
_ => { _ => {
println!("{}", dbginf.make_msg(crate::msg::ERR65)); //println!("{}", dbginf.make_msg(crate::msg::ERR65));
panic!() panic!()
} }
} },
}
Token::Operator(op, _) => { Token::Operator(op, _) => {
let prec0 = op.prec(); let prec0 = op.prec();
@ -500,43 +594,59 @@ fn parse_term<'a>(term: &mut VecDeque<Token<'a>>, declrs: &Vec<Declr<'a>>, scope
let prec1 = op1.prec(); let prec1 = op1.prec();
if prec1 > prec0 || prec0 == prec1 && op.assoc() == Assoc::Left { 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()); output.push_back(op_stack.pop().unwrap());
continue continue;
} }
break break;
}, }
_ => break _ => break,
} }
} }
op_stack.push(token); op_stack.push(token);
} }
_ => () _ => (),
} }
} }
while let Some(mut token) = op_stack.pop() { while let Some(mut token) = op_stack.pop() {
match &token { match &token {
Token::Delemiter(char, dbginf) => if *char == '(' { Token::Delemiter(char, dbginf) => {
println!("{}", dbginf.make_msg(crate::msg::ERR63)); 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) output.push_back(token)
} }
} }
} }
if value_stack.len() > 1 { if value_stack.len() > 1 {
println!("{}", output[0].create_msg(crate::msg::ERR50)); diagnostics.set_err(&output[0], crate::msg::ERR50, "");
panic!(); return;
} }
scope.expr_yield = value_stack.len() == 1; scope.expr_yield = value_stack.len() == 1;
if scope.expr_yield { if scope.expr_yield {
let yielded = value_stack.pop().unwrap(); let yielded = value_stack.pop().unwrap();
if !yielded.is_equal(scope.func_return_typ.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!(); panic!();
} }
} }
@ -553,20 +663,29 @@ fn is_func(declrs: &[Declr], text: &str) -> bool {
return false; return false;
} }
fn parse_block<'a>(block: &mut Block<'a>, declrs: &Vec<Declr<'a>>, scope: &mut Scope, source: &str) { fn parse_block<'a>(
block: &mut Block<'a>,
declrs: &Vec<Declr<'a>>,
scope: &mut Scope,
diagnostics: &mut data::Diagnostics,
) {
scope.cond_count += 1; scope.cond_count += 1;
scope.alloc_scope(); scope.alloc_scope();
for expr in block.iter_mut() { for expr in block.iter_mut() {
match expr { match expr {
Expr::Block(block) => parse_block(block, declrs, scope, source), Expr::Block(block) => parse_block(block, declrs, scope, diagnostics),
Expr::Term(term) => parse_term(term, declrs, scope, source) Expr::Term(term) => parse_term(term, declrs, scope, diagnostics),
} }
} }
scope.pop_scope(); scope.pop_scope();
scope.cond_count -= 1; scope.cond_count -= 1;
} }
fn parse_exprs<'a>(funcs: &mut Vec<Func<'a>>, declrs: &Vec<Declr<'a>>, source: &'a str) { fn parse_exprs<'a>(
funcs: &mut Vec<Func<'a>>,
declrs: &Vec<Declr<'a>>,
diagnostics: &mut data::Diagnostics,
) {
let mut scope = Scope::new(); let mut scope = Scope::new();
for (x, func) in funcs.iter_mut().enumerate() { for (x, func) in funcs.iter_mut().enumerate() {
@ -577,14 +696,14 @@ fn parse_exprs<'a>(funcs: &mut Vec<Func<'a>>, declrs: &Vec<Declr<'a>>, source: &
scope.yields = false; scope.yields = false;
scope.cond_count = 0; 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 { 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])); //token.create_msg_w_ext(crate::msg::ERR56, format!("at function {}", declrs[x]));
panic!(); 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<Func<'a>>, declrs: &Vec<Declr<'a>>, source: &
/// reorder and organize a listing of instructions to a RPN based format: /// reorder and organize a listing of instructions to a RPN based format:
/// any program is made out of functions. /// 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. /// 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<crate::Token<'a>>, source: &'a str) -> Vec<Func<'a>> { pub fn parse<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &'a str) -> Diagnostics<'a> {
let (mut funcs, declrs) = discover_functions(tokens, source); let mut dias = data::Diagnostics::new(source);
if let Ok((mut funcs, declrs)) = discover_functions(tokens, &mut dias) {
// make all of this shit return a mutable diagnostics struct. // make all of this shit return a mutable diagnostics struct.
discover_exprs(&mut funcs, &declrs, source); discover_exprs(&mut funcs, &declrs, &mut dias);
parse_exprs(&mut funcs, &declrs, source); parse_exprs(&mut funcs, &declrs, &mut dias);
crate::inter::convert_to_erpn(&mut funcs, &declrs); crate::inter::convert_to_erpn(&mut funcs, &declrs);
}
funcs
dias
} }

View File

@ -1,50 +1,200 @@
use crate::token::DebugMsg; use crate::token::DebugMsg;
use crate::token::MessageType::Error; use crate::token::MessageType::Error;
use crate::token::MessageType::Warning;
use crate::token::MessageType::Info; 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 ERR10: &DebugMsg = &DebugMsg {
pub const ERR11: &DebugMsg = &DebugMsg { typ: Error, code: 11, msg: "Function missing return type" }; typ: Error,
pub const ERR12: &DebugMsg = &DebugMsg { typ: Error, code: 12, msg: "Function missing name" }; code: 10,
pub const ERR13: &DebugMsg = &DebugMsg { typ: Error, code: 13, msg: "Open parameter list" }; msg: "Function defined multiple times",
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 ERR11: &DebugMsg = &DebugMsg {
pub const ERR16: &DebugMsg = &DebugMsg { typ: Error, code: 16, msg: "Missing assign for return type" }; typ: Error,
pub const ERR17: &DebugMsg = &DebugMsg { typ: Error, code: 17, msg: "Double function assign" }; code: 11,
pub const ERR18: &DebugMsg = &DebugMsg { typ: Error, code: 18, msg: "Function has multiple names" }; msg: "Function missing return type",
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 ERR12: &DebugMsg = &DebugMsg {
pub const ERR21: &DebugMsg = &DebugMsg { typ: Error, code: 21, msg: "type declaration missing for parameter" }; typ: Error,
pub const ERR22: &DebugMsg = &DebugMsg { typ: Error, code: 22, msg: "token outside of function definition" }; code: 12,
pub const ERR23: &DebugMsg = &DebugMsg { typ: Error, code: 23, msg: "token must be declaration" }; 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 ERR40: &DebugMsg = &DebugMsg {
pub const ERR41: &DebugMsg = &DebugMsg { typ: Error, code: 41, msg: "Closed non existant block" }; 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 ERR50: &DebugMsg = &DebugMsg {
pub const ERR51: &DebugMsg = &DebugMsg { typ: Error, code: 51, msg: "Missmatched variable types" }; typ: Error,
pub const ERR52: &DebugMsg = &DebugMsg { typ: Error, code: 52, msg: "Unable to assign variable type" }; code: 50,
pub const ERR53: &DebugMsg = &DebugMsg { typ: Error, code: 53, msg: "Expected single boolean value" }; msg: "Expression has multiple values",
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 ERR51: &DebugMsg = &DebugMsg {
pub const ERR56: &DebugMsg = &DebugMsg { typ: Error, code: 56, msg: "Function missing return value" }; typ: Error,
pub const ERR57: &DebugMsg = &DebugMsg { typ: Error, code: 57, msg: "Function does not return anything" }; code: 51,
pub const ERR58: &DebugMsg = &DebugMsg { typ: Error, code: 58, msg: "Yield must return a value" }; msg: "Missmatched variable types",
pub const ERR59: &DebugMsg = &DebugMsg { typ: Error, code: 59, msg: "Missmatched function return type" }; };
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 ERR60: &DebugMsg = &DebugMsg {
pub const ERR61: &DebugMsg = &DebugMsg { typ: Error, code: 61, msg: "Missmatched parameter type" }; typ: Error,
pub const ERR62: &DebugMsg = &DebugMsg { typ: Error, code: 62, msg: "Unknown symbol" }; code: 60,
pub const ERR63: &DebugMsg = &DebugMsg { typ: Error, code: 63, msg: "Missing left parenthesis" }; msg: "Missmatched parameter count",
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 ERR61: &DebugMsg = &DebugMsg {
typ: Error,
pub const ERR70: &DebugMsg = &DebugMsg { typ: Error, code: 70, msg: "Unknown type declaration"}; code: 61,
pub const ERR71: &DebugMsg = &DebugMsg { typ: Error, code: 71, msg: "Unable to identify characters as token"}; msg: "Missmatched parameter type",
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 ERR62: &DebugMsg = &DebugMsg {
pub const ERR74: &DebugMsg = &DebugMsg { typ: Error, code: 74, msg: "Missing operands"}; 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",
};

View File

@ -1,12 +1,14 @@
use colored::{ColoredString, Colorize};
use std::collections::VecDeque; use std::collections::VecDeque;
use colored::{Colorize, ColoredString};
#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)] #[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)]
pub enum Operator { pub enum Operator {
// bitwise boolean operations
Or, Or,
And, And,
Xor, Xor,
// comparisons
Eq, Eq,
Lt, Lt,
Gt, Gt,
@ -14,20 +16,48 @@ pub enum Operator {
LtEq, LtEq,
NotEq, NotEq,
// arithmetic
Add, Add,
Sub, Sub,
Mul, Mul,
Div, Div,
Assign Assign,
} }
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Assoc { pub enum Assoc {
Right, 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 { impl Operator {
pub fn parse<'a>(str: &'a str) -> Self { pub fn parse<'a>(str: &'a str) -> Self {
return match str { return match str {
@ -48,7 +78,10 @@ impl Operator {
"/" => Operator::Div, "/" => Operator::Div,
"=" => Operator::Assign, "=" => Operator::Assign,
_ => panic!("Unspecified operator") _ => {
crate::message(MessageType::Critical, "Unknown operator");
panic!();
}
}; };
} }
@ -57,6 +90,7 @@ impl Operator {
Operator::Eq => 2, Operator::Eq => 2,
Operator::Lt => 2, Operator::Lt => 2,
Operator::Gt => 2, Operator::Gt => 2,
Operator::NotEq => 2,
Operator::LtEq => 2, Operator::LtEq => 2,
Operator::GtEq => 2, Operator::GtEq => 2,
@ -66,113 +100,152 @@ impl Operator {
Operator::Add => 3, Operator::Add => 3,
Operator::Sub => 3, Operator::Sub => 3,
Operator::Mul => 4, Operator::Mul => 4,
Operator::Div => 4, Operator::Div => 4,
_ => 0 Operator::Assign => 0,
} };
} }
pub fn assoc(&self) -> Assoc { pub fn assoc(&self) -> Assoc {
match self { match self {
_ => Assoc::Right _ => Assoc::Right,
} }
} }
fn present_types(operands: &[Prim], types: &[Prim], r#yield: Prim, dbginf: &DebugInfo, source: &str) -> Option<Prim> { fn present_types(
operands: &[Prim],
types: &[Prim],
r#yield: Prim,
dbginf: &DebugInfo,
diagnostics: &mut crate::parser::data::Diagnostics,
) -> Option<Prim> {
if operands.len() < types.len() { 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!() panic!()
} }
for (x, typ) in types.iter().enumerate() { for (x, typ) in types.iter().enumerate() {
if typ != &operands[x] { if typ != &operands[x] {
return None return None;
} }
} }
Some(r#yield) Some(r#yield)
} }
fn check_types(operands: &[Prim], types: &[(Vec<Prim>, Prim)], dbginf: &DebugInfo, source: &str) -> Option<Prim> { fn check_types(
operands: &[Prim],
types: &[(&[Prim], Prim)],
dbginf: &DebugInfo,
diagnostics: &mut crate::parser::data::Diagnostics,
) -> Option<Prim> {
for combination in types.iter() { for combination in types.iter() {
if let Some(result) =
if let Some(result) = Self::present_types(operands, &combination.0, combination.1, dbginf, source) { Self::present_types(operands, combination.0, combination.1, dbginf, diagnostics)
{
return Some(result); return Some(result);
} }
} }
None None
} }
pub fn operate(&self, operands: &mut Vec<Prim>, dbginf: &DebugInfo, source: &str) { pub fn operate(
&self,
operands: &mut Vec<Prim>,
dbginf: &DebugInfo,
diagnostics: &mut crate::parser::data::Diagnostics,
) {
match self { match self {
Operator::Add | Operator::Sub | Operator::Mul | Operator::Div => { Operator::Add | Operator::Sub | Operator::Mul | Operator::Div => {
let types_valid = Self::check_types(operands, &[ let types_valid =
// +------------------------------------------------------------------------------------+---------------------------------+ Self::check_types(operands, ARITHMETIC_TYPES, dbginf, diagnostics);
// | 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);
if let Some(result) = types_valid { if let Some(result) = types_valid {
operands.pop(); operands.pop();
operands.pop(); operands.pop();
operands.push(result); operands.push(result);
} else { } 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!()
} }
}, }
Operator::And | Operator::Or | Operator::Xor => { Operator::And | Operator::Or | Operator::Xor => {
let types_valid = Self::check_types(operands, &[ let types_valid = Self::check_types(
(vec![Prim::Bool, Prim::Bool ], Prim::Bool), operands,
], dbginf, source); &[(&[Prim::Bool, Prim::Bool], Prim::Bool)],
dbginf,
diagnostics,
);
if let Some(result) = types_valid { if let Some(result) = types_valid {
operands.pop(); operands.pop();
operands.pop(); operands.pop();
operands.push(result); operands.push(result);
} else { } 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!() panic!()
} }
}, }
Operator::Eq | Operator::NotEq | Operator::Lt | Operator::Gt | Operator::GtEq | Operator::LtEq => { Operator::Eq
let types_valid = Self::check_types(operands, &[ | Operator::NotEq
// +------------------------------------------------------------------------------------+---------------------------------+ | Operator::Lt
// | Parameter list of types | result type | | Operator::Gt
// +------------------------------------------------------------------------------------+---------------------------------+ | Operator::GtEq
(vec![Prim::Int, Prim::Int ], Prim::Bool ), | Operator::LtEq => {
(vec![Prim::Rat, Prim::Rat ], Prim::Bool ), let types_valid = Self::check_types(
(vec![Prim::UntypedNum(NumberClassHint::Int), Prim::Int ], Prim::Bool ), operands,
(vec![Prim::UntypedNum(NumberClassHint::Rat), Prim::Rat ], Prim::Bool ), &[
(vec![Prim::Int, Prim::UntypedNum(NumberClassHint::Int)], Prim::Bool ), (&[Prim::Int, Prim::Int], Prim::Bool),
(vec![Prim::Rat, Prim::UntypedNum(NumberClassHint::Rat)], Prim::Bool ), (&[Prim::Rat, Prim::Rat], Prim::Bool),
(vec![Prim::UntypedNum(NumberClassHint::Rat), Prim::UntypedNum(NumberClassHint::Rat)], Prim::Bool ), (&[Prim::Num(NumHint::Int), Prim::Int], Prim::Bool),
(vec![Prim::UntypedNum(NumberClassHint::Int), Prim::UntypedNum(NumberClassHint::Int)], Prim::Bool ) (&[Prim::Num(NumHint::Rat), Prim::Rat], Prim::Bool),
], dbginf, source); (&[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 { if let Some(result) = types_valid {
operands.pop(); operands.pop();
operands.pop(); operands.pop();
operands.push(result); operands.push(result);
} else { } 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!()
} }
}, }
_ => { _ => {
panic!("Unknown operator"); panic!("Unknown operator");
} }
@ -204,25 +277,30 @@ impl Keyword {
"ret" => Keyword::Return, "ret" => Keyword::Return,
"yield" => Keyword::Yield, "yield" => Keyword::Yield,
"please" => Keyword::Please, "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)] #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
pub enum NumberClassHint { pub enum NumHint {
Int, Int,
Rat Rat,
} }
impl NumberClassHint { impl NumHint {
pub fn from(str: &str) -> NumHint {
pub fn from(str: &str) -> NumberClassHint {
if str.parse::<i32>().is_err() { if str.parse::<i32>().is_err() {
return NumberClassHint::Rat; return NumHint::Rat;
} }
NumberClassHint::Int NumHint::Int
} }
} }
@ -232,45 +310,52 @@ pub enum Prim {
Int, Int,
Rat, Rat,
Bool, Bool,
UntypedNum(NumberClassHint) Num(NumHint),
} }
impl Prim { 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 { return match text {
"int" => Prim::Int, "int" => Prim::Int,
"rat" => Prim::Rat, "rat" => Prim::Rat,
"bool" => Prim::Bool, "bool" => Prim::Bool,
_ => { _ => {
println!("{}", dbginf.make_msg(&crate::msg::ERR70)); //println!("{}", dbginf.make_msg(&crate::msg::ERR70));
panic!() panic!()
} }
} };
} }
pub fn is_equal(&self, value: Prim) -> bool { pub fn is_equal(&self, value: Prim) -> bool {
return match self { return match self {
Prim::Bool => *self == value, Prim::Bool => *self == value,
Prim::Rat => return match value { Prim::Rat => {
Prim::UntypedNum(NumberClassHint::Int) => true, return match value {
Prim::UntypedNum(NumberClassHint::Rat) => true, Prim::Num(NumHint::Int) => true,
Prim::Num(NumHint::Rat) => true,
_ => *self == value, _ => *self == value,
}, }
Prim::Int => return match value { }
Prim::UntypedNum(NumberClassHint::Int) => true, Prim::Int => {
return match value {
Prim::Num(NumHint::Int) => true,
_ => *self == value, _ => *self == value,
}, }
Prim::UntypedNum(NumberClassHint::Rat) => return match value { }
Prim::Num(NumHint::Rat) => {
return match value {
Prim::Rat | Prim::Int => true, Prim::Rat | Prim::Int => true,
_ => *self == value, _ => *self == value,
}, }
Prim::UntypedNum(NumberClassHint::Int) => return match value { }
Prim::Num(NumHint::Int) => {
return match value {
Prim::Int => true, Prim::Int => true,
_ => *self == value, _ => *self == value,
},
} }
} }
};
}
} }
pub struct DebugMsg { pub struct DebugMsg {
@ -279,65 +364,69 @@ pub struct DebugMsg {
pub msg: &'static str, pub msg: &'static str,
} }
pub struct DebugErr<'a> { pub struct DebugNotice<'a> {
info: DebugInfo<'a>, pub info: DebugInfo,
/// generic error description /// generic error description
msg: &'static DebugMsg, pub msg: &'static DebugMsg,
/// extra message which is case specific /// extra message which is case specific
ext: Option<String>, 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 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// write header as: // write header as:
// `Error (56) some syntax error message in line 5:` // `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.typ.to_colored(),
self.msg.code, self.msg.code,
self.msg.msg.bold().bright_white(), self.msg.msg.bold().bright_white(),
self.info.line, self.info.line,
self.ext.as_ref().unwrap_or(&String::new()) self.ext
)); ));
// write additional information // 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)] #[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 /// 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 /// 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 number where the line in which the token is begins
line: usize, pub 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<T>(&self, msg: &'static DebugMsg, ext: T) -> DebugErr where T: Into<String> {
DebugErr {
info: self.clone(),
msg,
ext: Some(ext.into())
}
}
} }
#[derive(Debug)] #[derive(Debug)]
pub enum MessageType { pub enum MessageType {
/// For internal compiler critical error
Critical,
/// compile errors that won't allow for further compilation
Error, Error,
Warning, Warning,
Info Info,
} }
impl MessageType { impl MessageType {
@ -348,21 +437,16 @@ impl MessageType {
pub fn to_colored(&self) -> ColoredString { pub fn to_colored(&self) -> ColoredString {
let raw = format!("{:#?}", self); let raw = format!("{:#?}", self);
return match self { return match self {
MessageType::Critical => raw.on_red().bold(),
MessageType::Error => raw.red().bold(), MessageType::Error => raw.red().bold(),
MessageType::Warning => raw.yellow().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 { 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(()) 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. /// They give a meaning to patterns of chars allowing to interpret them.
pub enum Token<'a> { pub enum Token<'a> {
// base tokens that can simply be split to from raw source code // 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 ```(```,```}``` /// Single symbol delemiter like ```(```,```}```
Delemiter(char, DebugInfo<'a>), Delemiter(char, DebugInfo),
Operator(Operator, DebugInfo<'a>), Operator(Operator, DebugInfo),
Number(&'a str, NumberClassHint, DebugInfo<'a>), Number(&'a str, NumHint, DebugInfo),
LineBreak(DebugInfo<'a>), LineBreak(DebugInfo),
Func(&'a str, DebugInfo<'a>), Func(&'a str, DebugInfo),
/// Variable /// Variable
Var(&'a str, DebugInfo<'a>), Var(&'a str, DebugInfo),
/// Function argument /// Function argument
Arg(&'a str, DebugInfo<'a>), Arg(&'a str, DebugInfo),
/// Variable assignment in the form of ```name = ``` /// Variable assignment in the form of ```name = ```
Assign(&'a str, Option<Prim>, DebugInfo<'a>), Assign(&'a str, Option<Prim>, DebugInfo),
/// Variable type declaration in the form of ```name:type``` /// Variable type declaration in the form of ```name:type```
Decl(&'a str, Prim, DebugInfo<'a>), Decl(&'a str, Prim, DebugInfo),
Bool(bool, DebugInfo<'a>), Bool(bool, DebugInfo),
/// Keywords like ```if```,```break```,```while``` /// Keywords like ```if```,```break```,```while```
Keyword(Keyword, DebugInfo<'a>), Keyword(Keyword, DebugInfo),
Type(Prim, DebugInfo<'a>), Type(Prim, DebugInfo),
/// Semicolon /// Semicolon
Terminator(DebugInfo<'a>) Terminator(DebugInfo),
} }
impl<'a> std::fmt::Display for Token<'a> { impl<'a> std::fmt::Display for Token<'a> {
@ -416,8 +500,8 @@ impl<'a> std::fmt::Display for Token<'a> {
} }
} }
impl<'a> Token<'a> { impl<'a> Into<DebugInfo> for Token<'a> {
fn debug_info(&self) -> &DebugInfo { fn into(self) -> DebugInfo {
match self { match self {
Token::Type(_, d) => d, Token::Type(_, d) => d,
Token::Word(_, d) => d, Token::Word(_, d) => d,
@ -435,14 +519,6 @@ impl<'a> Token<'a> {
Token::Terminator(d) => d, 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<T>(&self, msg: &'static DebugMsg, ext: T) -> DebugErr where T: Into<String> {
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)|(;)"; 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. /// creates a vector of tokens from the specified str.
pub fn tokenize<'a>(source: &'a str) -> VecDeque<Token<'a>> { pub fn tokenize(source: &str) -> VecDeque<Token> {
let mut tokens = VecDeque::new(); let mut tokens = VecDeque::new();
let mut line_count = 0; let mut line_count = 0;
let mut line_start = 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(); let mut enumerator = cap.iter().enumerate();
loop { loop {
let next = enumerator.next(); let next = enumerator.next();
if next.is_none() { if next.is_none() {
break break;
} }
let (i, group) = next.unwrap(); let (i, group) = next.unwrap();
@ -477,43 +553,41 @@ pub fn tokenize<'a>(source: &'a str) -> VecDeque<Token<'a>> {
// if we have a match, save it as token // if we have a match, save it as token
if let Some(mat) = group { if let Some(mat) = group {
let debug_info = DebugInfo { let debug_info = DebugInfo {
source,
start: mat.start() - line_start, start: mat.start() - line_start,
end: mat.end() - line_start, end: mat.end() - line_start,
line: line_count line: line_count,
}; };
tokens.push_back(match i { tokens.push_back(match i {
2 => Token::Keyword(Keyword::parse(mat.as_str()), debug_info), 2 => Token::Keyword(Keyword::parse(mat.as_str()), debug_info),
3 => { 3 => Token::Type(Prim::from(mat.as_str(), &debug_info), debug_info),
Token::Type(Prim::from(mat.as_str(), &debug_info, source), debug_info)
},
4 => Token::Bool(parse_bool(mat.as_str()), debug_info), 4 => Token::Bool(parse_bool(mat.as_str()), debug_info),
5 => { 5 => {
let var_type = if let Some(mat) = enumerator.next().unwrap().1 { 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 { } else {
None None
}; };
Token::Assign(mat.as_str(), var_type, debug_info) Token::Assign(mat.as_str(), var_type, debug_info)
}, }
7 => { 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) Token::Decl(mat.as_str(), var_type, debug_info)
}, }
9 => Token::Word(mat.as_str(), 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), 11 => Token::Operator(Operator::parse(mat.as_str()), debug_info),
12 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap(), debug_info), 12 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap(), debug_info),
13 => { 13 => {
line_count += 1; line_count += 1;
line_start = mat.start(); line_start = mat.start();
Token::LineBreak(debug_info) Token::LineBreak(debug_info)
}, }
14 => Token::Terminator(debug_info), 14 => Token::Terminator(debug_info),
_ => { _ => {
println!("{}", debug_info.make_msg(crate::msg::ERR71)); //println!("{}", debug_info.make_msg(crate::msg::ERR71));
panic!() panic!()
} }
}); });
@ -530,6 +604,6 @@ fn parse_bool(text: &str) -> bool {
"true" | "ye" => true, "true" | "ye" => true,
"false" | "no" => false, "false" | "no" => false,
"maybe" => rand::random(), "maybe" => rand::random(),
_ => panic!("Not a recognized boolean {text}") _ => panic!("Not a recognized boolean {text}"),
} };
} }