refactor: impl Parseable for Block
This commit is contained in:
parent
8d5fcd1ce3
commit
6a951434f3
@ -5,10 +5,13 @@ use super::Transpilable;
|
|||||||
impl Transpilable for Block<'_> {
|
impl Transpilable for Block<'_> {
|
||||||
fn transpile(&self) -> String {
|
fn transpile(&self) -> String {
|
||||||
// TODO: Handle indentation
|
// TODO: Handle indentation
|
||||||
self.statements
|
todo!("transpilation for block");
|
||||||
|
/*
|
||||||
|
self.members
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| x.transpile())
|
.map(|x| x.transpile())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n")
|
.join("\n")
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ mod tests {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* TODO: reimplement
|
||||||
#[test]
|
#[test]
|
||||||
fn should_transpile() {
|
fn should_transpile() {
|
||||||
let tokens = get_tokens(&String::from("fun id() {}")).unwrap();
|
let tokens = get_tokens(&String::from("fun id() {}")).unwrap();
|
||||||
@ -38,5 +39,5 @@ mod tests {
|
|||||||
}
|
}
|
||||||
_ => panic!("Expected a function declaration"),
|
_ => panic!("Expected a function declaration"),
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use crate::{
|
|||||||
impls::SemanticCheck,
|
impls::SemanticCheck,
|
||||||
symbol_table::{SymbolEntry, SymbolTable},
|
symbol_table::{SymbolEntry, SymbolTable},
|
||||||
},
|
},
|
||||||
syntax::ast::{FunctionDeclaration, Statement},
|
syntax::ast::{BlockMember, FunctionDeclaration, Statement},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl SemanticCheck for FunctionDeclaration<'_> {
|
impl SemanticCheck for FunctionDeclaration<'_> {
|
||||||
@ -33,16 +33,17 @@ impl SemanticCheck for FunctionDeclaration<'_> {
|
|||||||
|
|
||||||
// TODO: Check the return type of the function body
|
// TODO: Check the return type of the function body
|
||||||
// This should be the last expression in the block
|
// 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 {
|
match stmt {
|
||||||
Statement::Binding(b) => {
|
BlockMember::Stmt(Statement::Binding(b)) => {
|
||||||
if let Err(err) = b.check_semantics(&function_scope) {
|
if let Err(err) = b.check_semantics(&function_scope) {
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Statement::FnDecl(_) => {
|
BlockMember::Stmt(Statement::FnDecl(_)) => {
|
||||||
todo!("Function declaration: semantic check not implemented")
|
todo!("Function declaration: semantic check not implemented")
|
||||||
}
|
}
|
||||||
|
_ => todo!("Expression: semantic check not implemented"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,8 +37,14 @@ pub struct FunctionDeclaration<'a> {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Block<'a> {
|
pub struct Block<'a> {
|
||||||
// TODO: this should be a Vec of Statement|Expression
|
pub members: Vec<BlockMember<'a>>,
|
||||||
pub statements: Vec<Statement<'a>>,
|
}
|
||||||
|
|
||||||
|
/// Enum for productions available at the block level
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum BlockMember<'a> {
|
||||||
|
Stmt(Statement<'a>),
|
||||||
|
Expr(Expression<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
@ -1,11 +1,9 @@
|
|||||||
use crate::error_handling::MistiError;
|
use crate::error_handling::MistiError;
|
||||||
|
|
||||||
mod block;
|
|
||||||
mod expression;
|
mod expression;
|
||||||
mod functions;
|
mod functions;
|
||||||
mod parseable;
|
mod parseable;
|
||||||
mod parsers;
|
mod parsers;
|
||||||
mod statement;
|
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
pub mod ast;
|
pub mod ast;
|
||||||
|
147
src/syntax/parsers/block.rs
Normal file
147
src/syntax/parsers/block.rs
Normal 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);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
@ -2,8 +2,7 @@ use crate::{
|
|||||||
error_handling::SyntaxError,
|
error_handling::SyntaxError,
|
||||||
lexic::token::{Token, TokenType},
|
lexic::token::{Token, TokenType},
|
||||||
syntax::{
|
syntax::{
|
||||||
ast::FunctionDeclaration,
|
ast::{Block, FunctionDeclaration},
|
||||||
block::parse_block,
|
|
||||||
functions::params_list::parse_params_list,
|
functions::params_list::parse_params_list,
|
||||||
parseable::{Parseable, ParsingError, ParsingResult},
|
parseable::{Parseable, ParsingError, ParsingResult},
|
||||||
utils::{parse_token_type, try_operator},
|
utils::{parse_token_type, try_operator},
|
||||||
@ -72,6 +71,7 @@ impl<'a> Parseable<'a> for FunctionDeclaration<'a> {
|
|||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
// Try to parse a return type
|
// Try to parse a return type
|
||||||
|
// TODO: abstract parsing of Datatype to parse generics
|
||||||
let (return_type, next_pos) = 'return_label: {
|
let (return_type, next_pos) = 'return_label: {
|
||||||
let (arrow_op, next_pos) = match try_operator(tokens, current_pos, "->".into()) {
|
let (arrow_op, next_pos) = match try_operator(tokens, current_pos, "->".into()) {
|
||||||
Ok((op, next)) => (op, next),
|
Ok((op, next)) => (op, next),
|
||||||
@ -101,7 +101,8 @@ impl<'a> Parseable<'a> for FunctionDeclaration<'a> {
|
|||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
// Function body (block)
|
// 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),
|
Ok((block, next_pos)) => (block, next_pos),
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
return Err(ParsingError::Err(error));
|
return Err(ParsingError::Err(error));
|
||||||
@ -316,14 +317,14 @@ 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() { ")).unwrap();
|
||||||
let fun_decl = FunctionDeclaration::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!(err.reason, "Expected a closing brace after the block body.");
|
assert_eq!(err.reason, "Expected a closing brace after the block body.");
|
||||||
assert_eq!(err.error_start, 11);
|
assert_eq!(err.error_start, 9);
|
||||||
assert_eq!(err.error_end, 13);
|
assert_eq!(err.error_end, 10);
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
pub mod binding;
|
pub mod binding;
|
||||||
|
pub mod block;
|
||||||
pub mod expression;
|
pub mod expression;
|
||||||
pub mod function_declaration;
|
pub mod function_declaration;
|
||||||
pub mod module;
|
pub mod module;
|
||||||
|
@ -22,7 +22,6 @@ impl<'a> Parseable<'a> for ModuleAST<'a> {
|
|||||||
let mut current_pos = 0;
|
let mut current_pos = 0;
|
||||||
|
|
||||||
// Minus one because last token is EOF
|
// Minus one because last token is EOF
|
||||||
// TODO: Does that EOF do anything?
|
|
||||||
while current_pos < tokens_len - 1 {
|
while current_pos < tokens_len - 1 {
|
||||||
// Attempt to parse an statement
|
// Attempt to parse an statement
|
||||||
match Statement::try_parse(tokens, current_pos) {
|
match Statement::try_parse(tokens, current_pos) {
|
||||||
|
@ -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"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user