refactor: module constructions
This commit is contained in:
parent
5dafd6ca20
commit
1d4cec5548
@ -18,7 +18,7 @@ pub struct ModuleAST<'a> {
|
||||
pub enum ModuleMembers<'a> {
|
||||
// TODO: In the future implement module import
|
||||
Stmt(Statement<'a>),
|
||||
Expression(Expression<'a>),
|
||||
Expr(Expression<'a>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -4,6 +4,8 @@ mod binding;
|
||||
mod block;
|
||||
mod expression;
|
||||
mod functions;
|
||||
mod parseable;
|
||||
mod parsers;
|
||||
mod statement;
|
||||
mod utils;
|
||||
|
||||
@ -13,21 +15,7 @@ use crate::lexic::token::{Token, TokenType};
|
||||
use ast::ModuleAST;
|
||||
|
||||
use self::ast::ModuleMembers;
|
||||
|
||||
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),
|
||||
}
|
||||
use self::parseable::{ParsingError, ParsingResult};
|
||||
|
||||
/// Constructs the Misti AST from a vector of tokens
|
||||
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> {
|
||||
todo!();
|
||||
// Try to parse a function declaration
|
||||
match functions::function_declaration::try_parse(tokens, current_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)),
|
||||
_ => {}
|
||||
@ -84,7 +73,7 @@ fn next_construct<'a>(tokens: &'a Vec<Token>, current_pos: usize) -> ParsingResu
|
||||
|
||||
// Try to parse an expression
|
||||
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)),
|
||||
_ => {}
|
||||
}
|
||||
|
27
src/syntax/parseable.rs
Normal file
27
src/syntax/parseable.rs
Normal 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>;
|
||||
}
|
15
src/syntax/parsers/expression.rs
Normal file
15
src/syntax/parsers/expression.rs
Normal 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!()
|
||||
}
|
||||
}
|
3
src/syntax/parsers/mod.rs
Normal file
3
src/syntax/parsers/mod.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub mod expression;
|
||||
pub mod module;
|
||||
pub mod statement;
|
67
src/syntax/parsers/module.rs
Normal file
67
src/syntax/parsers/module.rs
Normal 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))
|
||||
}
|
||||
}
|
12
src/syntax/parsers/statement.rs
Normal file
12
src/syntax/parsers/statement.rs
Normal 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!()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user