diff --git a/src/syntax/ast/functions.rs b/src/syntax/ast/functions.rs index 0a731d1..91269e4 100644 --- a/src/syntax/ast/functions.rs +++ b/src/syntax/ast/functions.rs @@ -1,14 +1,11 @@ - - #[derive(Debug)] pub struct FunctionCall { - pub identifier: Box + pub identifier: Box, } - #[derive(Debug)] pub struct ArgumentsList { - pub arguments: Vec> + pub arguments: Vec>, } #[derive(Debug)] diff --git a/src/syntax/ast/mod.rs b/src/syntax/ast/mod.rs index 5d10324..7374dd8 100644 --- a/src/syntax/ast/mod.rs +++ b/src/syntax/ast/mod.rs @@ -1,6 +1,5 @@ pub mod functions; - pub struct ModuleAST { pub declarations: Vec, } diff --git a/src/syntax/functions/arguments_list.rs b/src/syntax/functions/arguments_list.rs new file mode 100644 index 0000000..d498fd4 --- /dev/null +++ b/src/syntax/functions/arguments_list.rs @@ -0,0 +1,92 @@ +use crate::{ + error_handling::SyntaxError, + lexic::token::{Token, TokenType}, + syntax::{ast::functions::ArgumentsList, utils::parse_token_type, ParseResult}, +}; + +pub fn try_parse<'a>(tokens: &'a Vec, pos: usize) -> ParseResult { + let mut current_pos = pos; + + let (opening_paren, next_pos) = + match parse_token_type(tokens, current_pos, TokenType::LeftParen) { + ParseResult::Ok(t, next) => (t, next), + ParseResult::Err(err) => return ParseResult::Err(err), + ParseResult::Mismatch(t) => return ParseResult::Mismatch(t), + ParseResult::Unmatched => return ParseResult::Unmatched, + }; + current_pos = next_pos; + + // Parse closing paren + let (_closing_paren, next_pos) = + match parse_token_type(tokens, current_pos, TokenType::RightParen) { + ParseResult::Ok(t, next) => (t, next), + ParseResult::Err(err) => return ParseResult::Err(err), + ParseResult::Mismatch(t) => { + return ParseResult::Err(SyntaxError { + reason: String::from("Expected a closing paren after the function identifier."), + error_start: t.position, + error_end: t.get_end_position(), + }); + } + ParseResult::Unmatched => { + return ParseResult::Err(SyntaxError { + reason: String::from("Expected a closing paren after the function identifier."), + error_start: opening_paren.position, + error_end: opening_paren.get_end_position(), + }); + } + }; + current_pos = next_pos; + + ParseResult::Ok( + ArgumentsList { + arguments: Vec::new(), + }, + current_pos, + ) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::lexic::get_tokens; + + #[test] + fn should_parse_empty_list() { + let tokens = get_tokens(&String::from("()")).unwrap(); + let fun_decl = try_parse(&tokens, 0); + + let ParseResult::Ok(list, next) = fun_decl else { + panic!("Expected an unmatched result: {:?}", fun_decl); + }; + + assert_eq!(next, 2); + assert_eq!(list.arguments.len(), 0); + } + + #[test] + fn should_parse_empty_list_with_whitespace() { + let tokens = get_tokens(&String::from("( ) ")).unwrap(); + let fun_decl = try_parse(&tokens, 0); + + let ParseResult::Ok(list, next) = fun_decl else { + panic!("Expected a result, got: {:?}", fun_decl); + }; + + assert_eq!(next, 2); + assert_eq!(list.arguments.len(), 0); + } + + #[test] + fn should_parse_empty_list_with_whitespace_2() { + let tokens = get_tokens(&String::from("(\n \n)")).unwrap(); + let fun_decl = try_parse(&tokens, 0); + + let ParseResult::Ok(list, next) = fun_decl else { + panic!("Expected a result, got: {:?}", fun_decl); + }; + + assert_eq!(next, 3); + assert_eq!(list.arguments.len(), 0); + } +} diff --git a/src/syntax/functions/function_call.rs b/src/syntax/functions/function_call.rs index 1e841c2..a81abdc 100644 --- a/src/syntax/functions/function_call.rs +++ b/src/syntax/functions/function_call.rs @@ -1,10 +1,13 @@ -use crate::{lexic::token::{Token, TokenType}, syntax::{ParseResult, ast::functions::FunctionCall, utils::parse_token_type}, error_handling::SyntaxError}; - - +use crate::{ + error_handling::SyntaxError, + lexic::token::{Token, TokenType}, + syntax::{ast::functions::FunctionCall, utils::parse_token_type, ParseResult}, +}; pub fn try_parse<'a>(tokens: &'a Vec, pos: usize) -> ParseResult { let mut current_pos = pos; + // TODO: Use an expression instead of a fixed identifier // Parse identifier let (identifier, next_pos) = match parse_token_type(tokens, current_pos, TokenType::Identifier) { @@ -20,15 +23,25 @@ pub fn try_parse<'a>(tokens: &'a Vec, pos: usize) -> ParseResult (args, next), + ParseResult::Err(err) => return ParseResult::Err(err), + ParseResult::Mismatch(_) => { + return ParseResult::Unmatched; + } + ParseResult::Unmatched => { + return ParseResult::Unmatched; + } + }; + current_pos = next_pos; - ParseResult::Unmatched + ParseResult::Ok(FunctionCall { identifier: Box::new(identifier.value.clone()) }, current_pos) } - #[cfg(test)] mod tests { - use crate::lexic::get_tokens; use super::*; + use crate::lexic::get_tokens; #[test] fn should_not_parse_identifier_alone() { @@ -39,4 +52,40 @@ mod tests { panic!("Expected an unmatched result: {:?}", fun_decl); }; } + + #[test] + fn should_parse_minimal_construct() { + let tokens = get_tokens(&String::from("function_name()")).unwrap(); + let fun_decl = try_parse(&tokens, 0); + + let ParseResult::Ok(_call, next) = fun_decl else { + panic!("Expected a result, got: {:?}", fun_decl); + }; + + assert_eq!(next, 3); + } + + #[test] + fn should_parse_minimal_construct_2() { + let tokens = get_tokens(&String::from("function_name ( )")).unwrap(); + let fun_decl = try_parse(&tokens, 0); + + let ParseResult::Ok(_call, next) = fun_decl else { + panic!("Expected a result, got: {:?}", fun_decl); + }; + + assert_eq!(next, 3); + } + + #[test] + fn should_parse_minimal_construct_3() { + let tokens = get_tokens(&String::from("function_name\n(\n \n)")).unwrap(); + let fun_decl = try_parse(&tokens, 0); + + let ParseResult::Ok(_call, next) = fun_decl else { + panic!("Expected a result, got: {:?}", fun_decl); + }; + + assert_eq!(next, 5); + } } diff --git a/src/syntax/functions/mod.rs b/src/syntax/functions/mod.rs index 1b867ec..e0cca0d 100644 --- a/src/syntax/functions/mod.rs +++ b/src/syntax/functions/mod.rs @@ -1,2 +1,2 @@ -pub mod function_call; pub mod arguments_list; +pub mod function_call; diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index 0807513..e96d253 100755 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -4,9 +4,9 @@ mod binding; mod block; mod expression; mod function_declaration; +mod functions; mod params_list; mod utils; -mod functions; pub mod ast; @@ -33,7 +33,7 @@ pub enum ParseResult { /// The parsing was a success Ok(A, usize), /// The parsing failed past a point of no return. - /// + /// /// For example, when parsing a function declaration /// the `fun` token is found, but then no identifier Err(SyntaxError),