improved error message composition
This commit is contained in:
parent
d2e57ae72c
commit
f262a5d92b
|
@ -10,3 +10,4 @@ regex = "*"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
colored = "*"
|
colored = "*"
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,9 @@ It contains features such as:
|
||||||
// code block
|
// code block
|
||||||
}</code></pre></td></tr><tr><td>cont</td><td>Short form for “continue”. Jumps to the next iteration of a loop</td><td> </td></tr><tr><td>break</td><td>Exits a loop immediately</td><td> </td></tr><tr><td>yield</td><td>Returns from a function with an argument as return value</td><td><pre><code class="language-plaintext">foo() = int {
|
}</code></pre></td></tr><tr><td>cont</td><td>Short form for “continue”. Jumps to the next iteration of a loop</td><td> </td></tr><tr><td>break</td><td>Exits a loop immediately</td><td> </td></tr><tr><td>yield</td><td>Returns from a function with an argument as return value</td><td><pre><code class="language-plaintext">foo() = int {
|
||||||
yield 4
|
yield 4
|
||||||
}</code></pre></td></tr><tr><td>ret</td><td>Short form for “return”. This keyword takes no argument and returns from a function. NOTE: if ret is used in a function with a return type, an error occurs.</td><td> </td></tr></tbody></table>
|
}</code></pre></td></tr><tr><td>ret</td><td>Short form for “return”. This keyword takes no argument and returns from a function. NOTE: if ret is used in a function with a return type, an error occurs.</td><td> </td></tr><tr><td>please</td><td>Decides on runtime wether a block should be executed or not.</td><td><pre><code class="language-plaintext">please {
|
||||||
|
// code
|
||||||
|
}</code></pre></td></tr></tbody></table>
|
||||||
|
|
||||||
### Example code
|
### Example code
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
use crate::data::*;
|
||||||
|
|
||||||
|
fn write_expr(file: &mut std::fs::File, indent: &mut String, expr: &Expr) {
|
||||||
|
match expr {
|
||||||
|
Expr::Block(block) => write_block(file, indent, block),
|
||||||
|
Expr::Term(term) => write_term(file, indent, term)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_term(file: &mut std::fs::File, indent: &mut String, term: &std::collections::VecDeque<crate::token::Token>) {
|
||||||
|
for token in term.iter() {
|
||||||
|
write!(file, "{}{}\n", indent, token).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_block(file: &mut std::fs::File, indent: &mut String, block: &std::collections::VecDeque<Expr>) {
|
||||||
|
indent.push('\t');
|
||||||
|
|
||||||
|
block.iter().for_each(|expr| write_expr(file, indent, expr));
|
||||||
|
|
||||||
|
indent.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn convert_to_erpn<'a>(funcs: &mut Vec<Func<'a>>, declrs: &Vec<Declr<'a>>) {
|
||||||
|
|
||||||
|
let mut file = std::fs::OpenOptions::new().write(true).create(true).truncate(true).open("test.erpn").unwrap();
|
||||||
|
|
||||||
|
let mut indent = String::new();
|
||||||
|
|
||||||
|
for (x, func) in funcs.iter().enumerate() {
|
||||||
|
// write function name
|
||||||
|
write!(&mut file, "{}:\n", declrs[x].name.unwrap()).unwrap();
|
||||||
|
|
||||||
|
// write down function body
|
||||||
|
write_expr(&mut file, &mut indent, func.expr.as_ref().unwrap());
|
||||||
|
}
|
||||||
|
}
|
18
src/main.rs
18
src/main.rs
|
@ -5,10 +5,11 @@ mod token;
|
||||||
mod parser;
|
mod parser;
|
||||||
// translate a tree of functions and expressions to pseudo assembly
|
// translate a tree of functions and expressions to pseudo assembly
|
||||||
// designed for a virtual stack machiene
|
// designed for a virtual stack machiene
|
||||||
|
mod inter;
|
||||||
|
|
||||||
use token::*;
|
use token::*;
|
||||||
use parser::*;
|
use parser::*;
|
||||||
use colored::{Colorize};
|
use colored::Colorize;
|
||||||
|
|
||||||
pub fn message(typ: MessageType, msg: String) {
|
pub fn message(typ: MessageType, msg: String) {
|
||||||
println!("{}: {}", typ.to_colored(), msg.bold().bright_white());
|
println!("{}: {}", typ.to_colored(), msg.bold().bright_white());
|
||||||
|
@ -19,7 +20,7 @@ fn main() {
|
||||||
let source =
|
let source =
|
||||||
r"
|
r"
|
||||||
# this is pi
|
# this is pi
|
||||||
pi = rat 3.1415926535
|
pi = rat 5.1415926535
|
||||||
|
|
||||||
foo(x:int, y:rat) = bool {
|
foo(x:int, y:rat) = bool {
|
||||||
x:int = 5 + 6
|
x:int = 5 + 6
|
||||||
|
@ -27,16 +28,25 @@ foo(x :int, y: rat) = bool {
|
||||||
unless (x < 6) {
|
unless (x < 6) {
|
||||||
yield true
|
yield true
|
||||||
|
|
||||||
|
please {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
unless(x < 6) {
|
unless(x < 6) {
|
||||||
yield true
|
yield true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- comment
|
||||||
yield false
|
yield false
|
||||||
}
|
}
|
||||||
|
|
||||||
main {
|
main() = int {
|
||||||
|
a = 4
|
||||||
|
b = 5.5
|
||||||
|
c = true
|
||||||
|
r = foo(3, 3.4)
|
||||||
|
0
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
use core::panic;
|
use core::panic;
|
||||||
use std::collections::{VecDeque};
|
use std::collections::{VecDeque};
|
||||||
use crate::token::{Token};
|
use crate::token::{Token, DebugErr};
|
||||||
use crate::Prim;
|
use crate::Prim;
|
||||||
|
|
||||||
|
pub struct Diagnostics<'a> {
|
||||||
|
/// terminating factor on error
|
||||||
|
err: Option<DebugErr<'a>>,
|
||||||
|
/// additional warning and informations
|
||||||
|
/// all non critical
|
||||||
|
hints: Vec<DebugErr<'a>>
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Func<'a> {
|
pub struct Func<'a> {
|
||||||
/// raw tokens
|
/// raw tokens
|
||||||
|
@ -155,4 +163,15 @@ impl<'a> Scope<'a> {
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new<'b>() -> Scope<'b> {
|
||||||
|
Scope {
|
||||||
|
args: None,
|
||||||
|
vars: vec![],
|
||||||
|
func_return_typ: None,
|
||||||
|
expr_yield: false,
|
||||||
|
yields: false,
|
||||||
|
cond_count: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -3,6 +3,7 @@ use std::{collections::{VecDeque}, vec};
|
||||||
use crate::token::{Token, Operator, Assoc, Prim, MessageType, Keyword};
|
use crate::token::{Token, Operator, Assoc, Prim, MessageType, Keyword};
|
||||||
|
|
||||||
pub mod data;
|
pub mod data;
|
||||||
|
pub mod msg;
|
||||||
|
|
||||||
use data::*;
|
use data::*;
|
||||||
|
|
||||||
|
@ -24,11 +25,12 @@ fn discover_functions<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &str)
|
||||||
macro_rules! finish_func {
|
macro_rules! finish_func {
|
||||||
($dbginf:expr) => {
|
($dbginf:expr) => {
|
||||||
if declrs.contains(&declr) {
|
if declrs.contains(&declr) {
|
||||||
panic!("Function defined multiple times: {declr}")
|
println!("{}", $dbginf.make_msg_w_ext(crate::msg::ERR10, format!("Multiple definitions: {declr}")));
|
||||||
|
panic!()
|
||||||
}
|
}
|
||||||
|
|
||||||
if declr.results && declr.result_typ.is_none() {
|
if declr.results && declr.result_typ.is_none() {
|
||||||
$dbginf.print(MessageType::Error, format!("Function is missing return type: {}", declr).as_str(), source);
|
println!("{}", $dbginf.make_msg_w_ext(crate::msg::ERR11, format!("for function {declr}")));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,14 +50,16 @@ fn discover_functions<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &str)
|
||||||
Token::Delemiter(char, dbginf) => match char {
|
Token::Delemiter(char, dbginf) => match char {
|
||||||
'{' => {
|
'{' => {
|
||||||
brace_cnt += 1;
|
brace_cnt += 1;
|
||||||
|
|
||||||
|
// 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() {
|
||||||
dbginf.print(MessageType::Error, "Anonymous function not permitted", source);
|
println!("{}", dbginf.make_msg(crate::msg::ERR12));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
|
|
||||||
if paren_cnt > 0 {
|
if paren_cnt > 0 {
|
||||||
dbginf.print(MessageType::Error, "Unclosed parameter list", source);
|
println!("{}", dbginf.make_msg(crate::msg::ERR13));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +70,14 @@ fn discover_functions<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &str)
|
||||||
},
|
},
|
||||||
'}' => {
|
'}' => {
|
||||||
brace_cnt -= 1;
|
brace_cnt -= 1;
|
||||||
|
|
||||||
|
// we closed one to much
|
||||||
|
if brace_cnt < 0 {
|
||||||
|
println!("{}", dbginf.make_msg(crate::msg::ERR14));
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
|
||||||
|
// end of function body
|
||||||
if brace_cnt == 0 {
|
if brace_cnt == 0 {
|
||||||
finish_func!(dbginf);
|
finish_func!(dbginf);
|
||||||
continue;
|
continue;
|
||||||
|
@ -74,17 +86,12 @@ fn discover_functions<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &str)
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
Token::Type(typ, dbginf) => {
|
Token::Type(typ, dbginf) => if declr.result_typ.is_none() {
|
||||||
if declr.results {
|
if declr.results {
|
||||||
if declr.result_typ.is_some() {
|
|
||||||
dbginf.print(MessageType::Error, "Function must return either nothing or a single type", source);
|
|
||||||
panic!();
|
|
||||||
}
|
|
||||||
|
|
||||||
declr.result_typ = Some(*typ);
|
declr.result_typ = Some(*typ);
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
dbginf.print(MessageType::Error, "Missing equal sign", source);
|
println!("{}", dbginf.make_msg(crate::msg::ERR16));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -104,11 +111,11 @@ fn discover_functions<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &str)
|
||||||
Token::Operator(op, dbginf) => match op {
|
Token::Operator(op, dbginf) => match op {
|
||||||
Operator::Assign => {
|
Operator::Assign => {
|
||||||
if declr.results {
|
if declr.results {
|
||||||
dbginf.print(MessageType::Error, "double function assignment", source);
|
println!("{}", dbginf.make_msg(crate::msg::ERR17));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
if declr.name.is_none() {
|
if declr.name.is_none() {
|
||||||
dbginf.print(MessageType::Error, "Anonymous function", source);
|
println!("{}", dbginf.make_msg(crate::msg::ERR12));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,14 +130,13 @@ fn discover_functions<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &str)
|
||||||
|
|
||||||
if declr.name.is_some() {
|
if declr.name.is_some() {
|
||||||
if declr.args.is_none() {
|
if declr.args.is_none() {
|
||||||
dbginf.print(MessageType::Error, "multiple function names", source);
|
println!("{}", dbginf.make_msg(crate::msg::ERR18));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
} else if brace_cnt > 0 {
|
} else if brace_cnt > 0 {
|
||||||
dbginf.print(MessageType::Error, "brace count missmatch", source);
|
println!("{}", dbginf.make_msg(crate::msg::ERR13));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
declr.name = Some(text);
|
declr.name = Some(text);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -138,11 +144,11 @@ fn discover_functions<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &str)
|
||||||
|
|
||||||
Token::Assign(name, _, dbginf) => {
|
Token::Assign(name, _, dbginf) => {
|
||||||
if declr.results {
|
if declr.results {
|
||||||
dbginf.print(MessageType::Error, "double function assignment", source);
|
println!("{}", dbginf.make_msg(crate::msg::ERR17));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
if declr.name.is_some() {
|
if declr.name.is_some() {
|
||||||
dbginf.print(MessageType::Error, "multiple function names", source);
|
println!("{}", dbginf.make_msg(crate::msg::ERR18));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +166,7 @@ fn discover_functions<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &str)
|
||||||
if paren_cnt == 1 {
|
if paren_cnt == 1 {
|
||||||
|
|
||||||
if declr.args.is_some() {
|
if declr.args.is_some() {
|
||||||
dbginf.print(MessageType::Error, "double parameter list", source);
|
println!("{}", dbginf.make_msg(crate::msg::ERR19));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,18 +193,18 @@ fn discover_functions<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &str)
|
||||||
else if let Some(args) = &mut declr.args {
|
else if let Some(args) = &mut declr.args {
|
||||||
|
|
||||||
if paren_cnt == 0 {
|
if paren_cnt == 0 {
|
||||||
top.print(MessageType::Error, "token is no parameter", source);
|
println!("{}", top.create_msg(crate::msg::ERR20));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
|
|
||||||
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) => {
|
||||||
dbginf.print(MessageType::Error, "type declaration missing", source);
|
println!("{}", dbginf.make_msg(crate::msg::ERR21));
|
||||||
panic!()
|
panic!()
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
top.print(MessageType::Error, "argument must be declaration", source);
|
println!("{}", top.create_msg(crate::msg::ERR23));
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,7 +215,7 @@ 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
|
||||||
_ => {
|
_ => {
|
||||||
top.print(MessageType::Error, "unresolvable token", source);
|
println!("{}", top.create_msg(crate::msg::ERR22));
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,7 +223,7 @@ fn discover_functions<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &str)
|
||||||
|
|
||||||
if let Some(raw) = func.raw {
|
if let Some(raw) = func.raw {
|
||||||
if let Some(front) = raw.front() {
|
if let Some(front) = raw.front() {
|
||||||
front.print(MessageType::Error, "Open function body", source);
|
println!("{}", front.create_msg(crate::msg::ERR15));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,7 +246,7 @@ fn discover_exprs<'a>(functions: &mut Vec<Func<'a>>, _: &Vec<Declr<'a>>, source:
|
||||||
match &top {
|
match &top {
|
||||||
Token::LineBreak(dbginf) | Token::Terminator(dbginf) => if !expr.is_empty() {
|
Token::LineBreak(dbginf) | Token::Terminator(dbginf) => if !expr.is_empty() {
|
||||||
blocks.last_mut().unwrap_or_else(|| {
|
blocks.last_mut().unwrap_or_else(|| {
|
||||||
dbginf.print(MessageType::Error, "curly brace missmatch", source);
|
println!("{}", dbginf.make_msg(crate::msg::ERR41));
|
||||||
panic!()
|
panic!()
|
||||||
}).push_back(Expr::Term(expr));
|
}).push_back(Expr::Term(expr));
|
||||||
expr = VecDeque::new();
|
expr = VecDeque::new();
|
||||||
|
@ -249,7 +255,7 @@ fn discover_exprs<'a>(functions: &mut Vec<Func<'a>>, _: &Vec<Declr<'a>>, source:
|
||||||
Token::Delemiter(char, dbginf) => match char {
|
Token::Delemiter(char, dbginf) => match char {
|
||||||
'{' => {
|
'{' => {
|
||||||
blocks.last_mut().unwrap_or_else(|| {
|
blocks.last_mut().unwrap_or_else(|| {
|
||||||
dbginf.print(MessageType::Error, "curly brace missmatch", source);
|
println!("{}", dbginf.make_msg(crate::msg::ERR41));
|
||||||
panic!()
|
panic!()
|
||||||
}).push_back(Expr::Term(expr));
|
}).push_back(Expr::Term(expr));
|
||||||
expr = VecDeque::new();
|
expr = VecDeque::new();
|
||||||
|
@ -260,11 +266,12 @@ fn discover_exprs<'a>(functions: &mut Vec<Func<'a>>, _: &Vec<Declr<'a>>, source:
|
||||||
// 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.last_mut().unwrap_or_else(|| {
|
||||||
dbginf.print(MessageType::Error, "curly brace missmatch", source);
|
println!("{}", dbginf.make_msg(crate::msg::ERR41));
|
||||||
panic!()
|
panic!()
|
||||||
}).push_back(Expr::Block(block));
|
}).push_back(Expr::Block(block));
|
||||||
} else {
|
} else {
|
||||||
panic!("Curly brace missmatch")
|
println!("{}", dbginf.make_msg(crate::msg::ERR40));
|
||||||
|
panic!()
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
|
@ -278,7 +285,7 @@ fn discover_exprs<'a>(functions: &mut Vec<Func<'a>>, _: &Vec<Declr<'a>>, source:
|
||||||
|
|
||||||
if !expr.is_empty() {
|
if !expr.is_empty() {
|
||||||
blocks.last_mut().unwrap_or_else(|| {
|
blocks.last_mut().unwrap_or_else(|| {
|
||||||
expr.back().unwrap().print(MessageType::Error, "curly brace missmatch", source);
|
println!("{}", expr.back().unwrap().create_msg(crate::msg::ERR40));
|
||||||
panic!()
|
panic!()
|
||||||
}).push_back(Expr::Term(expr));
|
}).push_back(Expr::Term(expr));
|
||||||
}
|
}
|
||||||
|
@ -292,26 +299,26 @@ 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>, dbginf: &crate::token::DebugInfo, source: &str) {
|
||||||
|
|
||||||
if let Some(value) = operands.pop() {
|
if let Some(value) = operands.pop() {
|
||||||
if !operands.is_empty() {
|
if !operands.is_empty() {
|
||||||
dbginf.print(MessageType::Error, format!("Expr does't resolve to a single value but multiple").as_str(), source);
|
println!("{}", dbginf.make_msg(crate::msg::ERR50));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(typ) = typ {
|
if let Some(typ) = typ {
|
||||||
if !typ.is_equal(value) {
|
if !typ.is_equal(value) {
|
||||||
dbginf.print(MessageType::Error, format!("Variable has type {:?} but {:?} was given", typ, value).as_str(), source);
|
println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR51, format!("needed {:?} got {:?}", typ, value) ));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// assign a type to untyped variable
|
// assign a type to untyped variable
|
||||||
dbginf.print(MessageType::Info, format!("Variable has no fixed type, guessing type: {:?}", value).as_str(), source);
|
println!("{}", dbginf.make_msg_w_ext(crate::msg::INF51, format!("gessed type: {:?}", value) ));
|
||||||
|
|
||||||
*typ = Some(value);
|
*typ = Some(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
dbginf.print(MessageType::Error, "No result to bind variable to", source);
|
println!("{}", dbginf.make_msg(crate::msg::ERR52));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -320,7 +327,7 @@ fn process_keyword(keyword: Keyword, _: &Vec<Declr>, scope: &mut Scope, operands
|
||||||
match keyword {
|
match keyword {
|
||||||
Keyword::If | Keyword::While => {
|
Keyword::If | Keyword::While => {
|
||||||
if operands.len() != 1 {
|
if operands.len() != 1 {
|
||||||
dbginf.print(MessageType::Error, format!("Expected single boolean got {} values", operands.len()).as_str(), source);
|
println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR53, format!("got {:?} values", operands.len()) ));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,7 +335,7 @@ fn process_keyword(keyword: Keyword, _: &Vec<Declr>, scope: &mut Scope, operands
|
||||||
match operand {
|
match operand {
|
||||||
Prim::Bool => (),
|
Prim::Bool => (),
|
||||||
_ => {
|
_ => {
|
||||||
dbginf.print(MessageType::Error, format!("Expected boolean, got {:?}", operand).as_str(), source);
|
println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR53, format!("got {:?}", operand) ));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -336,30 +343,30 @@ fn process_keyword(keyword: Keyword, _: &Vec<Declr>, scope: &mut Scope, operands
|
||||||
},
|
},
|
||||||
Keyword::Return => {
|
Keyword::Return => {
|
||||||
if scope.func_return_typ.is_some() {
|
if scope.func_return_typ.is_some() {
|
||||||
dbginf.print(MessageType::Error, "cannot return function, did u mean to use `yield`?", source);
|
println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR54, "perhaps use `yield`" ));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Keyword::Yield => {
|
Keyword::Yield => {
|
||||||
if operands.len() != 1 {
|
if operands.len() != 1 {
|
||||||
dbginf.print(MessageType::Error, format!("Expected single value but got {} values", operands.len()).as_str(), source);
|
println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR55, format!("got {:?} instead of 1", operands.len()) ));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
dbginf.print(MessageType::Error, format!("Expected {:?} but got {:?}", typ, operand).as_str(), source);
|
println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR59, format!("expected {:?} got {:?}", typ, operand) ));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
println!("{}", scope.cond_count);
|
println!("{}", scope.cond_count);
|
||||||
scope.yields = scope.cond_count == 1;
|
scope.yields = scope.cond_count == 1;
|
||||||
} else {
|
} else {
|
||||||
dbginf.print(MessageType::Error, format!("Function does not return anything").as_str(), source);
|
println!("{}", dbginf.make_msg(crate::msg::ERR57));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dbginf.print(MessageType::Error, format!("Yield must return something").as_str(), source);
|
println!("{}", dbginf.make_msg(crate::msg::ERR58));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -367,12 +374,12 @@ fn process_keyword(keyword: Keyword, _: &Vec<Declr>, scope: &mut Scope, operands
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collapse_operation(operation: &Token, declrs: &Vec<Declr>, scope: &mut Scope, operands: &mut Vec<Prim>, source: &str) {
|
fn collapse_operation(operation: &mut Token, declrs: &Vec<Declr>, scope: &mut Scope, operands: &mut Vec<Prim>, source: &str) {
|
||||||
match operation {
|
match operation {
|
||||||
Token::Operator(op, dbginf) => op.operate(operands, &dbginf, source),
|
Token::Operator(op, dbginf) => op.operate(operands, &dbginf, source),
|
||||||
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, source);
|
||||||
scope.decl_var((*name).to_owned(), typ.to_owned());
|
scope.decl_var((*name).to_owned(), typ);
|
||||||
},
|
},
|
||||||
Token::Func(name, dbginf) => call_func(name, declrs, scope, operands, &dbginf, source),
|
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::Keyword(keyword, dbginf) => process_keyword(*keyword, declrs, scope, operands, &dbginf, source),
|
||||||
|
@ -387,7 +394,7 @@ fn call_func(name: &str, declrs: &Vec<Declr>, _: &mut Scope, operands: &mut Vec<
|
||||||
if let Some(args) = &declr.args {
|
if let Some(args) = &declr.args {
|
||||||
|
|
||||||
if args.len() > operands.len() {
|
if args.len() > operands.len() {
|
||||||
dbginf.print(MessageType::Error, format!("Expected {} parameters but got {}", args.len(), operands.len()).as_str(), source);
|
println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR60, format!("expected {:?} got {:?}", args.len(), operands.len()) ));
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,7 +402,7 @@ 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) {
|
||||||
dbginf.print(MessageType::Error, format!("Expected {:?} as parameter {x}, but got {:?}", arg, operand).as_str(), source);
|
println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR61, format!("expected {:?} got {:?}", arg, operand) ));
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,7 +441,7 @@ 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;
|
||||||
}
|
}
|
||||||
dbginf.print(MessageType::Error, "Unknown word", source);
|
println!("{}", dbginf.make_msg(crate::msg::ERR62));
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
Token::Bool(_, _) => {
|
Token::Bool(_, _) => {
|
||||||
|
@ -442,7 +449,7 @@ fn parse_term<'a>(term: &mut VecDeque<Token<'a>>, declrs: &Vec<Declr<'a>>, scope
|
||||||
value_stack.push(Prim::Bool)
|
value_stack.push(Prim::Bool)
|
||||||
},
|
},
|
||||||
Token::Number(_, hint, _) => {
|
Token::Number(_, hint, _) => {
|
||||||
output.push_back(token);
|
output.push_back(token.clone());
|
||||||
value_stack.push(Prim::UntypedNum(*hint))
|
value_stack.push(Prim::UntypedNum(*hint))
|
||||||
},
|
},
|
||||||
Token::Assign(_, _, _) => {
|
Token::Assign(_, _, _) => {
|
||||||
|
@ -450,18 +457,18 @@ fn parse_term<'a>(term: &mut VecDeque<Token<'a>>, declrs: &Vec<Declr<'a>>, scope
|
||||||
},
|
},
|
||||||
Token::Keyword(_, _) => op_stack.push(token),
|
Token::Keyword(_, _) => op_stack.push(token),
|
||||||
|
|
||||||
Token::Delemiter(char, _) => {
|
Token::Delemiter(char, dbginf) => {
|
||||||
match char {
|
match char {
|
||||||
'(' => op_stack.push(token),
|
'(' => op_stack.push(token),
|
||||||
')' => {
|
')' => {
|
||||||
while let Some(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 token = op_stack.pop().unwrap();
|
let mut token = op_stack.pop().unwrap();
|
||||||
collapse_operation(&token, declrs, scope, &mut value_stack, source);
|
collapse_operation(&mut token, declrs, scope, &mut value_stack, source);
|
||||||
output.push_back(token);
|
output.push_back(token);
|
||||||
},
|
},
|
||||||
_ => ()
|
_ => ()
|
||||||
|
@ -470,26 +477,30 @@ fn parse_term<'a>(term: &mut VecDeque<Token<'a>>, declrs: &Vec<Declr<'a>>, scope
|
||||||
continue 'outer;
|
continue 'outer;
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
collapse_operation(&token, declrs, scope, &mut value_stack, source);
|
collapse_operation(&mut token, declrs, scope, &mut value_stack, source);
|
||||||
output.push_back(token)
|
output.push_back(token)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic!("Mismatched right parenthesis")
|
println!("{}", dbginf.make_msg(crate::msg::ERR64));
|
||||||
|
panic!();
|
||||||
},
|
},
|
||||||
_ => panic!("Misplaced character: '{char}'")
|
_ => {
|
||||||
|
println!("{}", dbginf.make_msg(crate::msg::ERR65));
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Token::Operator(op, _) => {
|
Token::Operator(op, _) => {
|
||||||
let prec0 = op.prec();
|
let prec0 = op.prec();
|
||||||
while let Some(top) = op_stack.last(){
|
while let Some(mut top) = op_stack.last_mut(){
|
||||||
match &top {
|
match &top {
|
||||||
Token::Operator(op1, _) => {
|
Token::Operator(op1, _) => {
|
||||||
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(top, declrs, scope, &mut value_stack, source);
|
collapse_operation(&mut top, declrs, scope, &mut value_stack, source);
|
||||||
output.push_back(op_stack.pop().unwrap());
|
output.push_back(op_stack.pop().unwrap());
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -504,20 +515,20 @@ fn parse_term<'a>(term: &mut VecDeque<Token<'a>>, declrs: &Vec<Declr<'a>>, scope
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while let Some(token) = op_stack.pop() {
|
while let Some(mut token) = op_stack.pop() {
|
||||||
match &token {
|
match &token {
|
||||||
Token::Delemiter(char, _) => if *char == '(' {
|
Token::Delemiter(char, dbginf) => if *char == '(' {
|
||||||
panic!("Mismatched parenthesis")
|
println!("{}", dbginf.make_msg(crate::msg::ERR63));
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
collapse_operation(&token, declrs, scope, &mut value_stack, source);
|
collapse_operation(&mut token, declrs, scope, &mut value_stack, source);
|
||||||
output.push_back(token)
|
output.push_back(token)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if value_stack.len() > 1 {
|
if value_stack.len() > 1 {
|
||||||
output[0].print(MessageType::Error, "expression resolves to multiple results", source);
|
println!("{}", output[0].create_msg(crate::msg::ERR50));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,7 +536,7 @@ fn parse_term<'a>(term: &mut VecDeque<Token<'a>>, declrs: &Vec<Declr<'a>>, scope
|
||||||
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()) {
|
||||||
output[0].print(MessageType::Error, format!("expected {:?} but got {:?}", scope.func_return_typ.unwrap(), yielded).as_str(), source);
|
println!("{}", output[0].create_msg_w_ext(crate::msg::ERR59, format!("expected: {:?} got {:?}", scope.func_return_typ.unwrap(), yielded) ));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -556,14 +567,7 @@ fn parse_block<'a>(block: &mut Block<'a>, declrs: &Vec<Declr<'a>>, scope: &mut S
|
||||||
}
|
}
|
||||||
|
|
||||||
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>>, source: &'a str) {
|
||||||
let mut scope = Scope {
|
let mut scope = Scope::new();
|
||||||
args: None,
|
|
||||||
vars: vec![],
|
|
||||||
func_return_typ: None,
|
|
||||||
expr_yield: false,
|
|
||||||
yields: false,
|
|
||||||
cond_count: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
for (x, func) in funcs.iter_mut().enumerate() {
|
for (x, func) in funcs.iter_mut().enumerate() {
|
||||||
match func.expr.as_mut().expect("Function has no body") {
|
match func.expr.as_mut().expect("Function has no body") {
|
||||||
|
@ -576,7 +580,7 @@ fn parse_exprs<'a>(funcs: &mut Vec<Func<'a>>, declrs: &Vec<Declr<'a>>, source: &
|
||||||
parse_block(block, declrs, &mut scope, source);
|
parse_block(block, declrs, &mut scope, source);
|
||||||
|
|
||||||
if scope.func_return_typ.is_some() && !scope.yields && !scope.expr_yield {
|
if scope.func_return_typ.is_some() && !scope.yields && !scope.expr_yield {
|
||||||
crate::message(MessageType::Error, format!("Function {} missing return value at some point", declrs[x]));
|
//token.create_msg_w_ext(crate::msg::ERR56, format!("at function {}", declrs[x]));
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -591,12 +595,11 @@ fn parse_exprs<'a>(funcs: &mut Vec<Func<'a>>, declrs: &Vec<Declr<'a>>, source: &
|
||||||
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) -> Vec<Func<'a>> {
|
||||||
let (mut funcs, declrs) = discover_functions(tokens, source);
|
let (mut funcs, declrs) = discover_functions(tokens, source);
|
||||||
|
|
||||||
|
// make all of this shit return a mutable diagnostics struct.
|
||||||
discover_exprs(&mut funcs, &declrs, source);
|
discover_exprs(&mut funcs, &declrs, source);
|
||||||
parse_exprs(&mut funcs, &declrs, source);
|
parse_exprs(&mut funcs, &declrs, source);
|
||||||
|
|
||||||
for (x, f) in funcs.iter().enumerate() {
|
crate::inter::convert_to_erpn(&mut funcs, &declrs);
|
||||||
println!("{:#?}{:#?}", declrs[x], f);
|
|
||||||
}
|
|
||||||
|
|
||||||
funcs
|
funcs
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
|
||||||
|
use crate::token::DebugMsg;
|
||||||
|
use crate::token::MessageType::Error;
|
||||||
|
use crate::token::MessageType::Warning;
|
||||||
|
use crate::token::MessageType::Info;
|
||||||
|
|
||||||
|
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 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 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"};
|
||||||
|
|
197
src/token/mod.rs
197
src/token/mod.rs
|
@ -1,4 +1,4 @@
|
||||||
use std::{collections::{VecDeque}};
|
use std::collections::VecDeque;
|
||||||
use colored::{Colorize, ColoredString};
|
use colored::{Colorize, ColoredString};
|
||||||
|
|
||||||
#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)]
|
#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)]
|
||||||
|
@ -82,7 +82,7 @@ impl Operator {
|
||||||
|
|
||||||
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, source: &str) -> Option<Prim> {
|
||||||
if operands.len() < types.len() {
|
if operands.len() < types.len() {
|
||||||
dbginf.print(MessageType::Error, format!("Missing {} operands", types.len() - operands.len()).as_str(), source);
|
println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR74, format!("required {} got {}", types.len() - operands.len(), operands.len())));
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ impl Operator {
|
||||||
operands.pop();
|
operands.pop();
|
||||||
operands.push(result);
|
operands.push(result);
|
||||||
} else {
|
} else {
|
||||||
dbginf.print(MessageType::Error, format!("Missmatched types for {:?}, expected either two integer or rationals", self).as_str(), source);
|
println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR73, "expected two numbers"));
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -144,7 +144,7 @@ impl Operator {
|
||||||
operands.pop();
|
operands.pop();
|
||||||
operands.push(result);
|
operands.push(result);
|
||||||
} else {
|
} else {
|
||||||
dbginf.print(MessageType::Error, format!("Missmatched types for {:?}, expected two booleans", self).as_str(), source);
|
println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR73, "expected two booleans"));
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -169,11 +169,13 @@ impl Operator {
|
||||||
operands.pop();
|
operands.pop();
|
||||||
operands.push(result);
|
operands.push(result);
|
||||||
} else {
|
} else {
|
||||||
dbginf.print(MessageType::Error, format!("Missmatched types for {:?}, expected two numbers", self).as_str(), source);
|
println!("{}", dbginf.make_msg_w_ext(crate::msg::ERR73, "expected two numbers"));
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => panic!("Unknown operator: {:?}", self)
|
_ => {
|
||||||
|
panic!("Unknown operator");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,7 +189,8 @@ pub enum Keyword {
|
||||||
Break,
|
Break,
|
||||||
Continue,
|
Continue,
|
||||||
Return,
|
Return,
|
||||||
Yield
|
Yield,
|
||||||
|
Please,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Keyword {
|
impl Keyword {
|
||||||
|
@ -200,6 +203,7 @@ impl Keyword {
|
||||||
"cont" => Keyword::Continue,
|
"cont" => Keyword::Continue,
|
||||||
"ret" => Keyword::Return,
|
"ret" => Keyword::Return,
|
||||||
"yield" => Keyword::Yield,
|
"yield" => Keyword::Yield,
|
||||||
|
"please" => Keyword::Please,
|
||||||
_ => panic!("Text not a known keyword {text}")
|
_ => panic!("Text not a known keyword {text}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -239,7 +243,7 @@ impl Prim {
|
||||||
"bool" => Prim::Bool,
|
"bool" => Prim::Bool,
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
dbginf.print(MessageType::Error, "Unknown type declaration", source);
|
println!("{}", dbginf.make_msg(&crate::msg::ERR70));
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -269,14 +273,64 @@ impl Prim {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct DebugMsg {
|
||||||
|
pub code: i32,
|
||||||
|
pub typ: MessageType,
|
||||||
|
pub msg: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DebugErr<'a> {
|
||||||
|
info: DebugInfo<'a>,
|
||||||
|
/// generic error description
|
||||||
|
msg: &'static DebugMsg,
|
||||||
|
/// extra message which is case specific
|
||||||
|
ext: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> std::fmt::Display for DebugErr<'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",
|
||||||
|
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())
|
||||||
|
));
|
||||||
|
// write additional information
|
||||||
|
f.write_fmt(format_args!("{}", self.info))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
pub struct DebugInfo {
|
pub struct DebugInfo<'a> {
|
||||||
/// 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,
|
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,
|
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
|
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)]
|
||||||
|
@ -301,79 +355,97 @@ impl MessageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DebugInfo {
|
impl<'a> std::fmt::Display for DebugInfo<'a> {
|
||||||
/// print message in the form of:
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
/// ```text
|
f.write_fmt(format_args!(" somewhere in here:\n --> `{}`\n",
|
||||||
/// Error (message) in line 7: token `code`
|
self.source.lines().nth(self.line).unwrap().trim().bold().bright_white())).unwrap();
|
||||||
/// somewhere in here:
|
|
||||||
/// --> `code line`
|
|
||||||
/// ^^^^
|
|
||||||
/// ```
|
|
||||||
pub fn print<'a>(&self, typ: MessageType, msg: &str, source: &'a str) {
|
|
||||||
println!("{} ({}) in line {}: token `{}`", typ.to_colored(), msg.bold().bright_white(), self.line, &source[self.start..self.end].bold());
|
|
||||||
println!(" somewhere in here:\n --> `{}`", source.lines().nth(self.line).unwrap().trim().bold().bright_white());
|
|
||||||
|
|
||||||
for _ in 0..self.start + 6 {
|
(0..self.start + 6).into_iter().for_each(|_| f.write_str(" ").unwrap());
|
||||||
print!(" ");
|
(self.start..self.end).into_iter().for_each(|_| f.write_str("^").unwrap());
|
||||||
}
|
|
||||||
for _ in self.start..self.end {
|
Ok(())
|
||||||
print!("^");
|
|
||||||
}
|
|
||||||
println!("\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
/// A token represents a basic building block for source code.
|
/// A token represents a basic building block for source code.
|
||||||
/// 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),
|
Word(&'a str, DebugInfo<'a>),
|
||||||
/// Single symbol delemiter like ```(```,```}```
|
/// Single symbol delemiter like ```(```,```}```
|
||||||
Delemiter(char, DebugInfo),
|
Delemiter(char, DebugInfo<'a>),
|
||||||
Operator(Operator, DebugInfo),
|
Operator(Operator, DebugInfo<'a>),
|
||||||
Number(&'a str, NumberClassHint, DebugInfo),
|
Number(&'a str, NumberClassHint, DebugInfo<'a>),
|
||||||
LineBreak(DebugInfo),
|
LineBreak(DebugInfo<'a>),
|
||||||
Func(&'a str, DebugInfo),
|
Func(&'a str, DebugInfo<'a>),
|
||||||
/// Variable
|
/// Variable
|
||||||
Var(&'a str, DebugInfo),
|
Var(&'a str, DebugInfo<'a>),
|
||||||
/// Function argument
|
/// Function argument
|
||||||
Arg(&'a str, DebugInfo),
|
Arg(&'a str, DebugInfo<'a>),
|
||||||
/// Variable assignment in the form of ```name = ```
|
/// Variable assignment in the form of ```name = ```
|
||||||
Assign(&'a str, Option<Prim>, DebugInfo),
|
Assign(&'a str, Option<Prim>, DebugInfo<'a>),
|
||||||
/// Variable type declaration in the form of ```name:type```
|
/// Variable type declaration in the form of ```name:type```
|
||||||
Decl(&'a str, Prim, DebugInfo),
|
Decl(&'a str, Prim, DebugInfo<'a>),
|
||||||
Bool(bool, DebugInfo),
|
Bool(bool, DebugInfo<'a>),
|
||||||
/// Keywords like ```if```,```break```,```while```
|
/// Keywords like ```if```,```break```,```while```
|
||||||
Keyword(Keyword, DebugInfo),
|
Keyword(Keyword, DebugInfo<'a>),
|
||||||
Type(Prim, DebugInfo),
|
Type(Prim, DebugInfo<'a>),
|
||||||
/// Semicolon
|
/// Semicolon
|
||||||
Terminator(DebugInfo)
|
Terminator(DebugInfo<'a>)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> std::fmt::Display for Token<'a> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Token::Type(t, _) => f.write_fmt(format_args!("__Type {:?}", t)),
|
||||||
|
Token::Word(w, _) => f.write_fmt(format_args!("__Word {:?}", w)),
|
||||||
|
Token::Delemiter(d, _) => f.write_fmt(format_args!("__Delemiter {:?}", d)),
|
||||||
|
Token::Operator(o, _) => f.write_fmt(format_args!("{:?}", o)),
|
||||||
|
Token::Number(n, hint, _) => f.write_fmt(format_args!("Load {:?} {}", hint, n)),
|
||||||
|
Token::LineBreak(_) => f.write_str("__Line-break"),
|
||||||
|
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::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)),
|
||||||
|
Token::Terminator(_) => f.write_str("__Terminator"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Token<'a> {
|
impl<'a> Token<'a> {
|
||||||
/// redirect for ```DebugInfo.print()```
|
fn debug_info(&self) -> &DebugInfo {
|
||||||
pub fn print(&self, error: MessageType, arg: &str, source: &str) {
|
|
||||||
match self {
|
match self {
|
||||||
Token::Type(_, dbginf) => dbginf.print(error, arg, source),
|
Token::Type(_, d) => d,
|
||||||
Token::Word(_, dbginf) => dbginf.print(error, arg, source),
|
Token::Word(_, d) => d,
|
||||||
Token::Delemiter(_, dbginf) => dbginf.print(error, arg, source),
|
Token::Delemiter(_, d) => d,
|
||||||
Token::Operator(_, dbginf) => dbginf.print(error, arg, source),
|
Token::Operator(_, d) => d,
|
||||||
Token::Number(_, _, dbginf) => dbginf.print(error, arg, source),
|
Token::Number(_, _, d) => d,
|
||||||
Token::LineBreak(dbginf) => dbginf.print(error, arg, source),
|
Token::LineBreak(d) => d,
|
||||||
Token::Func(_, dbginf) => dbginf.print(error, arg, source),
|
Token::Func(_, d) => d,
|
||||||
Token::Var(_, dbginf) => dbginf.print(error, arg, source),
|
Token::Var(_, d) => d,
|
||||||
Token::Arg(_, dbginf) => dbginf.print(error, arg, source),
|
Token::Arg(_, d) => d,
|
||||||
Token::Assign(_, _, dbginf) => dbginf.print(error, arg, source),
|
Token::Assign(_, _, d) => d,
|
||||||
Token::Decl(_, _, dbginf) => dbginf.print(error, arg, source),
|
Token::Decl(_, _, d) => d,
|
||||||
Token::Bool(_, dbginf) => dbginf.print(error, arg, source),
|
Token::Bool(_, d) => d,
|
||||||
Token::Keyword(_, dbginf) => dbginf.print(error, arg, source),
|
Token::Keyword(_, d) => d,
|
||||||
Token::Terminator(dbginf) => dbginf.print(error, arg, source),
|
Token::Terminator(d) => d,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const TOKEN_REGEX_SRC: &'static str = r"(#.*)|(unless|while|loop|break|cont|ret|yield)|(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)|(;)";
|
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)|(;)";
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref TOKEN_REGEX: regex::Regex = regex::Regex::new(TOKEN_REGEX_SRC).unwrap();
|
static ref TOKEN_REGEX: regex::Regex = regex::Regex::new(TOKEN_REGEX_SRC).unwrap();
|
||||||
|
@ -405,6 +477,7 @@ 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
|
||||||
|
@ -440,7 +513,7 @@ pub fn tokenize<'a>(source: &'a str) -> VecDeque<Token<'a>> {
|
||||||
14 => Token::Terminator(debug_info),
|
14 => Token::Terminator(debug_info),
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
debug_info.print(MessageType::Error, "Unable to identify sequence as token", source);
|
println!("{}", debug_info.make_msg(crate::msg::ERR71));
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
pi:
|
||||||
|
Load Rat 5.1415926535
|
||||||
|
foo:
|
||||||
|
Load Int 5
|
||||||
|
Load Int 6
|
||||||
|
Add
|
||||||
|
Store Some(Int) x
|
||||||
|
Load Arg x
|
||||||
|
Load Int 6
|
||||||
|
Lt
|
||||||
|
If
|
||||||
|
Load Bool true
|
||||||
|
Yield
|
||||||
|
Please
|
||||||
|
Load Arg x
|
||||||
|
Load Int 6
|
||||||
|
Lt
|
||||||
|
If
|
||||||
|
Load Bool true
|
||||||
|
Yield
|
||||||
|
Load Bool false
|
||||||
|
Yield
|
||||||
|
main:
|
||||||
|
Load Int 4
|
||||||
|
Store None a
|
||||||
|
Load Rat 5.5
|
||||||
|
Store None b
|
||||||
|
Load Bool true
|
||||||
|
Store None c
|
||||||
|
Load Int 3
|
||||||
|
Load Rat 3.4
|
||||||
|
Call foo
|
||||||
|
Store None r
|
||||||
|
Load Int 0
|
Loading…
Reference in New Issue