refactor: module constructions

master
Araozu 2024-06-01 21:32:16 -05:00
parent 5dafd6ca20
commit 1d4cec5548
7 changed files with 131 additions and 18 deletions

View File

@ -18,7 +18,7 @@ pub struct ModuleAST<'a> {
pub enum ModuleMembers<'a> { pub enum ModuleMembers<'a> {
// TODO: In the future implement module import // TODO: In the future implement module import
Stmt(Statement<'a>), Stmt(Statement<'a>),
Expression(Expression<'a>), Expr(Expression<'a>),
} }
#[derive(Debug)] #[derive(Debug)]

View File

@ -4,6 +4,8 @@ mod binding;
mod block; mod block;
mod expression; mod expression;
mod functions; mod functions;
mod parseable;
mod parsers;
mod statement; mod statement;
mod utils; mod utils;
@ -13,21 +15,7 @@ use crate::lexic::token::{Token, TokenType};
use ast::ModuleAST; use ast::ModuleAST;
use self::ast::ModuleMembers; use self::ast::ModuleMembers;
use self::parseable::{ParsingError, ParsingResult};
pub type ParsingResult<'a, A> = Result<(A, usize), ParsingError<'a>>;
#[derive(Debug)]
pub enum ParsingError<'a> {
/// Some other token was found than the expected one
Mismatch(&'a Token),
/// The parsing didn't succeed, but it's not a fatal error
Unmatched,
/// The parsing failed past a point of no return.
///
/// For example, when parsing a function declaration
/// the `fun` token is found, but then no identifier
Err(SyntaxError),
}
/// Constructs the Misti AST from a vector of tokens /// Constructs the Misti AST from a vector of tokens
pub fn build_ast<'a>(tokens: &'a Vec<Token>) -> Result<ModuleAST, MistiError> { pub fn build_ast<'a>(tokens: &'a Vec<Token>) -> Result<ModuleAST, MistiError> {
@ -66,10 +54,11 @@ pub fn build_ast<'a>(tokens: &'a Vec<Token>) -> Result<ModuleAST, MistiError> {
} }
fn next_construct<'a>(tokens: &'a Vec<Token>, current_pos: usize) -> ParsingResult<ModuleMembers> { fn next_construct<'a>(tokens: &'a Vec<Token>, current_pos: usize) -> ParsingResult<ModuleMembers> {
todo!();
// Try to parse a function declaration // Try to parse a function declaration
match functions::function_declaration::try_parse(tokens, current_pos) { match functions::function_declaration::try_parse(tokens, current_pos) {
Ok((declaration, next_pos)) => { Ok((declaration, next_pos)) => {
return Ok((ModuleMembers::FunctionDeclaration(declaration), next_pos)) return Ok((ModuleMembers::Stmt(FnDecl(declaration), next_pos)))
} }
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)), Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
_ => {} _ => {}
@ -84,7 +73,7 @@ fn next_construct<'a>(tokens: &'a Vec<Token>, current_pos: usize) -> ParsingResu
// Try to parse an expression // Try to parse an expression
match expression::try_parse(tokens, current_pos) { match expression::try_parse(tokens, current_pos) {
Ok((expression, next_pos)) => return Ok((ModuleMembers::Expression(expression), next_pos)), Ok((expression, next_pos)) => return Ok((ModuleMembers::Expr(expression), next_pos)),
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)), Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
_ => {} _ => {}
} }

27
src/syntax/parseable.rs Normal file
View File

@ -0,0 +1,27 @@
use crate::{error_handling::SyntaxError, lexic::token::Token};
/// The result of a parsing operation.
/// On success, it contains the item and the position of the next token
/// On failure, it contains the error
pub type ParsingResult<'a, A> = Result<(A, usize), ParsingError<'a>>;
#[derive(Debug)]
pub enum ParsingError<'a> {
/// The parsing didn't succeed, but it's not a fatal error
Unmatched,
/// Some other token was found than the expected one
Mismatch(&'a Token),
/// The parsing failed past a point of no return.
///
/// For example, when parsing a function declaration
/// the `fun` token is found, but then no identifier
Err(SyntaxError),
}
/// Represents a type that can be parsed using Recursive Descent
pub trait Parseable<'a> {
type Item;
/// Try to parse the current production.
fn try_parse(tokens: &'a Vec<Token>, current_pos: usize) -> ParsingResult<'a, Self::Item>;
}

View File

@ -0,0 +1,15 @@
use crate::{
lexic::token::Token,
syntax::{
ast::Expression,
parseable::{Parseable, ParsingResult},
},
};
impl<'a> Parseable<'a> for Expression<'a> {
type Item = Expression<'a>;
fn try_parse(tokens: &'a Vec<Token>, current_pos: usize) -> ParsingResult<'a, Self::Item> {
todo!()
}
}

View File

@ -0,0 +1,3 @@
pub mod expression;
pub mod module;
pub mod statement;

View File

@ -0,0 +1,67 @@
use crate::{
error_handling::SyntaxError,
lexic::token::Token,
syntax::{
ast::{Expression, ModuleAST, ModuleMembers, Statement},
parseable::{Parseable, ParsingError, ParsingResult},
},
};
impl<'a> Parseable<'a> for ModuleAST<'a> {
type Item = ModuleAST<'a>;
/// Parses a THP module/source file
///
/// As this function parses the whole file, it ignores `current_pos` and
/// always starts from token 0.
///
/// Its grammar is defined it the spec, at the webpage
fn try_parse(tokens: &'a Vec<Token>, current_pos: usize) -> ParsingResult<'a, Self::Item> {
let mut productions = Vec::<ModuleMembers>::new();
let tokens_len = tokens.len();
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) {
Ok((prod, next_pos)) => {
productions.push(ModuleMembers::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
// If this fails the whole thing fails
match Expression::try_parse(tokens, current_pos) {
Ok((prod, next_pos)) => {
productions.push(ModuleMembers::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 and fail
let t = tokens[current_pos];
return Err(ParsingError::Err(SyntaxError {
error_start: t.position,
error_end: t.get_end_position(),
reason: "Expected an statement or an expresion at the top level.".into(),
}));
}
Ok((ModuleAST { productions }, current_pos))
}
}

View File

@ -0,0 +1,12 @@
use crate::syntax::{ast::Statement, parseable::Parseable};
impl<'a> Parseable<'a> for Statement<'a> {
type Item = Statement<'a>;
fn try_parse(
tokens: &'a Vec<crate::lexic::token::Token>,
current_pos: usize,
) -> crate::syntax::parseable::ParsingResult<'a, Self::Item> {
todo!()
}
}