refactor: impl parseable for function declaration
This commit is contained in:
parent
778a1390a0
commit
8d5fcd1ce3
@ -11,6 +11,7 @@ mod unary;
|
|||||||
|
|
||||||
/// Expression is defined in the grammar.
|
/// Expression is defined in the grammar.
|
||||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
|
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
|
||||||
|
// TODO: This must be newline/indentation aware
|
||||||
equality::try_parse(tokens, pos)
|
equality::try_parse(tokens, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,2 @@
|
|||||||
pub mod arguments_list;
|
pub mod arguments_list;
|
||||||
|
|
||||||
pub mod function_declaration;
|
|
||||||
pub mod params_list;
|
pub mod params_list;
|
||||||
|
@ -35,8 +35,7 @@ impl<'a> Parseable<'a> for VariableBinding<'a> {
|
|||||||
/*
|
/*
|
||||||
* datatype
|
* datatype
|
||||||
*/
|
*/
|
||||||
let (datatype, next_pos) = match parse_token_type(tokens, next_pos, TokenType::Datatype)
|
let (datatype, next_pos) = match parse_token_type(tokens, next_pos, TokenType::Datatype) {
|
||||||
{
|
|
||||||
Ok((t, next)) => (Some(t), next),
|
Ok((t, next)) => (Some(t), next),
|
||||||
_ => (None, next_pos),
|
_ => (None, next_pos),
|
||||||
};
|
};
|
||||||
@ -50,45 +49,45 @@ impl<'a> Parseable<'a> for VariableBinding<'a> {
|
|||||||
/*
|
/*
|
||||||
* identifier
|
* identifier
|
||||||
*/
|
*/
|
||||||
let (identifier, next_pos) =
|
let (identifier, next_pos) = match parse_token_type(tokens, next_pos, TokenType::Identifier)
|
||||||
match parse_token_type(tokens, next_pos, TokenType::Identifier) {
|
{
|
||||||
Ok((t, n)) => (t, n),
|
Ok((t, n)) => (t, n),
|
||||||
Err(ParsingError::Mismatch(token)) => {
|
Err(ParsingError::Mismatch(token)) => {
|
||||||
// The parser found a token, but it's not an identifier
|
// The parser found a token, but it's not an identifier
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
error_start: token.position,
|
error_start: token.position,
|
||||||
error_end: token.get_end_position(),
|
error_end: token.get_end_position(),
|
||||||
reason: "There should be an identifier after a binding".into(),
|
reason: "There should be an identifier after a binding".into(),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// The parser didn't find an Identifier after VAL/VAR or the Datatype
|
// The parser didn't find an Identifier after VAL/VAR or the Datatype
|
||||||
match (binding_token, datatype) {
|
match (binding_token, datatype) {
|
||||||
(Some(binding_token), None) => {
|
(Some(binding_token), None) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: format!(
|
reason: format!(
|
||||||
"There should be an identifier after a `{}` token",
|
"There should be an identifier after a `{}` token",
|
||||||
if is_var { "var" } else { "val" }
|
if is_var { "var" } else { "val" }
|
||||||
),
|
),
|
||||||
error_start: binding_token.position,
|
error_start: binding_token.position,
|
||||||
error_end: binding_token.get_end_position(),
|
error_end: binding_token.get_end_position(),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
(_, Some(datatype_token)) => {
|
(_, Some(datatype_token)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: "There should be an identifier after the datatype".into(),
|
reason: "There should be an identifier after the datatype".into(),
|
||||||
error_start: datatype_token.position,
|
error_start: datatype_token.position,
|
||||||
error_end: datatype_token.get_end_position(),
|
error_end: datatype_token.get_end_position(),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!(
|
unreachable!(
|
||||||
"Illegal parser state: binding_token and datatype are both None"
|
"Illegal parser state: binding_token and datatype are both None"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Equal (=) operator
|
* Equal (=) operator
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
lexic::token::Token,
|
lexic::token::Token,
|
||||||
syntax::{
|
syntax::{
|
||||||
ast::Expression, expression, parseable::{Parseable, ParsingResult}
|
ast::Expression,
|
||||||
|
expression,
|
||||||
|
parseable::{Parseable, ParsingResult},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,134 +1,139 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::SyntaxError,
|
error_handling::SyntaxError,
|
||||||
lexic::token::{Token, TokenType},
|
lexic::token::{Token, TokenType},
|
||||||
syntax::{utils::try_operator, ParsingError, ParsingResult},
|
syntax::{
|
||||||
|
ast::FunctionDeclaration,
|
||||||
|
block::parse_block,
|
||||||
|
functions::params_list::parse_params_list,
|
||||||
|
parseable::{Parseable, ParsingError, ParsingResult},
|
||||||
|
utils::{parse_token_type, try_operator},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
impl<'a> Parseable<'a> for FunctionDeclaration<'a> {
|
||||||
super::{ast::FunctionDeclaration, block::parse_block, utils::parse_token_type},
|
type Item = FunctionDeclaration<'a>;
|
||||||
params_list::parse_params_list,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
fn try_parse(tokens: &'a Vec<Token>, current_pos: usize) -> ParsingResult<'a, Self::Item> {
|
||||||
function declaration = "fun", identifier, params list, return type?, block;
|
let mut current_pos = current_pos;
|
||||||
|
|
||||||
return type = "->", datatype;
|
// `fun` keyword
|
||||||
*/
|
let (fun_keyword, next_pos) = match parse_token_type(tokens, current_pos, TokenType::FUN) {
|
||||||
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<FunctionDeclaration> {
|
Ok((t, next)) => (t, next),
|
||||||
let mut current_pos = pos;
|
_ => return Err(ParsingError::Unmatched),
|
||||||
|
|
||||||
// `fun` keyword
|
|
||||||
let (fun_keyword, next_pos) = match parse_token_type(tokens, current_pos, TokenType::FUN) {
|
|
||||||
Ok((t, next)) => (t, next),
|
|
||||||
_ => return Err(ParsingError::Unmatched),
|
|
||||||
};
|
|
||||||
current_pos = next_pos;
|
|
||||||
|
|
||||||
// identifier
|
|
||||||
let (identifier, next_pos) = match parse_token_type(tokens, current_pos, TokenType::Identifier)
|
|
||||||
{
|
|
||||||
Ok((id, next)) => (id, next),
|
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
|
||||||
Err(ParsingError::Mismatch(wrong_token)) => {
|
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
|
||||||
reason: String::from("Expected an identifier after the `fun` keyword."),
|
|
||||||
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 identifier after the `fun` keyword."),
|
|
||||||
error_start: fun_keyword.position,
|
|
||||||
error_end: fun_keyword.get_end_position(),
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
current_pos = next_pos;
|
|
||||||
|
|
||||||
// Params list
|
|
||||||
let (params_list, next_pos) = match parse_params_list(tokens, current_pos) {
|
|
||||||
Ok((params, next_pos)) => (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 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 after the function identifier."),
|
|
||||||
error_start: identifier.position,
|
|
||||||
error_end: identifier.get_end_position(),
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
current_pos = next_pos;
|
|
||||||
|
|
||||||
// Try to parse a return type
|
|
||||||
let (return_type, next_pos) = 'return_label: {
|
|
||||||
let (arrow_op, next_pos) = match try_operator(tokens, current_pos, "->".into()) {
|
|
||||||
Ok((op, next)) => (op, next),
|
|
||||||
_ => break 'return_label (None, current_pos),
|
|
||||||
};
|
};
|
||||||
|
current_pos = next_pos;
|
||||||
|
|
||||||
// At this point the '->' operator was matched, so we expect a datatype
|
// identifier
|
||||||
match parse_token_type(tokens, next_pos, TokenType::Datatype) {
|
let (identifier, next_pos) =
|
||||||
Ok((t, next)) => (Some(t), next),
|
match parse_token_type(tokens, current_pos, TokenType::Identifier) {
|
||||||
|
Ok((id, next)) => (id, next),
|
||||||
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
|
Err(ParsingError::Mismatch(wrong_token)) => {
|
||||||
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
|
reason: String::from("Expected an identifier after the `fun` keyword."),
|
||||||
|
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 identifier after the `fun` keyword."),
|
||||||
|
error_start: fun_keyword.position,
|
||||||
|
error_end: fun_keyword.get_end_position(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
current_pos = next_pos;
|
||||||
|
|
||||||
|
// Params list
|
||||||
|
// TODO: impl Parseable
|
||||||
|
let (params_list, next_pos) = match parse_params_list(tokens, current_pos) {
|
||||||
|
Ok((params, next_pos)) => (params, next_pos),
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
Err(ParsingError::Mismatch(wrong_token)) => {
|
Err(ParsingError::Mismatch(wrong_token)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: String::from("Expected a datatype after the arrow operator."),
|
reason: String::from(
|
||||||
|
"Expected an opening paren after the function identifier.",
|
||||||
|
),
|
||||||
error_start: wrong_token.position,
|
error_start: wrong_token.position,
|
||||||
error_end: wrong_token.get_end_position(),
|
error_end: wrong_token.get_end_position(),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
reason: String::from("Expected a datatype after the arrow operator."),
|
reason: String::from(
|
||||||
error_start: arrow_op.position,
|
"Expected an opening paren after the function identifier.",
|
||||||
error_end: arrow_op.get_end_position(),
|
),
|
||||||
|
error_start: identifier.position,
|
||||||
|
error_end: identifier.get_end_position(),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
current_pos = next_pos;
|
||||||
current_pos = next_pos;
|
|
||||||
|
|
||||||
// Function body (block)
|
// Try to parse a return type
|
||||||
let (block, next_pos) = match parse_block(tokens, current_pos) {
|
let (return_type, next_pos) = 'return_label: {
|
||||||
Ok((block, next_pos)) => (block, next_pos),
|
let (arrow_op, next_pos) = match try_operator(tokens, current_pos, "->".into()) {
|
||||||
Err(ParsingError::Err(error)) => {
|
Ok((op, next)) => (op, next),
|
||||||
return Err(ParsingError::Err(error));
|
_ => break 'return_label (None, current_pos),
|
||||||
}
|
};
|
||||||
Err(ParsingError::Mismatch(wrong_token)) => {
|
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
|
||||||
reason: String::from("Expected a block after the function declaration."),
|
|
||||||
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 block after the function declaration."),
|
|
||||||
error_start: identifier.position,
|
|
||||||
error_end: identifier.get_end_position(),
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
current_pos = next_pos;
|
|
||||||
|
|
||||||
// Construct and return the function declaration
|
// At this point the '->' operator was matched, so we expect a datatype
|
||||||
Ok((
|
match parse_token_type(tokens, next_pos, TokenType::Datatype) {
|
||||||
FunctionDeclaration {
|
Ok((t, next)) => (Some(t), next),
|
||||||
identifier: &identifier,
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
return_type,
|
Err(ParsingError::Mismatch(wrong_token)) => {
|
||||||
params_list: Box::new(params_list),
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
block: Box::new(block),
|
reason: String::from("Expected a datatype after the arrow operator."),
|
||||||
},
|
error_start: wrong_token.position,
|
||||||
current_pos,
|
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)) => {
|
||||||
|
return Err(ParsingError::Err(error));
|
||||||
|
}
|
||||||
|
Err(ParsingError::Mismatch(wrong_token)) => {
|
||||||
|
return Err(ParsingError::Err(SyntaxError {
|
||||||
|
reason: String::from("Expected a block after the function declaration."),
|
||||||
|
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 block after the function declaration."),
|
||||||
|
error_start: identifier.position,
|
||||||
|
error_end: identifier.get_end_position(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
current_pos = next_pos;
|
||||||
|
|
||||||
|
// Construct and return the function declaration
|
||||||
|
Ok((
|
||||||
|
FunctionDeclaration {
|
||||||
|
identifier: &identifier,
|
||||||
|
return_type,
|
||||||
|
params_list: Box::new(params_list),
|
||||||
|
block: Box::new(block),
|
||||||
|
},
|
||||||
|
current_pos,
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -140,7 +145,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_return_none_on_wrong_initial_token() {
|
fn should_return_none_on_wrong_initial_token() {
|
||||||
let tokens = get_tokens(&String::from("val identifier = 20")).unwrap();
|
let tokens = get_tokens(&String::from("val identifier = 20")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
let Err(ParsingError::Unmatched) = fun_decl else {
|
let Err(ParsingError::Unmatched) = fun_decl else {
|
||||||
panic!("Expected an unmatched result: {:?}", fun_decl);
|
panic!("Expected an unmatched result: {:?}", fun_decl);
|
||||||
@ -150,7 +155,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_not_parse_fun_without_identifier() {
|
fn should_not_parse_fun_without_identifier() {
|
||||||
let tokens = get_tokens(&String::from("fun = 20")).unwrap();
|
let tokens = get_tokens(&String::from("fun = 20")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
@ -165,7 +170,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let tokens = get_tokens(&String::from("fun")).unwrap();
|
let tokens = get_tokens(&String::from("fun")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -182,7 +187,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_not_parse_fun_without_parens() {
|
fn should_not_parse_fun_without_parens() {
|
||||||
let tokens = get_tokens(&String::from("fun id =")).unwrap();
|
let tokens = get_tokens(&String::from("fun id =")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
@ -197,7 +202,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let tokens = get_tokens(&String::from("fun id")).unwrap();
|
let tokens = get_tokens(&String::from("fun id")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -214,7 +219,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_not_parse_fun_without_closing_paren() {
|
fn should_not_parse_fun_without_closing_paren() {
|
||||||
let tokens = get_tokens(&String::from("fun id(=")).unwrap();
|
let tokens = get_tokens(&String::from("fun id(=")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
@ -229,7 +234,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let tokens = get_tokens(&String::from("fun id(")).unwrap();
|
let tokens = get_tokens(&String::from("fun id(")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -246,7 +251,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_not_parse_fun_when_missing_id() {
|
fn should_not_parse_fun_when_missing_id() {
|
||||||
let tokens = get_tokens(&String::from("fun")).unwrap();
|
let tokens = get_tokens(&String::from("fun")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
@ -262,7 +267,7 @@ mod tests {
|
|||||||
|
|
||||||
let tokens = get_tokens(&String::from("fun\n")).unwrap();
|
let tokens = get_tokens(&String::from("fun\n")).unwrap();
|
||||||
println!("{:?}", tokens);
|
println!("{:?}", tokens);
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
@ -280,7 +285,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_not_parse_fun_without_opening_brace() {
|
fn should_not_parse_fun_without_opening_brace() {
|
||||||
let tokens = get_tokens(&String::from("fun id() =")).unwrap();
|
let tokens = get_tokens(&String::from("fun id() =")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
@ -295,7 +300,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let tokens = get_tokens(&String::from("fun id()")).unwrap();
|
let tokens = get_tokens(&String::from("fun id()")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -312,7 +317,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_not_parse_fun_without_closing_brace() {
|
fn should_not_parse_fun_without_closing_brace() {
|
||||||
let tokens = get_tokens(&String::from("fun id() { 20")).unwrap();
|
let tokens = get_tokens(&String::from("fun id() { 20")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
@ -324,7 +329,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let tokens = get_tokens(&String::from("fun id() {")).unwrap();
|
let tokens = get_tokens(&String::from("fun id() {")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
@ -339,7 +344,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_parse_simple_function_declaration() {
|
fn should_parse_simple_function_declaration() {
|
||||||
let tokens = get_tokens(&String::from("fun id() {}")).unwrap();
|
let tokens = get_tokens(&String::from("fun id() {}")).unwrap();
|
||||||
let (function_declaration, _) = try_parse(&tokens, 0).unwrap();
|
let (function_declaration, _) = FunctionDeclaration::try_parse(&tokens, 0).unwrap();
|
||||||
|
|
||||||
assert_eq!(function_declaration.identifier.value, String::from("id"));
|
assert_eq!(function_declaration.identifier.value, String::from("id"));
|
||||||
assert_eq!(function_declaration.return_type, None);
|
assert_eq!(function_declaration.return_type, None);
|
||||||
@ -348,7 +353,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_parse_return_type() {
|
fn should_parse_return_type() {
|
||||||
let tokens = get_tokens(&String::from("fun id() -> String {}")).unwrap();
|
let tokens = get_tokens(&String::from("fun id() -> String {}")).unwrap();
|
||||||
let (function_declaration, _) = try_parse(&tokens, 0).unwrap();
|
let (function_declaration, _) = FunctionDeclaration::try_parse(&tokens, 0).unwrap();
|
||||||
|
|
||||||
assert_eq!(function_declaration.identifier.value, String::from("id"));
|
assert_eq!(function_declaration.identifier.value, String::from("id"));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -360,7 +365,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_throw_error_on_return_type_1() {
|
fn should_throw_error_on_return_type_1() {
|
||||||
let tokens = get_tokens(&String::from("fun id() -> {}")).unwrap();
|
let tokens = get_tokens(&String::from("fun id() -> {}")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
@ -375,7 +380,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_throw_error_on_return_type_2() {
|
fn should_throw_error_on_return_type_2() {
|
||||||
let tokens = get_tokens(&String::from("fun id() -> ")).unwrap();
|
let tokens = get_tokens(&String::from("fun id() -> ")).unwrap();
|
||||||
let fun_decl = try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
@ -397,7 +402,7 @@ mod whitespace_test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_ignore_whitespace_1() {
|
fn should_ignore_whitespace_1() {
|
||||||
let tokens = get_tokens(&String::from("fun\nid() {}")).unwrap();
|
let tokens = get_tokens(&String::from("fun\nid() {}")).unwrap();
|
||||||
let (declaration, _) = try_parse(&tokens, 0).unwrap();
|
let (declaration, _) = FunctionDeclaration::try_parse(&tokens, 0).unwrap();
|
||||||
|
|
||||||
assert_eq!(declaration.identifier.value, (String::from("id")));
|
assert_eq!(declaration.identifier.value, (String::from("id")));
|
||||||
}
|
}
|
||||||
@ -405,7 +410,7 @@ mod whitespace_test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_ignore_whitespace_2() {
|
fn should_ignore_whitespace_2() {
|
||||||
let tokens = get_tokens(&String::from("fun\nid\n() {}")).unwrap();
|
let tokens = get_tokens(&String::from("fun\nid\n() {}")).unwrap();
|
||||||
let (declaration, _) = try_parse(&tokens, 0).unwrap();
|
let (declaration, _) = FunctionDeclaration::try_parse(&tokens, 0).unwrap();
|
||||||
|
|
||||||
assert_eq!(declaration.identifier.value, (String::from("id")));
|
assert_eq!(declaration.identifier.value, (String::from("id")));
|
||||||
}
|
}
|
||||||
@ -413,7 +418,7 @@ mod whitespace_test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_ignore_whitespace_3() {
|
fn should_ignore_whitespace_3() {
|
||||||
let tokens = get_tokens(&String::from("fun\nid\n(\n) {}")).unwrap();
|
let tokens = get_tokens(&String::from("fun\nid\n(\n) {}")).unwrap();
|
||||||
let (declaration, _) = try_parse(&tokens, 0).unwrap();
|
let (declaration, _) = FunctionDeclaration::try_parse(&tokens, 0).unwrap();
|
||||||
|
|
||||||
assert_eq!(declaration.identifier.value, (String::from("id")));
|
assert_eq!(declaration.identifier.value, (String::from("id")));
|
||||||
}
|
}
|
||||||
@ -421,14 +426,14 @@ mod whitespace_test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_ignore_whitespace_4() {
|
fn should_ignore_whitespace_4() {
|
||||||
let tokens = get_tokens(&String::from("fun id\n(\n)\n{}")).unwrap();
|
let tokens = get_tokens(&String::from("fun id\n(\n)\n{}")).unwrap();
|
||||||
let (declaration, _) = try_parse(&tokens, 0).unwrap();
|
let (declaration, _) = FunctionDeclaration::try_parse(&tokens, 0).unwrap();
|
||||||
assert_eq!(declaration.identifier.value, (String::from("id")));
|
assert_eq!(declaration.identifier.value, (String::from("id")));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_ignore_whitespace_5() {
|
fn should_ignore_whitespace_5() {
|
||||||
let tokens = get_tokens(&String::from("fun\nid() \n{\n}")).unwrap();
|
let tokens = get_tokens(&String::from("fun\nid() \n{\n}")).unwrap();
|
||||||
let (declaration, _) = try_parse(&tokens, 0).unwrap();
|
let (declaration, _) = FunctionDeclaration::try_parse(&tokens, 0).unwrap();
|
||||||
assert_eq!(declaration.identifier.value, (String::from("id")));
|
assert_eq!(declaration.identifier.value, (String::from("id")));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
pub mod binding;
|
pub mod binding;
|
||||||
pub mod expression;
|
pub mod expression;
|
||||||
|
pub mod function_declaration;
|
||||||
pub mod module;
|
pub mod module;
|
||||||
pub mod statement;
|
pub mod statement;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use crate::syntax::{
|
use crate::syntax::{
|
||||||
ast::{var_binding::VariableBinding, Statement},
|
ast::{var_binding::VariableBinding, FunctionDeclaration, Statement},
|
||||||
functions::function_declaration,
|
|
||||||
parseable::{Parseable, ParsingError},
|
parseable::{Parseable, ParsingError},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -24,8 +23,7 @@ impl<'a> Parseable<'a> for Statement<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try to parse a function declaration
|
// Try to parse a function declaration
|
||||||
// TODO: Rewrite function_declaration to use Parseable
|
match FunctionDeclaration::try_parse(tokens, current_pos) {
|
||||||
match function_declaration::try_parse(tokens, current_pos) {
|
|
||||||
Ok((prod, next)) => {
|
Ok((prod, next)) => {
|
||||||
return Ok((Statement::FnDecl(prod), next));
|
return Ok((Statement::FnDecl(prod), next));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user