diff --git a/src/syntax/ast/mod.rs b/src/syntax/ast/mod.rs index 4a013c8..db3cb23 100644 --- a/src/syntax/ast/mod.rs +++ b/src/syntax/ast/mod.rs @@ -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)] diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index 7b42f09..266b535 100755 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -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) -> Result { @@ -66,10 +54,11 @@ pub fn build_ast<'a>(tokens: &'a Vec) -> Result { } fn next_construct<'a>(tokens: &'a Vec, current_pos: usize) -> ParsingResult { + 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, 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)), _ => {} } diff --git a/src/syntax/parseable.rs b/src/syntax/parseable.rs new file mode 100644 index 0000000..bc658f6 --- /dev/null +++ b/src/syntax/parseable.rs @@ -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, current_pos: usize) -> ParsingResult<'a, Self::Item>; +} diff --git a/src/syntax/parsers/expression.rs b/src/syntax/parsers/expression.rs new file mode 100644 index 0000000..d1e0a2b --- /dev/null +++ b/src/syntax/parsers/expression.rs @@ -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, current_pos: usize) -> ParsingResult<'a, Self::Item> { + todo!() + } +} diff --git a/src/syntax/parsers/mod.rs b/src/syntax/parsers/mod.rs new file mode 100644 index 0000000..2a18e89 --- /dev/null +++ b/src/syntax/parsers/mod.rs @@ -0,0 +1,3 @@ +pub mod expression; +pub mod module; +pub mod statement; diff --git a/src/syntax/parsers/module.rs b/src/syntax/parsers/module.rs new file mode 100644 index 0000000..79adf30 --- /dev/null +++ b/src/syntax/parsers/module.rs @@ -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, current_pos: usize) -> ParsingResult<'a, Self::Item> { + let mut productions = Vec::::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)) + } +} diff --git a/src/syntax/parsers/statement.rs b/src/syntax/parsers/statement.rs new file mode 100644 index 0000000..95aa624 --- /dev/null +++ b/src/syntax/parsers/statement.rs @@ -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, + current_pos: usize, + ) -> crate::syntax::parseable::ParsingResult<'a, Self::Item> { + todo!() + } +}