added argument flags

This commit is contained in:
Sven Vogel 2022-11-28 19:10:29 +01:00
parent d3f121640a
commit fda09066c7
7 changed files with 366 additions and 200 deletions

34
src/conf/mod.rs Normal file
View File

@ -0,0 +1,34 @@
use crate::parser::data::Diagnostics;
pub struct Settings {
gen_erpn: bool
}
impl Settings {
fn new() -> Self {
Settings {
gen_erpn: false
}
}
pub fn gen_erpn(&self) -> bool {
self.gen_erpn
}
}
pub fn parse_args(diagnostics: &mut Diagnostics) -> Settings {
let args = std::env::args().collect::<Vec<String>>();
let mut settings = Settings::new();
for arg in args.iter() {
match arg.as_str() {
"--no-info" => diagnostics.set_loglvl(crate::parser::data::LogLvl::Warn),
"--no-warn" => diagnostics.set_loglvl(crate::parser::data::LogLvl::Err),
"--erpn" => settings.gen_erpn = true,
_ => ()
}
}
settings
}

View File

@ -5,11 +5,14 @@ mod parser;
// translate a tree of functions and expressions to pseudo assembly
// designed for a virtual stack machiene
mod inter;
mod conf;
use colored::Colorize;
use parser::*;
use token::*;
use crate::parser::data::Diagnostics;
pub fn message<S>(typ: MessageType, msg: S)
where
S: Into<String>,
@ -19,7 +22,7 @@ where
fn main() {
let source = r"
# this is pi
# surely this is pi
pi = rat 5.1415926535
foo(x:int, y:rat) = bool {
@ -38,19 +41,26 @@ foo(x:int, y:rat) = bool {
}
-- comment
yield false
yield true
}
main() = int {
a = 4
b = 5.5
c = true
r = foo(3, 3.4)
r = foo(3, ffalsee)
0
}
";
let diagnostics = parse(&mut tokenize(source), source);
let mut diagnostics = Diagnostics::new(source);
let settings = conf::parse_args(&mut diagnostics);
if let Ok(mut tokens) = tokenize(source, &mut diagnostics) {
parse(&mut tokens, &mut diagnostics, &settings);
}
println!("{}", diagnostics);
}

View File

@ -1,8 +1,18 @@
use crate::token::{DebugInfo, DebugNotice, Token};
use crate::token::{DebugInfo, DebugNotice, Token, MessageType};
use crate::Prim;
use core::panic;
use std::collections::VecDeque;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum LogLvl {
/// print everything
Info,
/// print only errors and warning
Warn,
/// print only errors
Err,
}
pub struct Diagnostics<'a> {
/// terminating factor on error
err: Option<DebugNotice<'a>>,
@ -11,6 +21,8 @@ pub struct Diagnostics<'a> {
hints: Vec<DebugNotice<'a>>,
/// source string
source: &'a str,
/// flags
loglvl: LogLvl,
}
impl<'a> Diagnostics<'a> {
@ -19,9 +31,14 @@ impl<'a> Diagnostics<'a> {
err: None,
hints: vec![],
source,
loglvl: LogLvl::Info
}
}
pub fn set_loglvl(&mut self, lvl: LogLvl) {
self.loglvl = lvl;
}
pub fn set_err<T, S>(&mut self, source: &S, message: &'static crate::token::DebugMsg, ext: T)
where
T: Into<String>,
@ -60,6 +77,16 @@ impl<'a> Diagnostics<'a> {
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() {
match hint.msg.typ {
MessageType::Info => if self.loglvl != LogLvl::Info {
continue;
},
MessageType::Warning => if self.loglvl == LogLvl::Err {
continue;
},
_ => (),
}
f.write_fmt(format_args!("{}\n\n", hint)).unwrap();
}
@ -98,6 +125,9 @@ pub struct Declr<'a> {
pub results: bool,
/// type of result
pub result_typ: Option<Prim>,
/// debug info
pub info: Option<DebugInfo>
}
impl<'a> Declr<'a> {
@ -107,6 +137,7 @@ impl<'a> Declr<'a> {
args: None,
results: false,
result_typ: None,
info: None,
}
}
}
@ -134,6 +165,10 @@ impl<'a> std::fmt::Display for Declr<'a> {
f.write_str(" =")?;
}
if let Some(typ) = self.result_typ {
f.write_fmt(format_args!(" {:?}", typ))?;
}
f.write_str(" {}")
}
}

