diff --git a/src/main.rs b/src/main.rs index 48f46d8..e5c75b4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,17 +18,19 @@ fn main() { let source = r" -pi = 3.1415926535 +#pi = 3.1415926535 -foo(x:i4, y:f4) { +foo(x :int, y: rat) = bool { } -main() { - a:i4 = 8 - b:f4 = 9 - - foo(a, 6) +main { + unless 3 > 4 { + a = 4 + 5; + b = 0.3 + 7; + + foo(a, b) + } } "; diff --git a/src/parser/data.rs b/src/parser/data.rs index 6b6d5f7..14d4433 100644 --- a/src/parser/data.rs +++ b/src/parser/data.rs @@ -28,6 +28,8 @@ pub struct Declr<'a> { pub args: Option>, /// if the function returns a single value pub results: bool, + /// type of result + pub result_typ: Option } impl<'a> Declr<'a> { @@ -35,7 +37,8 @@ impl<'a> Declr<'a> { Self { name: None, args: None, - results: false + results: false, + result_typ: None } } } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 0042f38..39d4eb7 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -22,11 +22,16 @@ fn discover_functions<'a>(tokens: &mut VecDeque>, source: &str) let mut single_line = false; macro_rules! finish_func { - () => { + ($dbginf:expr) => { if declrs.contains(&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); declrs.push(declr); declr = Declr::new(); @@ -62,15 +67,25 @@ fn discover_functions<'a>(tokens: &mut VecDeque>, source: &str) '}' => { brace_cnt -= 1; if brace_cnt == 0 { - finish_func!(); + finish_func!(dbginf); continue; } } _ => () } + + Token::Type(typ, dbginf) => { + if declr.results { + declr.result_typ = Some(*typ); + continue; + } else { + dbginf.print(MessageType::Error, "Missing equal sign", source); + panic!(); + } + }, - Token::LineBreak(_) => if single_line { - finish_func!(); + Token::LineBreak(dbginf) => if single_line { + finish_func!(dbginf); continue; } @@ -99,6 +114,23 @@ fn discover_functions<'a>(tokens: &mut VecDeque>, 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) => { if declr.results { dbginf.print(MessageType::Error, "double function assignment", source); @@ -139,23 +171,6 @@ fn discover_functions<'a>(tokens: &mut VecDeque>, 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, operands: &mut Vec, dbginf: &crat fn process_keyword(keyword: Keyword, _: &Vec, _: &mut Scope, operands: &mut Vec, dbginf: &crate::token::DebugInfo, source: &str) { match keyword { - Keyword::If => { + Keyword::If | Keyword::While => { if operands.len() != 1 { dbginf.print(MessageType::Error, format!("Expected single boolean got {} values", operands.len()).as_str(), source); panic!(); @@ -331,7 +346,7 @@ fn collapse_operation(operation: &Token, declrs: &Vec, scope: &mut Scope, } } -fn call_func(name: &str, declrs: &Vec, scope: &mut Scope, operands: &mut Vec, dbginf: &crate::token::DebugInfo, source: &str) { +fn call_func(name: &str, declrs: &Vec, _: &mut Scope, operands: &mut Vec, dbginf: &crate::token::DebugInfo, source: &str) { for declr in declrs { if declr.name.is_some() && declr.name.unwrap() == name { @@ -391,9 +406,9 @@ fn parse_term<'a>(term: &mut VecDeque>, declrs: &Vec>, scope output.push_back(token); value_stack.push(Prim::Bool) }, - Token::Number(_, _) => { + Token::Number(_, hint, _) => { output.push_back(token); - value_stack.push(Prim::UntypedNum) + value_stack.push(Prim::UntypedNum(*hint)) }, Token::Assign(_, _, _) => { op_stack.push(token); @@ -521,7 +536,9 @@ pub fn parse<'a>(tokens: &mut VecDeque>, source: &'a str) -> Ve discover_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 } \ No newline at end of file diff --git a/src/token/mod.rs b/src/token/mod.rs index 4b2f693..4d97ddb 100644 --- a/src/token/mod.rs +++ b/src/token/mod.rs @@ -108,16 +108,21 @@ impl Operator { match self { Operator::Add | Operator::Sub | Operator::Mul | Operator::Div=> { let types_valid = Self::check_types(operands, &[ - // +-----------------------------------+---------------------------------+ - // | Parameter list of types | result type | - // +-----------------------------------+---------------------------------+ - (vec![Prim::Int, Prim::Int ], Prim::Int ), - (vec![Prim::Real, Prim::Real ], Prim::Real), - (vec![Prim::UntypedNum, Prim::Int ], Prim::Int ), - (vec![Prim::UntypedNum, Prim::Real ], Prim::Real), - (vec![Prim::Int, Prim::UntypedNum], Prim::Int ), - (vec![Prim::Real, Prim::UntypedNum], Prim::Real), - (vec![Prim::UntypedNum, Prim::UntypedNum], Prim::UntypedNum) + // +-------------------------------------------------------------------------------+---------------------------------+ + // | Parameter list of types | result type | + // +-------------------------------------------------------------------------------+---------------------------------+ + (vec![Prim::Int, Prim::Int ], Prim::Int), + (vec![Prim::Rat, Prim::Rat ], Prim::Rat), + (vec![Prim::UntypedNum(NumberClassHint::Int), Prim::Int ], Prim::Int), + (vec![Prim::UntypedNum(NumberClassHint::Int), Prim::Rat ], Prim::Rat), + (vec![Prim::UntypedNum(NumberClassHint::Rat), Prim::Rat ], Prim::Rat), + (vec![Prim::Int, Prim::UntypedNum(NumberClassHint::Int)], Prim::Int), + (vec![Prim::Rat, Prim::UntypedNum(NumberClassHint::Rat)], Prim::Rat), + (vec![Prim::Rat, Prim::UntypedNum(NumberClassHint::Int)], Prim::Rat), + (vec![Prim::UntypedNum(NumberClassHint::Rat), Prim::UntypedNum(NumberClassHint::Rat)], Prim::Rat), + (vec![Prim::UntypedNum(NumberClassHint::Int), Prim::UntypedNum(NumberClassHint::Rat)], Prim::Rat), + (vec![Prim::UntypedNum(NumberClassHint::Rat), Prim::UntypedNum(NumberClassHint::Int)], Prim::Rat), + (vec![Prim::UntypedNum(NumberClassHint::Int), Prim::UntypedNum(NumberClassHint::Int)], Prim::Int) ], dbginf, source); if let Some(result) = types_valid { @@ -125,7 +130,7 @@ impl Operator { operands.pop(); operands.push(result); } 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!() } }, @@ -145,17 +150,20 @@ impl Operator { }, Operator::Eq | Operator::NotEq | Operator::Lt | Operator::Gt | Operator::GtEq | Operator::LtEq => { let types_valid = Self::check_types(operands, &[ - (vec![Prim::Int, Prim::Int ], Prim::Bool ), - (vec![Prim::Real, Prim::Real ], Prim::Bool ), - (vec![Prim::UntypedNum, Prim::Int ], Prim::Bool ), - (vec![Prim::UntypedNum, Prim::Real ], Prim::Bool ), - (vec![Prim::Int, Prim::UntypedNum], Prim::Bool ), - (vec![Prim::Real, Prim::UntypedNum], Prim::Bool ), - (vec![Prim::UntypedNum, Prim::UntypedNum], Prim::Bool ) + // +-------------------------------------------------------------------------------+---------------------------------+ + // | Parameter list of types | result type | + // +-------------------------------------------------------------------------------+---------------------------------+ + (vec![Prim::Int, Prim::Int ], Prim::Bool ), + (vec![Prim::Rat, Prim::Rat ], Prim::Bool ), + (vec![Prim::UntypedNum(NumberClassHint::Int), Prim::Int ], Prim::Bool ), + (vec![Prim::UntypedNum(NumberClassHint::Rat), Prim::Rat ], Prim::Bool ), + (vec![Prim::Int, Prim::UntypedNum(NumberClassHint::Int)], Prim::Bool ), + (vec![Prim::Rat, Prim::UntypedNum(NumberClassHint::Rat)], Prim::Bool ), + (vec![Prim::UntypedNum(NumberClassHint::Rat), Prim::UntypedNum(NumberClassHint::Rat)], Prim::Bool ), + (vec![Prim::UntypedNum(NumberClassHint::Int), Prim::UntypedNum(NumberClassHint::Int)], Prim::Bool ) ], dbginf, source); if let Some(result) = types_valid { - println!("checked: {:?} for: {:?}", self, operands); 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::().is_err() { + return NumberClassHint::Rat; + } + + NumberClassHint::Int + } +} + #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] /// primitve types pub enum Prim { Int, - Real, + Rat, Bool, - UntypedNum + UntypedNum(NumberClassHint) } impl Prim { fn from<'a>(text: &'a str, dbginf: &DebugInfo, source: &str) -> Prim { return match text { - "i4" => Prim::Int, - "f4" => Prim::Real, + "int" => Prim::Int, + "rat" => Prim::Rat, "bool" => Prim::Bool, _ => { @@ -219,16 +244,21 @@ impl Prim { pub fn is_equal(&self, value: Prim) -> bool { return match self { Prim::Bool => *self == value, - Prim::Real => return match value { - Prim::UntypedNum => true, + Prim::Rat => return match value { + Prim::UntypedNum(NumberClassHint::Int) => true, + Prim::UntypedNum(NumberClassHint::Rat) => true, _ => *self == value, }, Prim::Int => return match value { - Prim::UntypedNum => true, + Prim::UntypedNum(NumberClassHint::Int) => true, _ => *self == value, }, - Prim::UntypedNum => return match value { - Prim::Real | Prim::Int => true, + Prim::UntypedNum(NumberClassHint::Rat) => return match value { + Prim::Rat | Prim::Int => true, + _ => *self == value, + }, + Prim::UntypedNum(NumberClassHint::Int) => return match value { + Prim::Int => true, _ => *self == value, }, } @@ -289,7 +319,7 @@ pub enum Token<'a> { /// Single symbol delemiter like ```(```,```}``` Delemiter(char, DebugInfo), Operator(Operator, DebugInfo), - Number(&'a str, DebugInfo), + Number(&'a str, NumberClassHint, DebugInfo), LineBreak(DebugInfo), Func(&'a str, DebugInfo), /// Variable @@ -303,16 +333,18 @@ pub enum Token<'a> { Bool(bool, DebugInfo), /// Keywords like ```if```,```break```,```while``` Keyword(Keyword, DebugInfo), + Type(Prim, DebugInfo) } impl<'a> Token<'a> { /// redirect for ```DebugInfo.print()``` pub fn print(&self, error: MessageType, arg: &str, source: &str) { match self { + Token::Type(_, dbginf) => dbginf.print(error, arg, source), Token::Word(_, dbginf) => dbginf.print(error, arg, source), Token::Delemiter(_, 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::Func(_, 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! { 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> { tokens.push_back(match i { 2 => Token::Keyword(Keyword::parse(mat.as_str()), debug_info), - 3 => Token::Bool(parse_bool(mat.as_str()), debug_info), - 4 => { + 3 => { + 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 { Some(Prim::from(mat.as_str(), &debug_info, source)) } else { @@ -372,15 +407,15 @@ pub fn tokenize<'a>(source: &'a str) -> VecDeque> { }; 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); Token::Decl(mat.as_str(), var_type, debug_info) }, - 8 => Token::Word(mat.as_str(), debug_info), - 9 => Token::Number(mat.as_str(), debug_info), - 10 => Token::Operator(Operator::parse(mat.as_str()), debug_info), - 11 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap(), debug_info), - 12 => { + 9 => Token::Word(mat.as_str(), debug_info), + 10 => Token::Number(mat.as_str(), NumberClassHint::from(mat.as_str()), debug_info), + 11 => Token::Operator(Operator::parse(mat.as_str()), debug_info), + 12 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap(), debug_info), + 13 => { line_count += 1; Token::LineBreak(debug_info) },