function return type added

This commit is contained in:
Sven Vogel 2022-10-27 07:25:58 +02:00
parent a9b150a40e
commit 6e5461ce33
4 changed files with 130 additions and 73 deletions

View File

@ -18,17 +18,19 @@ fn main() {
let source = let source =
r" r"
pi = 3.1415926535 #pi = 3.1415926535
foo(x:i4, y:f4) { foo(x :int, y: rat) = bool {
} }
main() { main {
a:i4 = 8 unless 3 > 4 {
b:f4 = 9 a = 4 + 5;
b = 0.3 + 7;
foo(a, 6) foo(a, b)
}
} }
"; ";

View File

@ -28,6 +28,8 @@ pub struct Declr<'a> {
pub args: Option<Vec<(&'a str, Prim)>>, pub args: Option<Vec<(&'a str, Prim)>>,
/// if the function returns a single value /// if the function returns a single value
pub results: bool, pub results: bool,
/// type of result
pub result_typ: Option<Prim>
} }
impl<'a> Declr<'a> { impl<'a> Declr<'a> {
@ -35,7 +37,8 @@ impl<'a> Declr<'a> {
Self { Self {
name: None, name: None,
args: None, args: None,
results: false results: false,
result_typ: None
} }
} }
} }

View File

@ -22,11 +22,16 @@ 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) => {
if declrs.contains(&declr) { if declrs.contains(&declr) {
panic!("Function defined multiple times: {declr}") panic!("Function defined multiple times: {declr}")
} }
if declr.results && declr.result_typ.is_none() {
$dbginf.print(MessageType::Error, format!("Function is missing return type: {}", declr).as_str(), source);
panic!();
}
funcs.push(func); funcs.push(func);
declrs.push(declr); declrs.push(declr);
declr = Declr::new(); declr = Declr::new();
@ -62,15 +67,25 @@ fn discover_functions<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &str)
'}' => { '}' => {
brace_cnt -= 1; brace_cnt -= 1;
if brace_cnt == 0 { if brace_cnt == 0 {
finish_func!(); finish_func!(dbginf);
continue; continue;
} }
} }
_ => () _ => ()
} }
Token::LineBreak(_) => if single_line { Token::Type(typ, dbginf) => {
finish_func!(); if declr.results {
declr.result_typ = Some(*typ);
continue;
} else {
dbginf.print(MessageType::Error, "Missing equal sign", source);
panic!();
}
},
Token::LineBreak(dbginf) => if single_line {
finish_func!(dbginf);
continue; continue;
} }
@ -99,6 +114,23 @@ fn discover_functions<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &str)
_ => () _ => ()
} }
Token::Word(text, dbginf) => {
if declr.name.is_some() {
if declr.args.is_none() {
dbginf.print(MessageType::Error, "multiple function names", source);
panic!();
}
} else if brace_cnt > 0 {
dbginf.print(MessageType::Error, "brace count missmatch", source);
panic!();
}
else {
declr.name = Some(text);
continue;
}
},
Token::Assign(name, _, dbginf) => { Token::Assign(name, _, dbginf) => {
if declr.results { if declr.results {
dbginf.print(MessageType::Error, "double function assignment", source); dbginf.print(MessageType::Error, "double function assignment", source);
@ -139,23 +171,6 @@ fn discover_functions<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &str)
} }
_ => () _ => ()
} }
Token::Word(text, dbginf) => {
if declr.name.is_some() {
if declr.args.is_none() {
dbginf.print(MessageType::Error, "multiple function names", source);
panic!();
}
} else if brace_cnt > 0 {
dbginf.print(MessageType::Error, "brace count missmatch", source);
panic!();
}
else {
declr.name = Some(text);
continue;
}
}
_ => () _ => ()
} }
} }
@ -298,7 +313,7 @@ fn check_var_typ(typ: &mut Option<Prim>, operands: &mut Vec<Prim>, dbginf: &crat
fn process_keyword(keyword: Keyword, _: &Vec<Declr>, _: &mut Scope, operands: &mut Vec<Prim>, dbginf: &crate::token::DebugInfo, source: &str) { fn process_keyword(keyword: Keyword, _: &Vec<Declr>, _: &mut Scope, operands: &mut Vec<Prim>, dbginf: &crate::token::DebugInfo, source: &str) {
match keyword { match keyword {
Keyword::If => { 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); dbginf.print(MessageType::Error, format!("Expected single boolean got {} values", operands.len()).as_str(), source);
panic!(); panic!();
@ -331,7 +346,7 @@ fn collapse_operation(operation: &Token, declrs: &Vec<Declr>, scope: &mut Scope,
} }
} }
fn call_func(name: &str, declrs: &Vec<Declr>, scope: &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, source: &str) {
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 {
@ -391,9 +406,9 @@ fn parse_term<'a>(term: &mut VecDeque<Token<'a>>, declrs: &Vec<Declr<'a>>, scope
output.push_back(token); output.push_back(token);
value_stack.push(Prim::Bool) value_stack.push(Prim::Bool)
}, },
Token::Number(_, _) => { Token::Number(_, hint, _) => {
output.push_back(token); output.push_back(token);
value_stack.push(Prim::UntypedNum) value_stack.push(Prim::UntypedNum(*hint))
}, },
Token::Assign(_, _, _) => { Token::Assign(_, _, _) => {
op_stack.push(token); op_stack.push(token);
@ -521,7 +536,9 @@ pub fn parse<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &'a str) -> Ve
discover_exprs(&mut funcs, &declrs, source); discover_exprs(&mut funcs, &declrs, source);
parse_exprs(&mut funcs, &declrs, source); parse_exprs(&mut funcs, &declrs, source);
funcs.iter().for_each(|f| println!("{:?}", f)); for (x, f) in funcs.iter().enumerate() {
println!("{:?}{:?}", declrs[x], f);
}
funcs funcs
} }

View File

@ -108,16 +108,21 @@ impl Operator {
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, &[
// +-----------------------------------+---------------------------------+ // +-------------------------------------------------------------------------------+---------------------------------+
// | Parameter list of types | result type | // | Parameter list of types | result type |
// +-----------------------------------+---------------------------------+ // +-------------------------------------------------------------------------------+---------------------------------+
(vec![Prim::Int, Prim::Int ], Prim::Int ), (vec![Prim::Int, Prim::Int ], Prim::Int),
(vec![Prim::Real, Prim::Real ], Prim::Real), (vec![Prim::Rat, Prim::Rat ], Prim::Rat),
(vec![Prim::UntypedNum, Prim::Int ], Prim::Int ), (vec![Prim::UntypedNum(NumberClassHint::Int), Prim::Int ], Prim::Int),
(vec![Prim::UntypedNum, Prim::Real ], Prim::Real), (vec![Prim::UntypedNum(NumberClassHint::Int), Prim::Rat ], Prim::Rat),
(vec![Prim::Int, Prim::UntypedNum], Prim::Int ), (vec![Prim::UntypedNum(NumberClassHint::Rat), Prim::Rat ], Prim::Rat),
(vec![Prim::Real, Prim::UntypedNum], Prim::Real), (vec![Prim::Int, Prim::UntypedNum(NumberClassHint::Int)], Prim::Int),
(vec![Prim::UntypedNum, Prim::UntypedNum], Prim::UntypedNum) (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); ], dbginf, source);
if let Some(result) = types_valid { if let Some(result) = types_valid {
@ -125,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 reals", self).as_str(), source); dbginf.print(MessageType::Error, format!("Missmatched types for {:?}, expected either two integer or rationals", self).as_str(), source);
panic!() panic!()
} }
}, },
@ -145,17 +150,20 @@ impl Operator {
}, },
Operator::Eq | Operator::NotEq | Operator::Lt | Operator::Gt | Operator::GtEq | Operator::LtEq => { Operator::Eq | Operator::NotEq | Operator::Lt | Operator::Gt | Operator::GtEq | Operator::LtEq => {
let types_valid = Self::check_types(operands, &[ let types_valid = Self::check_types(operands, &[
(vec![Prim::Int, Prim::Int ], Prim::Bool ), // +-------------------------------------------------------------------------------+---------------------------------+
(vec![Prim::Real, Prim::Real ], Prim::Bool ), // | Parameter list of types | result type |
(vec![Prim::UntypedNum, Prim::Int ], Prim::Bool ), // +-------------------------------------------------------------------------------+---------------------------------+
(vec![Prim::UntypedNum, Prim::Real ], Prim::Bool ), (vec![Prim::Int, Prim::Int ], Prim::Bool ),
(vec![Prim::Int, Prim::UntypedNum], Prim::Bool ), (vec![Prim::Rat, Prim::Rat ], Prim::Bool ),
(vec![Prim::Real, Prim::UntypedNum], Prim::Bool ), (vec![Prim::UntypedNum(NumberClassHint::Int), Prim::Int ], Prim::Bool ),
(vec![Prim::UntypedNum, Prim::UntypedNum], Prim::Bool ) (vec![Prim::UntypedNum(NumberClassHint::Rat), Prim::Rat ], Prim::Bool ),
(vec![Prim::Int, Prim::UntypedNum(NumberClassHint::Int)], Prim::Bool ),
(vec![Prim::Rat, Prim::UntypedNum(NumberClassHint::Rat)], Prim::Bool ),
(vec![Prim::UntypedNum(NumberClassHint::Rat), Prim::UntypedNum(NumberClassHint::Rat)], Prim::Bool ),
(vec![Prim::UntypedNum(NumberClassHint::Int), Prim::UntypedNum(NumberClassHint::Int)], Prim::Bool )
], dbginf, source); ], dbginf, source);
if let Some(result) = types_valid { if let Some(result) = types_valid {
println!("checked: {:?} for: {:?}", self, operands);
operands.pop(); operands.pop();
operands.pop(); operands.pop();
@ -193,20 +201,37 @@ impl Keyword {
} }
} }
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
pub enum NumberClassHint {
Int,
Rat
}
impl NumberClassHint {
pub fn from(str: &str) -> NumberClassHint {
if str.parse::<i32>().is_err() {
return NumberClassHint::Rat;
}
NumberClassHint::Int
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
/// primitve types /// primitve types
pub enum Prim { pub enum Prim {
Int, Int,
Real, Rat,
Bool, Bool,
UntypedNum UntypedNum(NumberClassHint)
} }
impl Prim { impl Prim {
fn from<'a>(text: &'a str, dbginf: &DebugInfo, source: &str) -> Prim { fn from<'a>(text: &'a str, dbginf: &DebugInfo, source: &str) -> Prim {
return match text { return match text {
"i4" => Prim::Int, "int" => Prim::Int,
"f4" => Prim::Real, "rat" => Prim::Rat,
"bool" => Prim::Bool, "bool" => Prim::Bool,
_ => { _ => {
@ -219,16 +244,21 @@ impl Prim {
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::Real => return match value { Prim::Rat => return match value {
Prim::UntypedNum => true, Prim::UntypedNum(NumberClassHint::Int) => true,
Prim::UntypedNum(NumberClassHint::Rat) => true,
_ => *self == value, _ => *self == value,
}, },
Prim::Int => return match value { Prim::Int => return match value {
Prim::UntypedNum => true, Prim::UntypedNum(NumberClassHint::Int) => true,
_ => *self == value, _ => *self == value,
}, },
Prim::UntypedNum => return match value { Prim::UntypedNum(NumberClassHint::Rat) => return match value {
Prim::Real | Prim::Int => true, Prim::Rat | Prim::Int => true,
_ => *self == value,
},
Prim::UntypedNum(NumberClassHint::Int) => return match value {
Prim::Int => true,
_ => *self == value, _ => *self == value,
}, },
} }
@ -289,7 +319,7 @@ pub enum Token<'a> {
/// Single symbol delemiter like ```(```,```}``` /// Single symbol delemiter like ```(```,```}```
Delemiter(char, DebugInfo), Delemiter(char, DebugInfo),
Operator(Operator, DebugInfo), Operator(Operator, DebugInfo),
Number(&'a str, DebugInfo), Number(&'a str, NumberClassHint, DebugInfo),
LineBreak(DebugInfo), LineBreak(DebugInfo),
Func(&'a str, DebugInfo), Func(&'a str, DebugInfo),
/// Variable /// Variable
@ -303,16 +333,18 @@ pub enum Token<'a> {
Bool(bool, DebugInfo), Bool(bool, DebugInfo),
/// Keywords like ```if```,```break```,```while``` /// Keywords like ```if```,```break```,```while```
Keyword(Keyword, DebugInfo), Keyword(Keyword, DebugInfo),
Type(Prim, DebugInfo)
} }
impl<'a> Token<'a> { impl<'a> Token<'a> {
/// redirect for ```DebugInfo.print()``` /// redirect for ```DebugInfo.print()```
pub fn print(&self, error: MessageType, arg: &str, source: &str) { pub fn print(&self, error: MessageType, arg: &str, source: &str) {
match self { match self {
Token::Type(_, dbginf) => dbginf.print(error, arg, source),
Token::Word(_, dbginf) => dbginf.print(error, arg, source), Token::Word(_, dbginf) => dbginf.print(error, arg, source),
Token::Delemiter(_, dbginf) => dbginf.print(error, arg, source), Token::Delemiter(_, dbginf) => dbginf.print(error, arg, source),
Token::Operator(_, dbginf) => dbginf.print(error, arg, source), Token::Operator(_, dbginf) => dbginf.print(error, arg, source),
Token::Number(_, dbginf) => dbginf.print(error, arg, source), Token::Number(_, _, dbginf) => dbginf.print(error, arg, source),
Token::LineBreak(dbginf) => dbginf.print(error, arg, source), Token::LineBreak(dbginf) => dbginf.print(error, arg, source),
Token::Func(_, dbginf) => dbginf.print(error, arg, source), Token::Func(_, dbginf) => dbginf.print(error, arg, source),
Token::Var(_, dbginf) => dbginf.print(error, arg, source), Token::Var(_, dbginf) => dbginf.print(error, arg, source),
@ -325,7 +357,7 @@ impl<'a> Token<'a> {
} }
} }
const TOKEN_REGEX_SRC: &'static str = r"(#.*)|(unless|while|loop|break|continue)|(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|continue)|(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();
@ -363,8 +395,11 @@ pub fn tokenize<'a>(source: &'a str) -> VecDeque<Token<'a>> {
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 => Token::Bool(parse_bool(mat.as_str()), debug_info), 3 => {
4 => { Token::Type(Prim::from(mat.as_str(), &debug_info, source), debug_info)
},
4 => Token::Bool(parse_bool(mat.as_str()), debug_info),
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, source))
} else { } else {
@ -372,15 +407,15 @@ pub fn tokenize<'a>(source: &'a str) -> VecDeque<Token<'a>> {
}; };
Token::Assign(mat.as_str(), var_type, debug_info) Token::Assign(mat.as_str(), var_type, debug_info)
}, },
6 => { 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, source);
Token::Decl(mat.as_str(), var_type, debug_info) Token::Decl(mat.as_str(), var_type, debug_info)
}, },
8 => Token::Word(mat.as_str(), debug_info), 9 => Token::Word(mat.as_str(), debug_info),
9 => Token::Number(mat.as_str(), debug_info), 10 => Token::Number(mat.as_str(), NumberClassHint::from(mat.as_str()), debug_info),
10 => Token::Operator(Operator::parse(mat.as_str()), debug_info), 11 => Token::Operator(Operator::parse(mat.as_str()), debug_info),
11 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap(), debug_info), 12 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap(), debug_info),
12 => { 13 => {
line_count += 1; line_count += 1;
Token::LineBreak(debug_info) Token::LineBreak(debug_info)
}, },