View File

@ -1,4 +1,4 @@
use crate::token::{Assoc, DebugInfo, Keyword, Operator, Prim, Token};
use crate::{token::{Assoc, DebugInfo, Keyword, Operator, Prim, Token}, conf::Settings};
use core::panic;
use std::{collections::VecDeque, vec};
@ -12,6 +12,7 @@ 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 declrs = Vec::new();
@ -27,6 +28,7 @@ fn discover_functions<'a>(
macro_rules! finish_func {
($token:expr) => {
// check if the function is already declared
if declrs.contains(&declr) {
diagnostics.set_err(
$token,
@ -36,13 +38,17 @@ fn discover_functions<'a>(
return Err(());
}
// check if the function returns sth but no return value is given
if declr.results && declr.result_typ.is_none() {
diagnostics.set_err($token, crate::msg::ERR11, format!("for function {declr}"));
return Err(());
}
// store new function and its declaration
funcs.push(func);
declrs.push(declr);
// create new empty function
declr = Declr::new();
func = Func::new();
single_line = false;
@ -53,17 +59,20 @@ fn discover_functions<'a>(
// function body detection
// has highest priority
match &top {
Token::Delemiter(char, dbginf) => match char {
Token::Delemiter(char, _) => match char {
// open body
'{' => {
brace_cnt += 1;
// we have an found open function body
if brace_cnt == 1 {
// check if we have a name for our function
if declr.name.is_none() {
diagnostics.set_err(&top, crate::msg::ERR12, "");
return Err(());
}
// check if the parameter list was closed
if paren_cnt > 0 {
diagnostics.set_err(&top, crate::msg::ERR13, "");
return Err(());
@ -92,8 +101,10 @@ fn discover_functions<'a>(
_ => (),
},
Token::Type(typ, dbginf) => {
Token::Type(typ, _) => {
// check if we already have a result type
if declr.result_typ.is_none() {
// then check if we even need to return sth.
if declr.results {
declr.result_typ = Some(*typ);
continue;
@ -101,10 +112,13 @@ fn discover_functions<'a>(
diagnostics.set_err(&top, crate::msg::ERR16, "");
return Err(());
}
} else {
diagnostics.set_err(&top, crate::msg::ERR24, "");
return Err(());
}
}
Token::LineBreak(dbginf) => {
Token::LineBreak(_) => {
if single_line {
finish_func!(&top);
continue;
@ -120,12 +134,15 @@ fn discover_functions<'a>(
if func.raw.is_none() {
match &top {
Token::Operator(op, dbginf) => match op {
Token::Operator(op, _) => match op {
Operator::Assign => {
// check if we already have an assign
if declr.results {
diagnostics.set_err(&top, crate::msg::ERR17, "");
return Err(());
}
// check if we even have a function name
// which must always be first
if declr.name.is_none() {
diagnostics.set_err(&top, crate::msg::ERR12, "");
return Err(());
@ -138,26 +155,38 @@ fn discover_functions<'a>(
_ => (),
},
Token::Word(text, dbginf) => {
Token::Word(text, info) => {
// check if we have a function name
if declr.name.is_some() {
// we have a function name check if we have no open argument list.
// if so this word is missplaced
if declr.args.is_none() {
diagnostics.set_err(&top, crate::msg::ERR18, "");
return Err(());
}
// function body is open and we have no function name
} else if brace_cnt > 0 {
diagnostics.set_err(&top, crate::msg::ERR13, "");
return Err(());
// this must be a valid function name
} else {
declr.name = Some(text);
declr.info = Some(info.to_owned());
continue;
}
}
Token::Assign(name, _, dbginf) => {
Token::Assign(name, _, info) => {
// check if we already marked a return type
// we dont want a double assignment
if declr.results {
diagnostics.set_err(&top, crate::msg::ERR17, "");
return Err(());
}
// check if we already set function name
// then we dont want to reassign
if declr.name.is_some() {
diagnostics.set_err(&top, crate::msg::ERR18, "");
return Err(());
@ -165,16 +194,22 @@ fn discover_functions<'a>(
func.raw = Some(VecDeque::new());
declr.name = Some(name);
declr.info = Some(info.to_owned());
declr.results = true;
single_line = true;
continue;
}
Token::Delemiter(char, dbginf) => match char {
Token::Delemiter(char, _) => match char {
'(' => {
// check for no existing function body
// if we have none we can open an parameter list
if func.raw.is_none() {
paren_cnt += 1;
// check if we have one open parenthsis
if paren_cnt == 1 {
// we have some arguments then we have a double parameter list
// dont want that
if declr.args.is_some() {
diagnostics.set_err(&top, crate::msg::ERR19, "");
return Err(());
@ -198,9 +233,14 @@ fn discover_functions<'a>(
}
if let Some(body) = &mut func.raw {
// if we have an open function body
// drop all token in there till it closes
body.push_back(top);
continue;
// check for open parameter list
} else if let Some(args) = &mut declr.args {
// the parameter list is closed
if paren_cnt == 0 {
diagnostics.set_err(&top, crate::msg::ERR20, "");
return Err(());
@ -208,7 +248,9 @@ fn discover_functions<'a>(
match &top {
Token::Decl(name, typ, _dbginf) => args.push((name, *typ)),
Token::Word(_, dbginf) => {
// as parameter we only accept declarations
Token::Word(_, _) => {
diagnostics.set_err(&top, crate::msg::ERR21, "");
return Err(());
}
@ -231,6 +273,7 @@ fn discover_functions<'a>(
}
if let Some(raw) = func.raw {
// still some raw unused tokens left over
if let Some(front) = raw.front() {
diagnostics.set_err(front, crate::msg::ERR15, "");
return Err(());
@ -247,7 +290,8 @@ fn discover_exprs<'a>(
functions: &mut Vec<Func<'a>>,
_: &Vec<Declr<'a>>,
diagnostics: &mut data::Diagnostics,
) {
) -> Result<(),()> {
for func in functions.iter_mut() {
let mut blocks = vec![Block::new()];
@ -255,27 +299,27 @@ fn discover_exprs<'a>(
while let Some(top) = func.raw.as_mut().unwrap().pop_front() {
match &top {
Token::LineBreak(dbginf) | Token::Terminator(dbginf) => {
Token::LineBreak(_) | Token::Terminator(_) => {
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;
return Err(());
}
expr = VecDeque::new();
continue;
}
}
Token::Delemiter(char, dbginf) => match char {
Token::Delemiter(char, _) => match char {
'{' => {
blocks
.last_mut()
.unwrap_or_else(|| {
if let Some(block) = blocks.last_mut() {
block.push_back(Expr::Term(expr));
} else {
diagnostics.set_err(&top, crate::msg::ERR41, "");
panic!()
})
.push_back(Expr::Term(expr));
return Err(());
}
expr = VecDeque::new();
blocks.push(Block::new());
continue;
@ -283,17 +327,22 @@ fn discover_exprs<'a>(
'}' => {
// 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));
if let Some(dst) = blocks.last_mut() {
dst.push_back(Expr::Block(block));
} else {
//println!("{}", dbginf.make_msg(crate::msg::ERR40));
panic!()
diagnostics.set_err(&top, crate::msg::ERR41, "");
return Err(());
}
} else {
diagnostics.set_err(&top, crate::msg::ERR40, "");
return Err(());
}
if blocks.is_empty() {
diagnostics.set_err(&top, crate::msg::ERR41, "");
return Err(());
}
continue;
}
_ => (),
@ -305,21 +354,19 @@ fn discover_exprs<'a>(
}
if !expr.is_empty() {
blocks
.last_mut()
.unwrap_or_else(|| {
if let Some(block) = blocks.last_mut() {
block.push_back(Expr::Term(expr));
} else {
diagnostics.set_err(expr.back().unwrap(), crate::msg::ERR40, "");
panic!()
})
.push_back(Expr::Term(expr));
return Err(());
}
}
if let Some(block) = blocks.pop() {
func.expr = Some(Expr::Block(block));
} else {
panic!("curly brace missmatch")
}
}
Ok(())
}
fn check_var_typ(
@ -328,7 +375,7 @@ fn check_var_typ(
info: &crate::token::DebugInfo,
diagnostics: &mut data::Diagnostics,
) -> Result<(), ()> {
if let Some(value) = operands.pop() {
if let Some(mut value) = operands.pop() {
if !operands.is_empty() {
diagnostics.set_err(info, crate::msg::ERR50, "");
return Err(());
@ -345,6 +392,17 @@ fn check_var_typ(
}
} else {
diagnostics.hint(info, crate::msg::INF51, format!("gessed type: {:?}", value));
// resolve to concrete typ
// i.e all Prim::Num(hint) will convert to their hints.
value = match value {
Prim::Num(hint) => match hint {
crate::token::NumHint::Int => Prim::Int,
crate::token::NumHint::Rat => Prim::Rat,
}
_ => value
};
*typ = Some(value);
}
} else {
@ -362,7 +420,7 @@ fn process_keyword(
diagnostics: &mut data::Diagnostics,
) -> Result<(), ()> {
match keyword {
Keyword::If | Keyword::While => {
Keyword::Unless | Keyword::While => {
if operands.len() != 1 {
diagnostics.set_err(
info,
@ -431,70 +489,78 @@ fn collapse_operation(
operands: &mut Vec<Prim>,
diagnostics: &mut data::Diagnostics,
) -> Result<(), ()> {
match operation {
Token::Operator(op, dbginf) => op.operate(operands, &dbginf, diagnostics),
Token::Assign(name, mut typ, dbginf) => {
check_var_typ(&mut typ, operands, &dbginf, diagnostics)?;
scope.decl_var((*name).to_owned(), typ);
Token::Operator(op, dbginf) => op.operate(operands, &dbginf, diagnostics)?,
Token::Assign(name, ref mut typ, dbginf) => {
check_var_typ(typ, operands, &dbginf, diagnostics)?;
scope.decl_var((*name).to_owned(), typ.clone());
}
Token::Func(name, dbginf) => call_func(name, declrs, scope, operands, &dbginf, diagnostics),
Token::Func(name, dbginf) => {
call_func(name, declrs, operands, &dbginf, diagnostics)?;
},
Token::Keyword(keyword, dbginf) => {
process_keyword(dbginf, *keyword, scope, operands, diagnostics)?
process_keyword(dbginf, *keyword, scope, operands, diagnostics)?;
}
_ => (),
}
Ok(())
return Ok(());
}
fn call_func(
name: &str,
declrs: &Vec<Declr>,
_: &mut Scope,
operands: &mut Vec<Prim>,
dbginf: &crate::token::DebugInfo,
info: &DebugInfo,
diagnostics: &mut data::Diagnostics,
) {
) -> Result<(), ()> {
// find the function in our function declarations by its name
for declr in declrs {
if declr.name.is_some() && declr.name.unwrap() == name {
// check if declaration name matches the function name
if let Some(declr_name) = declr.name {
if declr_name != name {
continue;
}
} else {
// some critical compiler error
crate::message(crate::token::MessageType::Critical, "Missing function name in declaration");
panic!();
}
if let Some(args) = &declr.args {
// check if we have enough parameter on the stack
// note that the stack may contain more than just the functions
// // parameters
if args.len() > operands.len() {
/*
println!(
"{}",
dbginf.make_msg_w_ext(
crate::msg::ERR60,
format!("expected {:?} got {:?}", args.len(), operands.len())
)
);*/
panic!()
diagnostics.set_err(info, crate::msg::ERR60, format!("expected {:?} got {:?}", args.len(), operands.len()));
return Err(());
}
// check parameter types
for (x, arg) in args.iter().enumerate() {
// parameter are in reverse order on the stack
// so they are placed at the bottom
let operand = operands.first().unwrap();
// check types
if !operand.is_equal(arg.1) {
/*
println!(
"{}",
dbginf.make_msg_w_ext(
crate::msg::ERR61,
format!("expected {:?} got {:?}", arg, operand)
)
);*/
panic!()
diagnostics.set_err(info, crate::msg::ERR61, format!("expected {:?} got {:?} as {}th argument", arg, operand, x));
return Err(());
}
operands.remove(0);
}
}
// if the function returns sth. we will add
// its type to the stack
// assuming the execution was successfull
if let Some(typ) = declr.result_typ {
operands.push(typ);
}
break;
}
}
Ok(())
}
/// parse a single term using a modified shunting yard
@ -503,28 +569,36 @@ fn parse_term<'a>(
declrs: &Vec<Declr<'a>>,
scope: &mut Scope,
diagnostics: &mut data::Diagnostics,
) {
) -> Result<(),()> {
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() {
match &token {
// resolve word to either a function, parameter or variable
Token::Word(text, dbginf) => {
// test for function
if is_func(declrs, text) {
op_stack.push(Token::Func(text, *dbginf));
continue;
// test for function parameter
} else if scope.is_arg(text) {
value_stack.push(scope.get_arg_type(text));
output.push_back(Token::Arg(text, *dbginf));
continue;
// test for variable in scope
} else if scope.is_var(text).is_some() {
value_stack.push(scope.get_var_type(text));
output.push_back(Token::Var(text, *dbginf));
continue;
}
//println!("{}", dbginf.make_msg(crate::msg::ERR62));
panic!()
// word was not reolved to anything
diagnostics.set_err(&token, crate::msg::ERR62, "");
return Err(());
}
Token::Bool(_, _) => {
output.push_back(token);
@ -539,7 +613,7 @@ fn parse_term<'a>(
}
Token::Keyword(_, _) => op_stack.push(token),
Token::Delemiter(char, dbginf) => match char {
Token::Delemiter(char, _) => match char {
'(' => op_stack.push(token),
')' => {
while let Some(mut token) = op_stack.pop() {
@ -556,7 +630,7 @@ fn parse_term<'a>(
scope,
&mut value_stack,
diagnostics,
);
)?;
output.push_back(token);
}
_ => (),
@ -572,17 +646,17 @@ fn parse_term<'a>(
scope,
&mut value_stack,
diagnostics,
);
)?;
output.push_back(token)
}
}
}
//println!("{}", dbginf.make_msg(crate::msg::ERR64));
panic!();
diagnostics.set_err(&token, crate::msg::ERR64, "");
return Err(());
}
_ => {
//println!("{}", dbginf.make_msg(crate::msg::ERR65));
panic!()
diagnostics.set_err(&token, crate::msg::ERR65, "");
return Err(());
}
},
@ -600,7 +674,7 @@ fn parse_term<'a>(
scope,
&mut value_stack,
diagnostics,
);
)?;
output.push_back(op_stack.pop().unwrap());
continue;
}
@ -617,13 +691,14 @@ fn parse_term<'a>(
while let Some(mut token) = op_stack.pop() {
match &token {
Token::Delemiter(char, dbginf) => {
Token::Delemiter(char, _) => {
if *char == '(' {
//println!("{}", dbginf.make_msg(crate::msg::ERR63));
diagnostics.set_err(&token, crate::msg::ERR63, "");
return Err(());
}
}
_ => {
collapse_operation(&mut token, declrs, scope, &mut value_stack, diagnostics);
collapse_operation(&mut token, declrs, scope, &mut value_stack, diagnostics)?;
output.push_back(token)
}
}
@ -631,7 +706,7 @@ fn parse_term<'a>(
if value_stack.len() > 1 {
diagnostics.set_err(&output[0], crate::msg::ERR50, "");
return;
return Err(());
}
scope.expr_yield = value_stack.len() == 1;
@ -652,6 +727,8 @@ fn parse_term<'a>(
}
term.append(&mut output);
Ok(())
}
fn is_func(declrs: &[Declr], text: &str) -> bool {
@ -668,24 +745,25 @@ fn parse_block<'a>(
declrs: &Vec<Declr<'a>>,
scope: &mut Scope,
diagnostics: &mut data::Diagnostics,
) {
) -> Result<(), ()> {
scope.cond_count += 1;
scope.alloc_scope();
for expr in block.iter_mut() {
match expr {
Expr::Block(block) => parse_block(block, declrs, scope, diagnostics),
Expr::Term(term) => parse_term(term, declrs, scope, diagnostics),
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;
Ok(())
}
fn parse_exprs<'a>(
funcs: &mut Vec<Func<'a>>,
declrs: &Vec<Declr<'a>>,
diagnostics: &mut data::Diagnostics,
) {
) -> Result<(),()> {
let mut scope = Scope::new();
for (x, func) in funcs.iter_mut().enumerate() {
@ -696,31 +774,35 @@ fn parse_exprs<'a>(
scope.yields = false;
scope.cond_count = 0;
parse_block(block, declrs, &mut scope, diagnostics);
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]));
diagnostics.set_err(declrs[x].info.as_ref().unwrap(), crate::msg::ERR56, format!("for function: {}", declrs[x]));
return Err(());
}
}
_ => {
crate::message(crate::token::MessageType::Critical, "Fatal-Compilier-Error: function must have a block");
panic!();
},
}
}
_ => panic!("Fatal-Compilier-Error: function must have a block"),
}
}
Ok(())
}
/// 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<crate::Token<'a>>, source: &'a str) -> Diagnostics<'a> {
let mut dias = data::Diagnostics::new(source);
pub fn parse<'a>(tokens: &mut VecDeque<crate::Token<'a>>, diagnostics: &mut data::Diagnostics, settings: &Settings) {
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);
if let Ok((mut funcs, declrs)) = discover_functions(tokens, diagnostics) {
if let Ok(()) = discover_exprs(&mut funcs, &declrs, diagnostics) {
if let Ok(()) = parse_exprs(&mut funcs, &declrs, diagnostics) {
if settings.gen_erpn() {
crate::inter::convert_to_erpn(&mut funcs, &declrs);
}
dias
}
}
}
}

View File

@ -1,7 +1,7 @@
use crate::token::DebugMsg;
use crate::token::MessageType::Error;
use crate::token::MessageType::Info;
use crate::token::MessageType::Warning;
//use crate::token::MessageType::Warning;
pub const ERR10: &DebugMsg = &DebugMsg {
typ: Error,
@ -73,6 +73,12 @@ pub const ERR23: &DebugMsg = &DebugMsg {
code: 23,
msg: "token must be declaration",
};
pub const ERR24: &DebugMsg = &DebugMsg {
typ: Error,
code: 24,
msg: "function already has return type",
};
pub const ERR40: &DebugMsg = &DebugMsg {
typ: Error,
@ -183,11 +189,7 @@ pub const ERR71: &DebugMsg = &DebugMsg {
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,

View File

@ -1,6 +1,8 @@
use colored::{ColoredString, Colorize};
use std::collections::VecDeque;
use crate::parser::data::Diagnostics;
#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)]
pub enum Operator {
// bitwise boolean operations
@ -117,31 +119,26 @@ impl Operator {
operands: &[Prim],
types: &[Prim],
r#yield: Prim,
dbginf: &DebugInfo,
info: &DebugInfo,
diagnostics: &mut crate::parser::data::Diagnostics,
) -> Option<Prim> {
) -> Result<Option<Prim>, ()> {
if operands.len() < types.len() {
/*
println!(
"{}",
dbginf.make_msg_w_ext(
crate::msg::ERR74,
format!(
diagnostics.set_err(info, crate::msg::ERR74, format!(
"required {} got {}",
types.len() - operands.len(),
operands.len()
)
)
);*/
panic!()
);
return Err(());
}
for (x, typ) in types.iter().enumerate() {
if typ != &operands[x] {
return None;
return Ok(None);
}
}
Some(r#yield)
Ok(Some(r#yield))
}
fn check_types(
@ -149,60 +146,54 @@ impl Operator {
types: &[(&[Prim], Prim)],
dbginf: &DebugInfo,
diagnostics: &mut crate::parser::data::Diagnostics,
) -> Option<Prim> {
) -> Result<Option<Prim>,()> {
for combination in types.iter() {
if let Some(result) =
Self::present_types(operands, combination.0, combination.1, dbginf, diagnostics)
Self::present_types(operands, combination.0, combination.1, dbginf, diagnostics)?
{
return Some(result);
return Ok(Some(result));
}
}
None
Ok(None)
}
pub fn operate(
&self,
operands: &mut Vec<Prim>,
dbginf: &DebugInfo,
info: &DebugInfo,
diagnostics: &mut crate::parser::data::Diagnostics,
) {
) -> Result<(),()> {
match self {
Operator::Add | Operator::Sub | Operator::Mul | Operator::Div => {
let types_valid =
Self::check_types(operands, ARITHMETIC_TYPES, dbginf, diagnostics);
Self::check_types(operands, ARITHMETIC_TYPES, info, diagnostics)?;
if let Some(result) = types_valid {
operands.pop();
operands.pop();
operands.push(result);
return Ok(());
} else {
/*
println!(
"{}",
dbginf.make_msg_w_ext(crate::msg::ERR73, "expected two numbers")
);*/
panic!()
diagnostics.set_err(info, crate::msg::ERR73, "expected two numbers");
return Err(());
}
}
Operator::And | Operator::Or | Operator::Xor => {
let types_valid = Self::check_types(
operands,
&[(&[Prim::Bool, Prim::Bool], Prim::Bool)],
dbginf,
info,
diagnostics,
);
)?;
if let Some(result) = types_valid {
operands.pop();
operands.pop();
operands.push(result);
return Ok(())
} else {
/*
println!(
"{}",
dbginf.make_msg_w_ext(crate::msg::ERR73, "expected two booleans")
);*/
panic!()
diagnostics.set_err(info, crate::msg::ERR73, "expected two booleans");
return Err(());
}
}
Operator::Eq
@ -229,21 +220,18 @@ impl Operator {
Prim::Bool,
),
],
dbginf,
info,
diagnostics,
);
)?;
if let Some(result) = types_valid {
operands.pop();
operands.pop();
operands.push(result);
return Ok(());
} else {
/*
println!(
"{}",
dbginf.make_msg_w_ext(crate::msg::ERR73, "expected two numbers")
);*/
panic!()
diagnostics.set_err(info, crate::msg::ERR73, "expected either two booleans or two numbers");
return Err(());
}
}
_ => {
@ -255,7 +243,7 @@ impl Operator {
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum Keyword {
If,
Unless,
While,
/// while(true) loop
Loop,
@ -269,7 +257,7 @@ pub enum Keyword {
impl Keyword {
pub fn parse<'a>(text: &'a str) -> Keyword {
return match text {
"unless" => Keyword::If,
"unless" => Keyword::Unless,
"while" => Keyword::While,
"loop" => Keyword::Loop,
"break" => Keyword::Break,
@ -314,14 +302,14 @@ pub enum Prim {
}
impl Prim {
fn from<'a>(text: &'a str, dbginf: &DebugInfo) -> Prim {
fn from<'a>(text: &'a str, info: &DebugInfo, diagnostics: &mut Diagnostics) -> Result<Prim, ()> {
return match text {
"int" => Prim::Int,
"rat" => Prim::Rat,
"bool" => Prim::Bool,
"int" => Ok(Prim::Int),
"rat" => Ok(Prim::Rat),
"bool" => Ok(Prim::Bool),
_ => {
//println!("{}", dbginf.make_msg(&crate::msg::ERR70));
panic!()
diagnostics.set_err(info, crate::msg::ERR70, format!("token is not a type: {}", text));
return Err(())
}
};
}
@ -358,6 +346,18 @@ impl Prim {
}
}
impl std::fmt::Display for Prim {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Prim::Int => f.write_str("Int")?,
Prim::Rat => f.write_str("Rat")?,
Prim::Bool => f.write_str("Bool")?,
Prim::Num(_) => f.write_fmt(format_args!("{:?}", self))?
}
Ok(())
}
}
pub struct DebugMsg {
pub code: i32,
pub typ: MessageType,
@ -384,7 +384,7 @@ impl<'a> std::fmt::Display for DebugNotice<'a> {
self.msg.msg.bold().bright_white(),
self.info.line,
self.ext
));
))?;
// write additional information
f.write_fmt(format_args!(
" somewhere in here:\n --> `{}`\n",
@ -446,7 +446,7 @@ impl MessageType {
}
impl std::fmt::Display for DebugInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Ok(())
}
}
@ -491,7 +491,7 @@ impl<'a> std::fmt::Display for Token<'a> {
Token::Func(name, _) => f.write_fmt(format_args!("Call {}", name)),
Token::Var(v, _) => f.write_fmt(format_args!("Load Var {}", v)),
Token::Arg(a, _) => f.write_fmt(format_args!("Load Arg {}", a)),
Token::Assign(a, typ, _) => f.write_fmt(format_args!("Store {:?} {}", typ, a)),
Token::Assign(a, typ, _) => f.write_fmt(format_args!("Store {} {}", typ.unwrap(), a)),
Token::Decl(d, typ, _) => f.write_fmt(format_args!("__Decl {:?} as {}", typ, d)),
Token::Bool(b, _) => f.write_fmt(format_args!("Load Bool {}", b)),
Token::Keyword(k, _) => f.write_fmt(format_args!("{:?}", k)),
@ -528,7 +528,7 @@ lazy_static::lazy_static! {
}
/// creates a vector of tokens from the specified str.
pub fn tokenize(source: &str) -> VecDeque<Token> {
pub fn tokenize<'a>(source: &'a str, diagnostics: &mut Diagnostics) -> Result<VecDeque<Token<'a>>, ()> {
let mut tokens = VecDeque::new();
let mut line_count = 0;
@ -560,11 +560,11 @@ pub fn tokenize(source: &str) -> VecDeque<Token> {
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), debug_info),
3 => Token::Type(Prim::from(mat.as_str(), &debug_info, diagnostics)?, 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))
Some(Prim::from(mat.as_str(), &debug_info, diagnostics)?)
} else {
None
};
@ -572,7 +572,7 @@ pub fn tokenize(source: &str) -> VecDeque<Token> {
}
7 => {
let var_type =
Prim::from(enumerator.next().unwrap().1.unwrap().as_str(), &debug_info);
Prim::from(enumerator.next().unwrap().1.unwrap().as_str(), &debug_info, diagnostics)?;
Token::Decl(mat.as_str(), var_type, debug_info)
}
9 => Token::Word(mat.as_str(), debug_info),
@ -587,8 +587,8 @@ pub fn tokenize(source: &str) -> VecDeque<Token> {
14 => Token::Terminator(debug_info),
_ => {
//println!("{}", debug_info.make_msg(crate::msg::ERR71));
panic!()
diagnostics.set_err(&debug_info, crate::msg::ERR71, format!("token: {}", mat.as_str()));
return Err(());
}
});
break;
@ -596,7 +596,7 @@ pub fn tokenize(source: &str) -> VecDeque<Token> {
}
}
return tokens;
return Ok(tokens);
}
fn parse_bool(text: &str) -> bool {
@ -604,6 +604,9 @@ fn parse_bool(text: &str) -> bool {
"true" | "ye" => true,
"false" | "no" => false,
"maybe" => rand::random(),
_ => panic!("Not a recognized boolean {text}"),
_ => {
crate::message(MessageType::Critical, format!("token: {}", text));
panic!();
},
};
}

View File

@ -4,31 +4,31 @@ foo:
Load Int 5
Load Int 6
Add
Store Some(Int) x
Store Int x
Load Arg x
Load Int 6
Lt
If
Unless
Load Bool true
Yield
Please
Load Arg x
Load Int 6
Lt
If
Unless
Load Bool true
Yield
Load Bool false
Load Bool true
Yield
main:
Load Int 4
Store None a
Store Int a
Load Rat 5.5
Store None b
Store Rat b
Load Bool true
Store None c
Store Bool c
Load Int 3
Load Rat 3.4
Call foo
Store None r
Store Bool r
Load Int 0