From 2d32f1a0bcbc001fc3c77a0e766710555381da10 Mon Sep 17 00:00:00 2001 From: Araozu Date: Mon, 18 Mar 2024 09:51:17 -0500 Subject: [PATCH] Parse val/var binding & implicit val binding --- CHANGELOG.md | 8 +- src/syntax/binding.rs | 148 +++++++++++++------ src/syntax/functions/function_declaration.rs | 7 +- src/syntax/grammar.md | 8 +- src/syntax/utils.rs | 2 - 5 files changed, 121 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11c1bec..61b4383 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,13 +32,13 @@ ## v0.0.11 -- [ ] Parse binding of form `val Type variable = value` -- [ ] Parse binding of form `Type variable = value` +- [x] Parse binding of form `val Type variable = value` +- [x] Parse binding of form `Type variable = value` - [ ] Infer datatype of `value` in the above for a simple expression - [ ] Ensure that the anotated datatype matches the datatype of `value` in the above - [ ] Infer datatype of a `val variable = value` in the AST: Use the infered datatype -- [ ] Formally define the top level constructs -- [ ] Parse bindings and function declarations as top level constructs +- [x] Formally define the top level constructs +- [x] Parse bindings and function declarations as top level constructs - [ ] Parse function declaration arguments (`Type id`) - [x] Parse function return datatype (`fun f() -> Type`) - [x] Return parsing to variables to var/val diff --git a/src/syntax/binding.rs b/src/syntax/binding.rs index efd2a84..2b0269f 100644 --- a/src/syntax/binding.rs +++ b/src/syntax/binding.rs @@ -4,29 +4,51 @@ use super::{expression, ParsingError, ParsingResult}; use crate::error_handling::SyntaxError; use crate::lexic::token::{Token, TokenType}; +/* +binding = val binding | var binding +val binding = "val", datatype?, binding remainder + | datatype, binding remainder + +var binding = "var", datatype?, binding remainder + +binding remainder = identifier, "=", expression + */ pub fn try_parse<'a>(tokens: &'a Vec, pos: usize) -> ParsingResult { let mut current_pos = pos; - // TODO: Detect if the binding starts with a datatype - // TODO: Revert to val/var - /* - * let keyword + * val/var keyword */ - let (is_mutable, binding_token, next_pos) = { - match parse_token_type(tokens, current_pos, TokenType::VAL) { - Ok((val_token, next_pos)) => (false, val_token, next_pos), - _ => { - // If VAL is not found, search for VAR - match parse_token_type(tokens, current_pos, TokenType::VAR) { - Ok((var_token, next_pos)) => (true, var_token, next_pos), - _ => return Err(ParsingError::Unmatched), - } - } + let (is_var, binding_token, next_pos) = 'token: { + // check for VAL + if let Ok((val_token, next_pos)) = parse_token_type(tokens, current_pos, TokenType::VAL) { + break 'token (false, Some(val_token), next_pos); + }; + + // check for VAR + match parse_token_type(tokens, current_pos, TokenType::VAR) { + Ok((var_token, next_pos)) => (true, Some(var_token), next_pos), + // If a VAR is not found it is still possible that the binding is an implicit VAL + _ => (false, None, current_pos), } }; current_pos = next_pos; + /* + * datatype + */ + let (datatype, next_pos) = match parse_token_type(tokens, current_pos, TokenType::Datatype) { + Ok((t, next)) => (Some(t), next), + _ => (None, current_pos), + }; + current_pos = next_pos; + + // Here: + // If the binding is None and the datatype is None, then we didn't match a binding + if binding_token.is_none() && datatype.is_none() { + return Err(ParsingError::Unmatched); + } + /* * identifier */ @@ -45,15 +67,29 @@ pub fn try_parse<'a>(tokens: &'a Vec, pos: usize) -> ParsingResult { - // The parser didn't find an Identifier after VAL/VAR - return Err(ParsingError::Err(SyntaxError { - reason: format!( - "There should be an identifier after a `{}` token", - if is_mutable { "val" } else { "var" } - ), - error_start: binding_token.position, - error_end: binding_token.get_end_position(), - })); + // The parser didn't find an Identifier after VAL/VAR or the Datatype + match (binding_token, datatype) { + (Some(binding_token), _) => { + return Err(ParsingError::Err(SyntaxError { + reason: format!( + "There should be an identifier after a `{}` token", + if is_var { "val" } else { "var" } + ), + error_start: binding_token.position, + error_end: binding_token.get_end_position(), + })); + } + (None, Some(datatype_token)) => { + return Err(ParsingError::Err(SyntaxError { + reason: "There should be an identifier after the datatype".into(), + error_start: datatype_token.position, + error_end: datatype_token.get_end_position(), + })); + } + _ => { + panic!("Illegal parser state: binding_token and datatype are both None") + } + }; } }; current_pos = next_pos; @@ -82,6 +118,9 @@ pub fn try_parse<'a>(tokens: &'a Vec, pos: usize) -> ParsingResult (exp, next), _ => { @@ -95,10 +134,10 @@ pub fn try_parse<'a>(tokens: &'a Vec, pos: usize) -> ParsingResult 20")).unwrap(); + let binding = try_parse(&tokens, 0); + + match binding { + Err(ParsingError::Err(error)) => { + assert_eq!(4, error.error_start); + assert_eq!(6, error.error_end); + } + _ => panic!("Error expected"), + } } - */ #[test] fn should_return_correct_error() { diff --git a/src/syntax/functions/function_declaration.rs b/src/syntax/functions/function_declaration.rs index eb8ca30..d8f098d 100644 --- a/src/syntax/functions/function_declaration.rs +++ b/src/syntax/functions/function_declaration.rs @@ -69,7 +69,6 @@ pub fn try_parse<'a>(tokens: &'a Vec, pos: usize) -> ParsingResult(tokens: &'a Vec, pos: usize) -> ParsingResult