diff --git a/CHANGELOG.md b/CHANGELOG.md index 40aa6e8..11c1bec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,7 +40,7 @@ - [ ] Formally define the top level constructs - [ ] Parse bindings and function declarations as top level constructs - [ ] Parse function declaration arguments (`Type id`) -- [ ] Parse function return datatype (`fun f() -> Type`) +- [x] Parse function return datatype (`fun f() -> Type`) - [x] Return parsing to variables to var/val - [ ] Write tests diff --git a/src/lexic/token.rs b/src/lexic/token.rs index 074ddf1..55eb00c 100755 --- a/src/lexic/token.rs +++ b/src/lexic/token.rs @@ -22,7 +22,7 @@ pub enum TokenType { FUN, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct Token { pub token_type: TokenType, // The token as a raw string diff --git a/src/syntax/ast/mod.rs b/src/syntax/ast/mod.rs index 0677042..8d8aee5 100644 --- a/src/syntax/ast/mod.rs +++ b/src/syntax/ast/mod.rs @@ -20,6 +20,7 @@ pub enum TopLevelDeclaration<'a> { #[derive(Debug)] pub struct FunctionDeclaration<'a> { pub identifier: &'a Token, + pub return_type: Option<&'a Token>, pub params_list: Box, pub block: Box>, } diff --git a/src/syntax/functions/function_declaration.rs b/src/syntax/functions/function_declaration.rs index b96324c..eb8ca30 100644 --- a/src/syntax/functions/function_declaration.rs +++ b/src/syntax/functions/function_declaration.rs @@ -1,7 +1,7 @@ use crate::{ error_handling::SyntaxError, lexic::token::{Token, TokenType}, - syntax::{ParsingError, ParsingResult}, + syntax::{utils::try_operator, ParsingError, ParsingResult}, }; use super::{ @@ -9,6 +9,13 @@ use super::{ params_list::parse_params_list, }; +/* +function declaration = "fun", identifier, params list, return type?, block; + +params list = "(", ")"; + +return type = ; + */ pub fn try_parse<'a>(tokens: &'a Vec, pos: usize) -> ParsingResult { let mut current_pos = pos; @@ -19,6 +26,7 @@ pub fn try_parse<'a>(tokens: &'a Vec, pos: usize) -> ParsingResult (id, next), @@ -40,19 +48,20 @@ pub fn try_parse<'a>(tokens: &'a Vec, pos: usize) -> ParsingResult (params, next_pos), Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)), Err(ParsingError::Mismatch(wrong_token)) => { return Err(ParsingError::Err(SyntaxError { - reason: String::from("Expected an opening paren afted the function identifier."), + reason: String::from("Expected an opening paren after the function identifier."), error_start: wrong_token.position, error_end: wrong_token.get_end_position(), })); } Err(ParsingError::Unmatched) => { return Err(ParsingError::Err(SyntaxError { - reason: String::from("Expected an opening paren afted the function identifier."), + reason: String::from("Expected an opening paren after the function identifier."), error_start: identifier.position, error_end: identifier.get_end_position(), })); @@ -60,6 +69,37 @@ pub fn try_parse<'a>(tokens: &'a Vec, pos: usize) -> ParsingResult' operator was matched, so we expect a datatype + match parse_token_type(tokens, next_pos, TokenType::Datatype) { + Ok((t, next)) => (Some(t), next), + Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)), + Err(ParsingError::Mismatch(wrong_token)) => { + return Err(ParsingError::Err(SyntaxError { + reason: String::from("Expected a datatype after the arrow operator."), + error_start: wrong_token.position, + error_end: wrong_token.get_end_position(), + })); + } + Err(ParsingError::Unmatched) => { + return Err(ParsingError::Err(SyntaxError { + reason: String::from("Expected a datatype after the arrow operator."), + error_start: arrow_op.position, + error_end: arrow_op.get_end_position(), + })); + } + } + }; + current_pos = next_pos; + + // Function body (block) let (block, next_pos) = match parse_block(tokens, current_pos) { Ok((block, next_pos)) => (block, next_pos), Err(ParsingError::Err(error)) => { @@ -86,6 +126,7 @@ pub fn try_parse<'a>(tokens: &'a Vec, pos: usize) -> ParsingResult(tokens: &'a Vec, pos: usize) -> ParsingResult { assert_eq!( err.reason, - "Expected an opening paren afted the function identifier." + "Expected an opening paren after the function identifier." ); assert_eq!(err.error_start, 7); assert_eq!(err.error_end, 8); @@ -164,7 +206,7 @@ mod tests { Err(ParsingError::Err(err)) => { assert_eq!( err.reason, - "Expected an opening paren afted the function identifier." + "Expected an opening paren after the function identifier." ); assert_eq!(err.error_start, 4); assert_eq!(err.error_end, 6); @@ -304,6 +346,46 @@ mod tests { let (function_declaration, _) = try_parse(&tokens, 0).unwrap(); assert_eq!(function_declaration.identifier.value, String::from("id")); + assert_eq!(function_declaration.return_type, None); + } + + #[test] + fn should_parse_return_type() { + let tokens = get_tokens(&String::from("fun id() -> String {}")).unwrap(); + let (function_declaration, _) = try_parse(&tokens, 0).unwrap(); + + assert_eq!(function_declaration.identifier.value, String::from("id")); + assert_eq!(function_declaration.return_type.unwrap().value, String::from("String")); + } + + #[test] + fn should_throw_error_on_return_type_1() { + let tokens = get_tokens(&String::from("fun id() -> {}")).unwrap(); + let fun_decl = try_parse(&tokens, 0); + + match fun_decl { + Err(ParsingError::Err(err)) => { + assert_eq!(err.reason, "Expected a datatype after the arrow operator."); + assert_eq!(err.error_start, 12); + assert_eq!(err.error_end, 13); + } + _ => panic!("Expected an error: {:?}", fun_decl), + } + } + + #[test] + fn should_throw_error_on_return_type_2() { + let tokens = get_tokens(&String::from("fun id() -> ")).unwrap(); + let fun_decl = try_parse(&tokens, 0); + + match fun_decl { + Err(ParsingError::Err(err)) => { + assert_eq!(err.reason, "Expected a datatype after the arrow operator."); + assert_eq!(err.error_start, 9); + assert_eq!(err.error_end, 11); + } + _ => panic!("Expected an error: {:?}", fun_decl), + } } } diff --git a/src/syntax/utils.rs b/src/syntax/utils.rs index b3f627d..7792e11 100644 --- a/src/syntax/utils.rs +++ b/src/syntax/utils.rs @@ -75,3 +75,5 @@ pub fn parse_token_type( None => Err(ParsingError::Unmatched), } } + +