refactor: impl Parseable for Block

master
Araozu 2024-06-04 20:23:50 -05:00
parent 8d5fcd1ce3
commit 6a951434f3
11 changed files with 174 additions and 186 deletions

View File

@ -5,10 +5,13 @@ use super::Transpilable;
impl Transpilable for Block<'_> {
fn transpile(&self) -> String {
// TODO: Handle indentation
self.statements
todo!("transpilation for block");
/*
self.members
.iter()
.map(|x| x.transpile())
.collect::<Vec<_>>()
.join("\n")
*/
}
}

View File

@ -23,6 +23,7 @@ mod tests {
},
};
/* TODO: reimplement
#[test]
fn should_transpile() {
let tokens = get_tokens(&String::from("fun id() {}")).unwrap();
@ -38,5 +39,5 @@ mod tests {
}
_ => panic!("Expected a function declaration"),
}
}
}*/
}

View File

@ -4,7 +4,7 @@ use crate::{
impls::SemanticCheck,
symbol_table::{SymbolEntry, SymbolTable},
},
syntax::ast::{FunctionDeclaration, Statement},
syntax::ast::{BlockMember, FunctionDeclaration, Statement},
};
impl SemanticCheck for FunctionDeclaration<'_> {
@ -33,16 +33,17 @@ impl SemanticCheck for FunctionDeclaration<'_> {
// TODO: Check the return type of the function body
// This should be the last expression in the block
for stmt in self.block.statements.iter() {
for stmt in self.block.members.iter() {
match stmt {
Statement::Binding(b) => {
BlockMember::Stmt(Statement::Binding(b)) => {
if let Err(err) = b.check_semantics(&function_scope) {
return Err(err);
}
}
Statement::FnDecl(_) => {
BlockMember::Stmt(Statement::FnDecl(_)) => {
todo!("Function declaration: semantic check not implemented")
}
_ => todo!("Expression: semantic check not implemented"),
}
}

View File

@ -37,8 +37,14 @@ pub struct FunctionDeclaration<'a> {
#[derive(Debug)]
pub struct Block<'a> {
// TODO: this should be a Vec of Statement|Expression
pub statements: Vec<Statement<'a>>,
pub members: Vec<BlockMember<'a>>,
}
/// Enum for productions available at the block level
#[derive(Debug)]
pub enum BlockMember<'a> {
Stmt(Statement<'a>),
Expr(Expression<'a>),
}
#[derive(Debug)]

View File

@ -1,118 +0,0 @@
use crate::{
error_handling::SyntaxError,
lexic::token::{Token, TokenType},
};
use super::{ast::Block, utils::parse_token_type, ParsingError, ParsingResult};
// Assumes that the token at `pos` is a {
pub fn parse_block<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Block> {
let mut current_pos = pos;
let (opening_brace, next_pos) = parse_token_type(tokens, current_pos, TokenType::LeftBrace)?;
current_pos = next_pos;
// Parse block statements
let mut statements = Vec::new();
// First statement
match super::statement::try_parse(tokens, current_pos) {
Ok((statement, next_pos)) => {
current_pos = next_pos;
statements.push(statement);
}
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
_ => {}
}
// More statements separated by new lines
while let Some(t) = tokens.get(current_pos) {
if t.token_type != TokenType::NewLine {
break;
}
current_pos += 1;
match super::statement::try_parse(tokens, current_pos) {
Ok((statement, next_pos)) => {
current_pos = next_pos;
statements.push(statement);
}
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
_ => break,
}
}
// Parse closing brace
let (_closing_brace, next_pos) =
match parse_token_type(tokens, current_pos, TokenType::RightBrace) {
Ok((t, next)) => (t, next),
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
Err(ParsingError::Mismatch(t)) => {
return Err(ParsingError::Err(SyntaxError {
reason: String::from("Expected a closing brace after the block body."),
error_start: t.position,
error_end: t.get_end_position(),
}));
}
Err(ParsingError::Unmatched) => {
return Err(ParsingError::Err(SyntaxError {
reason: String::from("Expected a closing brace after the block body."),
error_start: opening_brace.position,
error_end: opening_brace.get_end_position(),
}));
}
};
current_pos = next_pos;
Ok((Block { statements }, current_pos))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::lexic::get_tokens;
// TODO: rewrite, refactor
/*
#[test]
fn test_parse_block() {
let tokens = get_tokens(&String::from("{f()}")).unwrap();
let block = parse_block(&tokens, 0);
let block = match block {
ParsingResult::Ok((p, _)) => p,
_ => panic!("Expected a block, got: {:?}", block),
};
assert_eq!(block.statements.len(), 1);
}
#[test]
fn test_parse_block_2() {
let tokens = get_tokens(&String::from("{f()\ng()}")).unwrap();
let block = parse_block(&tokens, 0);
let block = match block {
ParsingResult::Ok((p, _)) => p,
_ => panic!("Expected a block, got: {:?}", block),
};
assert_eq!(block.statements.len(), 2);
}
#[test]
fn test_parse_block_3() {
let tokens = get_tokens(&String::from("{\n f()\n}")).unwrap();
let block = parse_block(&tokens, 0);
let block = match block {
ParsingResult::Ok((p, _)) => p,
_ => {
panic!("Expected a block, got: {:?}\n\n{:?}", block, tokens)
}
};
assert_eq!(block.statements.len(), 1);
}
*/
}

View File

@ -1,11 +1,9 @@
use crate::error_handling::MistiError;
mod block;
mod expression;
mod functions;
mod parseable;
mod parsers;
mod statement;
mod utils;
pub mod ast;

147
src/syntax/parsers/block.rs Normal file
View File

@ -0,0 +1,147 @@
use crate::{
error_handling::SyntaxError,
lexic::token::{Token, TokenType},
syntax::{
ast::{Block, BlockMember, Expression, Statement},
parseable::{Parseable, ParsingError, ParsingResult},
utils::parse_token_type,
},
};
impl<'a> Parseable<'a> for Block<'a> {
type Item = Block<'a>;
fn try_parse(tokens: &'a Vec<Token>, current_pos: usize) -> ParsingResult<'a, Self::Item> {
let mut current_pos = current_pos;
let (opening_brace, next_pos) =
parse_token_type(tokens, current_pos, TokenType::LeftBrace)?;
current_pos = next_pos;
// Parse BlockMember = Statement | Expression
let mut members = Vec::<BlockMember>::new();
let tokens_len = tokens.len();
// Minus one because last token is EOF
while current_pos < tokens_len - 1 {
// Attempt to parse an statement
match Statement::try_parse(tokens, current_pos) {
Ok((prod, next_pos)) => {
members.push(BlockMember::Stmt(prod));
current_pos = next_pos;
continue;
}
Err(ParsingError::Err(error)) => {
// TODO: Better error handling, write a better error message
return Err(ParsingError::Err(error));
}
_ => {}
};
// Attempt to parse an expression
match Expression::try_parse(tokens, current_pos) {
Ok((prod, next_pos)) => {
members.push(BlockMember::Expr(prod));
current_pos = next_pos;
}
Err(ParsingError::Err(error)) => {
// TODO: Better error handling, write a better error message
return Err(ParsingError::Err(error));
}
_ => {}
}
// If we reached this point we didn't match any productions
// we get out of the block, the parsing of "}" will deal
// with any incorrect tokens
break;
}
// Parse closing brace
let (_closing_brace, next_pos) =
match parse_token_type(tokens, current_pos, TokenType::RightBrace) {
Ok((t, next)) => (t, next),
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
Err(ParsingError::Mismatch(t)) => {
return Err(ParsingError::Err(SyntaxError {
reason: String::from("Expected a closing brace after the block body."),
error_start: t.position,
error_end: t.get_end_position(),
}));
}
Err(ParsingError::Unmatched) => {
return Err(ParsingError::Err(SyntaxError {
reason: String::from("Expected a closing brace after the block body."),
// TODO: use the last token (at pos current_pos) as guide for the error
// msg position
error_start: opening_brace.position,
error_end: opening_brace.get_end_position(),
}));
}
};
current_pos = next_pos;
let block = Block { members };
Ok((block, current_pos))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::lexic::get_tokens;
#[test]
fn should_parse_empty_block() {
let tokens = get_tokens(&String::from("{}")).unwrap();
let (block, next_pos) = Block::try_parse(&tokens, 0).unwrap();
assert_eq!(2, next_pos);
assert_eq!(0, block.members.len())
}
// TODO: rewrite, refactor
/*
#[test]
fn test_parse_block() {
let tokens = get_tokens(&String::from("{f()}")).unwrap();
let block = parse_block(&tokens, 0);
let block = match block {
ParsingResult::Ok((p, _)) => p,
_ => panic!("Expected a block, got: {:?}", block),
};
assert_eq!(block.statements.len(), 1);
}
#[test]
fn test_parse_block_2() {
let tokens = get_tokens(&String::from("{f()\ng()}")).unwrap();
let block = parse_block(&tokens, 0);
let block = match block {
ParsingResult::Ok((p, _)) => p,
_ => panic!("Expected a block, got: {:?}", block),
};
assert_eq!(block.statements.len(), 2);
}
#[test]
fn test_parse_block_3() {
let tokens = get_tokens(&String::from("{\n f()\n}")).unwrap();
let block = parse_block(&tokens, 0);
let block = match block {
ParsingResult::Ok((p, _)) => p,
_ => {
panic!("Expected a block, got: {:?}\n\n{:?}", block, tokens)
}
};
assert_eq!(block.statements.len(), 1);
}
*/
}

View File

@ -2,8 +2,7 @@ use crate::{
error_handling::SyntaxError,
lexic::token::{Token, TokenType},
syntax::{
ast::FunctionDeclaration,
block::parse_block,
ast::{Block, FunctionDeclaration},
functions::params_list::parse_params_list,
parseable::{Parseable, ParsingError, ParsingResult},
utils::{parse_token_type, try_operator},
@ -72,6 +71,7 @@ impl<'a> Parseable<'a> for FunctionDeclaration<'a> {
current_pos = next_pos;
// Try to parse a return type
// TODO: abstract parsing of Datatype to parse generics
let (return_type, next_pos) = 'return_label: {
let (arrow_op, next_pos) = match try_operator(tokens, current_pos, "->".into()) {
Ok((op, next)) => (op, next),
@ -101,7 +101,8 @@ impl<'a> Parseable<'a> for FunctionDeclaration<'a> {
current_pos = next_pos;
// Function body (block)
let (block, next_pos) = match parse_block(tokens, current_pos) {
// TODO: impl Parseable
let (block, next_pos) = match Block::try_parse(tokens, current_pos) {
Ok((block, next_pos)) => (block, next_pos),
Err(ParsingError::Err(error)) => {
return Err(ParsingError::Err(error));
@ -316,14 +317,14 @@ mod tests {
#[test]
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() { ")).unwrap();
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
match fun_decl {
Err(ParsingError::Err(err)) => {
assert_eq!(err.reason, "Expected a closing brace after the block body.");
assert_eq!(err.error_start, 11);
assert_eq!(err.error_end, 13);
assert_eq!(err.error_start, 9);
assert_eq!(err.error_end, 10);
}
_ => panic!("Expected an error: {:?}", fun_decl),
}

View File

@ -1,4 +1,5 @@
pub mod binding;
pub mod block;
pub mod expression;
pub mod function_declaration;
pub mod module;

View File

@ -22,7 +22,6 @@ impl<'a> Parseable<'a> for ModuleAST<'a> {
let mut current_pos = 0;
// Minus one because last token is EOF
// TODO: Does that EOF do anything?
while current_pos < tokens_len - 1 {
// Attempt to parse an statement
match Statement::try_parse(tokens, current_pos) {

View File

@ -1,51 +0,0 @@
use crate::lexic::token::Token;
use super::{
ast::{var_binding::VariableBinding, Statement},
parseable::Parseable,
ParsingError, ParsingResult,
};
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<Statement> {
// Try to parse a binding
match VariableBinding::try_parse(tokens, pos) {
Ok((b, next)) => return Ok((Statement::Binding(b), next)),
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
_ => {}
}
// A function call is an expression, not a statement. Remove
// Try to parse a function call
/*
match function_call_expr::try_parse(tokens, pos) {
Ok((Expression::FunctionCall(f), next)) => return Ok((Statement::FunctionCall(f), next)),
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
_ => {}
};
*/
// Return unmatched
Err(ParsingError::Unmatched)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_parse_binding() {
let input = String::from("val identifier = 20");
let tokens = crate::lexic::get_tokens(&input).unwrap();
let statement = try_parse(&tokens, 0);
let statement = match statement {
Ok((s, _)) => s,
_ => panic!("Expected a statement"),
};
match statement {
Statement::Binding(_) => assert!(true),
_ => panic!("Expected a binding"),
}
}
}