Parse minimal function call

master
Araozu 2023-10-01 17:43:59 -05:00
parent c4d13e76bc
commit 971b9d9516
6 changed files with 152 additions and 15 deletions

View File

@ -1,14 +1,11 @@
#[derive(Debug)] #[derive(Debug)]
pub struct FunctionCall { pub struct FunctionCall {
pub identifier: Box<String> pub identifier: Box<String>,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct ArgumentsList { pub struct ArgumentsList {
pub arguments: Vec<Box<Argument>> pub arguments: Vec<Box<Argument>>,
} }
#[derive(Debug)] #[derive(Debug)]

View File

@ -1,6 +1,5 @@
pub mod functions; pub mod functions;
pub struct ModuleAST { pub struct ModuleAST {
pub declarations: Vec<TopLevelDeclaration>, pub declarations: Vec<TopLevelDeclaration>,
} }

View File

@ -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<Token>, pos: usize) -> ParseResult<ArgumentsList, &Token> {
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);
}
}

View File

@ -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<Token>, pos: usize) -> ParseResult<FunctionCall, ()> { pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<FunctionCall, ()> {
let mut current_pos = pos; let mut current_pos = pos;
// TODO: Use an expression instead of a fixed identifier
// Parse identifier // Parse identifier
let (identifier, next_pos) = match parse_token_type(tokens, current_pos, TokenType::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<Token>, pos: usize) -> ParseResult<Function
current_pos = next_pos; current_pos = next_pos;
// Parse arguments list // Parse arguments list
let (args_list, next_pos) = match super::arguments_list::try_parse(tokens, current_pos) {
ParseResult::Ok(args, next) => (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)] #[cfg(test)]
mod tests { mod tests {
use crate::lexic::get_tokens;
use super::*; use super::*;
use crate::lexic::get_tokens;
#[test] #[test]
fn should_not_parse_identifier_alone() { fn should_not_parse_identifier_alone() {
@ -39,4 +52,40 @@ mod tests {
panic!("Expected an unmatched result: {:?}", fun_decl); 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);
}
} }

View File

@ -1,2 +1,2 @@
pub mod function_call;
pub mod arguments_list; pub mod arguments_list;
pub mod function_call;

View File

@ -4,9 +4,9 @@ mod binding;
mod block; mod block;
mod expression; mod expression;
mod function_declaration; mod function_declaration;
mod functions;
mod params_list; mod params_list;
mod utils; mod utils;
mod functions;
pub mod ast; pub mod ast;
@ -33,7 +33,7 @@ pub enum ParseResult<A, B> {
/// The parsing was a success /// The parsing was a success
Ok(A, usize), Ok(A, usize),
/// The parsing failed past a point of no return. /// The parsing failed past a point of no return.
/// ///
/// For example, when parsing a function declaration /// For example, when parsing a function declaration
/// the `fun` token is found, but then no identifier /// the `fun` token is found, but then no identifier
Err(SyntaxError), Err(SyntaxError),