diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs index d58b079..2ea3db8 100644 --- a/src/syntax/ast.rs +++ b/src/syntax/ast.rs @@ -13,6 +13,9 @@ pub struct FunctionDeclaration { pub identifier: Box, } +#[derive(Debug)] +pub struct Block {} + #[derive(Debug)] pub enum Binding { Val(ValBinding), diff --git a/src/syntax/block.rs b/src/syntax/block.rs new file mode 100644 index 0000000..65c2909 --- /dev/null +++ b/src/syntax/block.rs @@ -0,0 +1,36 @@ +use crate::{ + lexic::token::{Token, TokenType}, + syntax::{utils::expect_token_w, SyntaxResult}, +}; + +use super::{ast::Block, utils::parse_token_type, ParseResult}; + +// Assumes that the token at `pos` is a { +pub fn parse_block<'a>(tokens: &'a Vec, pos: usize) -> ParseResult { + let mut current_pos = pos; + + let (opening_brace, next_pos) = + match parse_token_type(tokens, current_pos, TokenType::LeftBrace) { + 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 brace + let (_closing_brace, next_pos) = match expect_token_w( + tokens, + current_pos, + TokenType::RightBrace, + "Expected a closing brace after the block body.".into(), + opening_brace, + ) { + Ok(t) => t, + Err(Some(SyntaxResult::Err(err))) => return ParseResult::Err(err), + _ => panic!("parse_block: invalid state"), + }; + current_pos = next_pos; + + ParseResult::Ok(Block {}, current_pos) +} diff --git a/src/syntax/function_declaration.rs b/src/syntax/function_declaration.rs index f44451b..8fd877a 100644 --- a/src/syntax/function_declaration.rs +++ b/src/syntax/function_declaration.rs @@ -1,12 +1,14 @@ use crate::{ + error_handling::SyntaxError, lexic::token::{Token, TokenType}, utils::Result3, }; use super::{ ast::{FunctionDeclaration, TopLevelDeclaration}, + block::parse_block, utils::{expect_token_w, try_token_type}, - SyntaxResult, + ParseResult, SyntaxResult, }; pub fn try_parse<'a>(tokens: &'a Vec, pos: usize) -> Option { @@ -57,7 +59,6 @@ pub fn try_parse<'a>(tokens: &'a Vec, pos: usize) -> Option }; current_pos = next_pos; - // Parse a closing paren let (closing_paren, next_pos) = match expect_token_w( tokens, @@ -71,34 +72,28 @@ pub fn try_parse<'a>(tokens: &'a Vec, pos: usize) -> Option }; current_pos = next_pos; - // TODO: Replace by block parsing - // Parse opening brace - let (opening_brace, next_pos) = match expect_token_w( - tokens, - current_pos, - TokenType::LeftBrace, - "Expected an opening brace afted the parameter list.".into(), - closing_paren, - ) { - Ok(t) => t, - Err(err) => return err, + let (_block, next_pos) = match parse_block(tokens, current_pos) { + ParseResult::Ok(block, next_pos) => (block, next_pos), + ParseResult::Err(error) => { + return Some(SyntaxResult::Err(error)); + } + ParseResult::Mismatch(wrong_token) => { + return Some(SyntaxResult::Err(SyntaxError { + reason: String::from("Expected a block after the function declaration."), + error_start: wrong_token.position, + error_end: wrong_token.get_end_position(), + })); + } + ParseResult::Unmatched => { + return Some(SyntaxResult::Err(SyntaxError { + reason: String::from("Expected a block after the function declaration."), + error_start: closing_paren.position, + error_end: closing_paren.get_end_position(), + })); + } }; current_pos = next_pos; - // Parse closing brace - let (_closing_brace, next_pos) = match expect_token_w( - tokens, - current_pos, - TokenType::RightBrace, - "Expected a closing brace after afted the function body.".into(), - opening_brace, - ) { - Ok(t) => t, - Err(err) => return err, - }; - current_pos = next_pos; - - // Construct and return the function declaration Some(SyntaxResult::Ok( TopLevelDeclaration::FunctionDeclaration(FunctionDeclaration { @@ -261,7 +256,7 @@ mod tests { Some(SyntaxResult::Err(err)) => { assert_eq!( err.reason, - "Expected an opening brace afted the parameter list." + "Expected a block after the function declaration." ); assert_eq!(err.error_start, 9); assert_eq!(err.error_end, 10); @@ -275,7 +270,7 @@ mod tests { Some(SyntaxResult::Err(err)) => { assert_eq!( err.reason, - "Expected an opening brace afted the parameter list." + "Expected a block after the function declaration." ); assert_eq!(err.error_start, 7); assert_eq!(err.error_end, 8); @@ -291,10 +286,7 @@ mod tests { match fun_decl { Some(SyntaxResult::Err(err)) => { - assert_eq!( - err.reason, - "Expected a closing brace after afted the function body." - ); + assert_eq!(err.reason, "Expected a closing brace after the block body."); assert_eq!(err.error_start, 11); assert_eq!(err.error_end, 13); } @@ -306,10 +298,7 @@ mod tests { match fun_decl { Some(SyntaxResult::Err(err)) => { - assert_eq!( - err.reason, - "Expected a closing brace after afted the function body." - ); + assert_eq!(err.reason, "Expected a closing brace after the block body."); assert_eq!(err.error_start, 9); assert_eq!(err.error_end, 10); } diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index 1d9c28d..83f293a 100755 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -1,6 +1,7 @@ use crate::error_handling::{MistiError, SyntaxError}; mod binding; +mod block; mod expression; mod function_declaration; mod utils; @@ -25,6 +26,14 @@ pub enum SyntaxResult { Err(SyntaxError), } +#[derive(Debug)] +pub enum ParseResult { + Ok(A, usize), + Err(SyntaxError), + Mismatch(B), + Unmatched, +} + /// Constructs the Misti AST from a vector of tokens pub fn construct_ast<'a>(tokens: &'a Vec) -> Result { let mut top_level_declarations = Vec::new(); diff --git a/src/syntax/utils.rs b/src/syntax/utils.rs index 87d22bb..21e5f4f 100644 --- a/src/syntax/utils.rs +++ b/src/syntax/utils.rs @@ -4,7 +4,7 @@ use crate::{ utils::Result3, }; -use super::SyntaxResult; +use super::{ParseResult, SyntaxResult}; /// Expects the token at `pos` to be of type `token_type` pub fn try_token_type(tokens: &Vec, pos: usize, token_type: TokenType) -> Result3<&Token> { @@ -18,6 +18,36 @@ pub fn try_token_type(tokens: &Vec, pos: usize, token_type: TokenType) -> } } +/// Expects the token at `pos` to be of type `token_type` +pub fn parse_token_type( + tokens: &Vec, + pos: usize, + token_type: TokenType, +) -> ParseResult<&Token, &Token> { + let mut current_pos = pos; + + // Ignore all whitespace and newlines + while let Some(t) = tokens.get(current_pos) { + if t.token_type == TokenType::INDENT + || t.token_type == TokenType::DEDENT + || t.token_type == TokenType::NewLine + { + current_pos += 1; + } else { + break; + } + } + + match tokens.get(current_pos) { + Some(t) if t.token_type == token_type => ParseResult::Ok(t, current_pos + 1), + Some(t) if t.token_type == TokenType::EOF || t.token_type == TokenType::NewLine => { + ParseResult::Unmatched + } + Some(t) => ParseResult::Mismatch(t), + None => ParseResult::Unmatched, + } +} + pub fn try_operator(tokens: &Vec, pos: usize, operator: String) -> Result3<&Token> { match tokens.get(pos) { Some(t) if t.token_type == TokenType::Operator && t.value == operator => Result3::Ok(t), @@ -29,7 +59,7 @@ pub fn try_operator(tokens: &Vec, pos: usize, operator: String) -> Result } } -pub fn try_operator_w<'a>( +pub fn _try_operator_w<'a>( tokens: &'a Vec, pos: usize, operator: String,