Simplify ParseResult struct

master
Araozu 2024-03-15 15:49:02 -05:00
parent d822c64fd7
commit 1348020cd7
24 changed files with 86 additions and 45 deletions

View File

@ -13,7 +13,10 @@ impl Transpilable for Binding<'_> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::{lexic::token::{Token, TokenType}, syntax::ast::{var_binding::Binding, Expression}}; use crate::{
lexic::token::{Token, TokenType},
syntax::ast::{var_binding::Binding, Expression},
};
#[test] #[test]
fn binding_should_transpile() { fn binding_should_transpile() {

View File

@ -34,6 +34,7 @@ mod tests {
assert_eq!("function id() {\n\n}", transpiled); assert_eq!("function id() {\n\n}", transpiled);
} }
_ => panic!("Not implemented: Expression at top level"),
} }
} }
} }

View File

@ -18,7 +18,10 @@ impl Transpilable for ModuleAST<'_> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::{lexic::token::{Token, TokenType}, syntax::ast::{var_binding::Binding, Expression, TopLevelDeclaration}}; use crate::{
lexic::token::{Token, TokenType},
syntax::ast::{var_binding::Binding, Expression, TopLevelDeclaration},
};
#[test] #[test]
fn module_ast_should_transpile() { fn module_ast_should_transpile() {

View File

@ -7,6 +7,7 @@ impl Transpilable for TopLevelDeclaration<'_> {
match self { match self {
TopLevelDeclaration::Binding(binding) => binding.transpile(), TopLevelDeclaration::Binding(binding) => binding.transpile(),
TopLevelDeclaration::FunctionDeclaration(fun) => fun.transpile(), TopLevelDeclaration::FunctionDeclaration(fun) => fun.transpile(),
_ => panic!("Not implemented: Expression at top level"),
} }
} }
} }

View File

@ -22,7 +22,7 @@ pub enum TokenType {
FUN, FUN,
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Token { pub struct Token {
pub token_type: TokenType, pub token_type: TokenType,
// The token as a raw string // The token as a raw string

View File

@ -51,12 +51,15 @@ impl SemanticCheck for TopLevelDeclaration<'_> {
binding_name binding_name
), ),
}; };
return Err(MistiError::Semantic(error)); return Err(MistiError::Semantic(error));
} }
}; };
scope.insert(binding_name.clone(), SymbolEntry::new_variable(datatype.value.clone())); scope.insert(
binding_name.clone(),
SymbolEntry::new_variable(datatype.value.clone()),
);
Ok(()) Ok(())
} }
@ -77,10 +80,14 @@ impl SemanticCheck for TopLevelDeclaration<'_> {
return Err(MistiError::Semantic(error)); return Err(MistiError::Semantic(error));
} }
scope.insert(function_name, SymbolEntry::new_function(vec![], "Unit".into())); scope.insert(
function_name,
SymbolEntry::new_function(vec![], "Unit".into()),
);
Ok(()) Ok(())
} }
_ => panic!("Not implemented"),
} }
} }
} }

View File

@ -14,6 +14,7 @@ pub struct ModuleAST<'a> {
pub enum TopLevelDeclaration<'a> { pub enum TopLevelDeclaration<'a> {
Binding(var_binding::Binding<'a>), Binding(var_binding::Binding<'a>),
FunctionDeclaration(FunctionDeclaration<'a>), FunctionDeclaration(FunctionDeclaration<'a>),
Expression(Expression<'a>),
} }
#[derive(Debug)] #[derive(Debug)]

View File

@ -5,7 +5,7 @@ use crate::error_handling::SyntaxError;
use crate::lexic::token::{Token, TokenType}; use crate::lexic::token::{Token, TokenType};
use crate::utils::Result3; use crate::utils::Result3;
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Binding, ()> { pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Binding> {
let mut current_pos = pos; let mut current_pos = pos;
// TODO: Detect if the binding starts with a datatype // TODO: Detect if the binding starts with a datatype

View File

@ -6,7 +6,7 @@ use crate::{
use super::{ast::Block, utils::parse_token_type, ParseResult}; use super::{ast::Block, utils::parse_token_type, ParseResult};
// Assumes that the token at `pos` is a { // Assumes that the token at `pos` is a {
pub fn parse_block<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Block, &Token> { pub fn parse_block<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Block> {
let mut current_pos = pos; let mut current_pos = pos;
let (opening_brace, next_pos) = let (opening_brace, next_pos) =

View File

@ -8,7 +8,7 @@ use crate::{
/// ```ebnf /// ```ebnf
/// comparison = term, ((">" | ">=" | "<" | "<="), term)*; /// comparison = term, ((">" | ">=" | "<" | "<="), term)*;
/// ``` /// ```
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> { pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression> {
let (term, next_pos) = match super::term::try_parse(tokens, pos) { let (term, next_pos) = match super::term::try_parse(tokens, pos) {
ParseResult::Ok(expr, next_pos) => (expr, next_pos), ParseResult::Ok(expr, next_pos) => (expr, next_pos),
_ => return ParseResult::Unmatched, _ => return ParseResult::Unmatched,
@ -21,7 +21,7 @@ fn parse_many<'a>(
tokens: &'a Vec<Token>, tokens: &'a Vec<Token>,
pos: usize, pos: usize,
prev_expr: Expression<'a>, prev_expr: Expression<'a>,
) -> ParseResult<Expression<'a>, ()> { ) -> ParseResult<Expression<'a>> {
// comparison = term, ((">" | ">=" | "<" | "<="), term)*; // comparison = term, ((">" | ">=" | "<" | "<="), term)*;
match tokens.get(pos) { match tokens.get(pos) {

View File

@ -8,7 +8,7 @@ use crate::{
/// ```ebnf /// ```ebnf
/// equality = comparison, (("==" | "!="), comparison )*; /// equality = comparison, (("==" | "!="), comparison )*;
/// ``` /// ```
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> { pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression> {
let (comparison, next_pos) = match super::comparison::try_parse(tokens, pos) { let (comparison, next_pos) = match super::comparison::try_parse(tokens, pos) {
ParseResult::Ok(expr, next_pos) => (expr, next_pos), ParseResult::Ok(expr, next_pos) => (expr, next_pos),
_ => return ParseResult::Unmatched, _ => return ParseResult::Unmatched,
@ -21,7 +21,7 @@ fn parse_many<'a>(
tokens: &'a Vec<Token>, tokens: &'a Vec<Token>,
pos: usize, pos: usize,
prev_expr: Expression<'a>, prev_expr: Expression<'a>,
) -> ParseResult<Expression<'a>, ()> { ) -> ParseResult<Expression<'a>> {
// equality = comparison, (("==" | "!="), comparison )*; // equality = comparison, (("==" | "!="), comparison )*;
match tokens.get(pos) { match tokens.get(pos) {

View File

@ -8,7 +8,7 @@ use crate::{
/// ```ebnf /// ```ebnf
/// factor = unary, (("/" | "*"), unary)*; /// factor = unary, (("/" | "*"), unary)*;
/// ``` /// ```
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> { pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression> {
let (unary, next_pos) = match super::unary::try_parse(tokens, pos) { let (unary, next_pos) = match super::unary::try_parse(tokens, pos) {
ParseResult::Ok(expr, next_pos) => (expr, next_pos), ParseResult::Ok(expr, next_pos) => (expr, next_pos),
_ => return ParseResult::Unmatched, _ => return ParseResult::Unmatched,
@ -21,7 +21,7 @@ fn parse_many<'a>(
tokens: &'a Vec<Token>, tokens: &'a Vec<Token>,
pos: usize, pos: usize,
prev_expr: Expression<'a>, prev_expr: Expression<'a>,
) -> ParseResult<Expression<'a>, ()> { ) -> ParseResult<Expression<'a>> {
// (("/" | "*"), unary)* // (("/" | "*"), unary)*
match tokens.get(pos) { match tokens.get(pos) {

View File

@ -13,7 +13,7 @@ use crate::{
/// function call expr = primary, "(", (arguments list)?, ")" /// function call expr = primary, "(", (arguments list)?, ")"
/// | primary; /// | primary;
/// ``` /// ```
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> { pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression> {
let (primary_expr, next_pos) = match super::primary::try_parse(tokens, pos) { let (primary_expr, next_pos) = match super::primary::try_parse(tokens, pos) {
ParseResult::Ok(expr, next_pos) => (expr, next_pos), ParseResult::Ok(expr, next_pos) => (expr, next_pos),
_ => return ParseResult::Unmatched, _ => return ParseResult::Unmatched,

View File

@ -10,7 +10,7 @@ mod term;
mod unary; mod unary;
/// Expression is defined in the grammar. /// Expression is defined in the grammar.
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> { pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression> {
return equality::try_parse(tokens, pos); return equality::try_parse(tokens, pos);
} }

View File

@ -9,7 +9,7 @@ use crate::{
/// ```ebnf /// ```ebnf
/// primary = number | string | boolean | identifier | ("(", expression, ")"); /// primary = number | string | boolean | identifier | ("(", expression, ")");
/// ``` /// ```
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> { pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression> {
match tokens.get_significant(pos) { match tokens.get_significant(pos) {
Some((token, token_pos)) => match token.token_type { Some((token, token_pos)) => match token.token_type {
TokenType::Number => ParseResult::Ok(Expression::Number(&token.value), token_pos + 1), TokenType::Number => ParseResult::Ok(Expression::Number(&token.value), token_pos + 1),
@ -27,7 +27,7 @@ pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()>
} }
} }
fn parse_parenthesized_expression(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> { fn parse_parenthesized_expression(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression> {
let expression = super::try_parse(tokens, pos + 1); let expression = super::try_parse(tokens, pos + 1);
match expression { match expression {
ParseResult::Ok(expression, next_pos) => match tokens.get(next_pos) { ParseResult::Ok(expression, next_pos) => match tokens.get(next_pos) {

View File

@ -8,7 +8,7 @@ use crate::{
/// ```ebnf /// ```ebnf
/// term = factor, (("-" | "+"), factor)*; /// term = factor, (("-" | "+"), factor)*;
/// ``` /// ```
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> { pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression> {
let (factor, next_pos) = match super::factor::try_parse(tokens, pos) { let (factor, next_pos) = match super::factor::try_parse(tokens, pos) {
ParseResult::Ok(expr, next_pos) => (expr, next_pos), ParseResult::Ok(expr, next_pos) => (expr, next_pos),
_ => return ParseResult::Unmatched, _ => return ParseResult::Unmatched,
@ -21,7 +21,7 @@ fn parse_many<'a>(
tokens: &'a Vec<Token>, tokens: &'a Vec<Token>,
pos: usize, pos: usize,
prev_expr: Expression<'a>, prev_expr: Expression<'a>,
) -> ParseResult<Expression<'a>, ()> { ) -> ParseResult<Expression<'a>> {
// term = factor, (("-" | "+"), factor)*; // term = factor, (("-" | "+"), factor)*;
match tokens.get(pos) { match tokens.get(pos) {

View File

@ -11,7 +11,7 @@ use super::function_call_expr;
/// unary = ("!" | "-"), expression /// unary = ("!" | "-"), expression
/// | function call expr; /// | function call expr;
/// ``` /// ```
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> { pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression> {
match tokens.get(pos) { match tokens.get(pos) {
Some(token) if token.value == "!" || token.value == "-" => { Some(token) if token.value == "!" || token.value == "-" => {
match super::try_parse(tokens, pos + 1) { match super::try_parse(tokens, pos + 1) {

View File

@ -8,7 +8,7 @@ use crate::{
}, },
}; };
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<ArgumentsList, &Token> { pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<ArgumentsList> {
let mut current_pos = pos; let mut current_pos = pos;
let (opening_paren, next_pos) = let (opening_paren, next_pos) =

View File

@ -14,7 +14,7 @@ use super::{
params_list::parse_params_list, params_list::parse_params_list,
}; };
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<FunctionDeclaration, ()> { pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<FunctionDeclaration> {
let mut current_pos = pos; let mut current_pos = pos;
// `fun` keyword // `fun` keyword

View File

@ -9,10 +9,7 @@ use super::super::{
utils, ParseResult, utils, ParseResult,
}; };
pub fn parse_params_list<'a>( pub fn parse_params_list<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<ParamsList> {
tokens: &'a Vec<Token>,
pos: usize,
) -> ParseResult<ParamsList, &Token> {
let mut current_pos = pos; let mut current_pos = pos;
let (opening_paren, next_pos) = let (opening_paren, next_pos) =
@ -24,6 +21,14 @@ pub fn parse_params_list<'a>(
}; };
current_pos = next_pos; current_pos = next_pos;
/*
val (opening_paren, next_pos) = try parse_token_type(...)
val (next_parameter, next_pos) = try parse_param_definition(...) catch
case ::Err(e) { return ::Err(e) }
else { break }
*/
// Parse parameters definitions, separated by commas // Parse parameters definitions, separated by commas
let mut parameters = Vec::<Parameter>::new(); let mut parameters = Vec::<Parameter>::new();
loop { loop {
@ -79,10 +84,7 @@ pub fn parse_params_list<'a>(
ParseResult::Ok(ParamsList {}, current_pos) ParseResult::Ok(ParamsList {}, current_pos)
} }
fn parse_param_definition<'a>( fn parse_param_definition<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Parameter> {
tokens: &'a Vec<Token>,
pos: usize,
) -> ParseResult<Parameter, &Token> {
// Parse a single parameter definition of the form: // Parse a single parameter definition of the form:
// - Type identifier // - Type identifier
// There will be more constructs in the future, like: // There will be more constructs in the future, like:

View File

@ -1,19 +1,21 @@
# Grammar # Grammar
## Module ## Source file
A module is (commonly) a single source file.
```ebnf ```ebnf
module = top level declaration* source file = top level statement*
``` ```
## Top level declaration ## Top level statement
Current focus: Have a mvp compiler (w lexical/syntactic/semantic analysis + codegen) for
simple function calls, and then implement other features top down
```ebnf ```ebnf
top level declaration = function declaration top level statement = expression
| function declaration
``` ```

View File

@ -15,7 +15,7 @@ use ast::ModuleAST;
use self::ast::TopLevelDeclaration; use self::ast::TopLevelDeclaration;
#[derive(Debug)] #[derive(Debug)]
pub enum ParseResult<A, B> { pub enum ParseResult<A> {
/// The parsing was a success. The first element is the parsed construct, /// The parsing was a success. The first element is the parsed construct,
/// the second element is the position of the next token to parse /// the second element is the position of the next token to parse
Ok(A, usize), Ok(A, usize),
@ -26,11 +26,19 @@ pub enum ParseResult<A, B> {
Err(SyntaxError), Err(SyntaxError),
/// Some special value was expected, but something else was found. /// Some special value was expected, but something else was found.
/// The inside element is the something else found. /// The inside element is the something else found.
Mismatch(B), Mismatch(Token),
/// This parsing didn't succeed, but it's not a fatal error. /// This parsing didn't succeed, but it's not a fatal error.
Unmatched, Unmatched,
} }
enum ParsingError {
Mismatch(Token),
Unmatch,
Error(SyntaxError),
}
type ParsingResult<A> = Result<(A, usize), ParsingError>;
/// Constructs the Misti AST from a vector of tokens /// Constructs the Misti AST from a vector of tokens
pub fn construct_ast<'a>(tokens: &'a Vec<Token>) -> Result<ModuleAST, MistiError> { pub fn construct_ast<'a>(tokens: &'a Vec<Token>) -> Result<ModuleAST, MistiError> {
let mut top_level_declarations = Vec::new(); let mut top_level_declarations = Vec::new();
@ -70,7 +78,7 @@ pub fn construct_ast<'a>(tokens: &'a Vec<Token>) -> Result<ModuleAST, MistiError
fn next_construct<'a>( fn next_construct<'a>(
tokens: &'a Vec<Token>, tokens: &'a Vec<Token>,
current_pos: usize, current_pos: usize,
) -> ParseResult<TopLevelDeclaration, ()> { ) -> ParseResult<TopLevelDeclaration> {
None.or_else( None.or_else(
|| match functions::function_declaration::try_parse(tokens, current_pos) { || match functions::function_declaration::try_parse(tokens, current_pos) {
ParseResult::Ok(declaration, next_pos) => Some(ParseResult::Ok( ParseResult::Ok(declaration, next_pos) => Some(ParseResult::Ok(
@ -81,6 +89,15 @@ fn next_construct<'a>(
_ => None, _ => None,
}, },
) )
.or_else(|| match expression::try_parse(tokens, current_pos) {
ParseResult::Ok(expression, next_pos) => Some(ParseResult::Ok(
TopLevelDeclaration::Expression(expression),
next_pos,
)),
ParseResult::Err(_) => todo!(),
ParseResult::Mismatch(_) => todo!(),
ParseResult::Unmatched => todo!(),
})
.unwrap_or_else(|| ParseResult::Unmatched) .unwrap_or_else(|| ParseResult::Unmatched)
} }
@ -101,6 +118,7 @@ mod tests {
TopLevelDeclaration::FunctionDeclaration(_f) => { TopLevelDeclaration::FunctionDeclaration(_f) => {
assert!(true) assert!(true)
} }
_ => panic!("Not implemented: Expression at top level"),
} }
} }
@ -117,6 +135,7 @@ mod tests {
TopLevelDeclaration::FunctionDeclaration(_f) => { TopLevelDeclaration::FunctionDeclaration(_f) => {
assert!(true) assert!(true)
} }
_ => panic!("Not implemented: Expression at top level"),
} }
match declarations.get(1).unwrap() { match declarations.get(1).unwrap() {
@ -124,6 +143,7 @@ mod tests {
TopLevelDeclaration::FunctionDeclaration(_f) => { TopLevelDeclaration::FunctionDeclaration(_f) => {
assert!(true) assert!(true)
} }
_ => panic!("Not implemented: Expression at top level"),
} }
} }
} }

View File

@ -7,7 +7,7 @@ use super::{
ParseResult, ParseResult,
}; };
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Statement, ()> { pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Statement> {
None.or_else(|| match binding::try_parse(tokens, pos) { None.or_else(|| match binding::try_parse(tokens, pos) {
ParseResult::Ok(b, next) => Some(ParseResult::Ok(Statement::Binding(b), next)), ParseResult::Ok(b, next) => Some(ParseResult::Ok(Statement::Binding(b), next)),
ParseResult::Err(err) => Some(ParseResult::Err(err)), ParseResult::Err(err) => Some(ParseResult::Err(err)),

View File

@ -33,7 +33,7 @@ impl Tokenizer for Vec<Token> {
} }
} }
/// Expects the token at `pos` to be of type `token_type` /// Expects the token at `pos` to be of type `token_type`. Doesn't ignore whitespace or newlines
pub fn try_token_type(tokens: &Vec<Token>, pos: usize, token_type: TokenType) -> Result3<&Token> { pub fn try_token_type(tokens: &Vec<Token>, pos: usize, token_type: TokenType) -> Result3<&Token> {
match tokens.get(pos) { match tokens.get(pos) {
Some(t) if t.token_type == token_type => Result3::Ok(t), Some(t) if t.token_type == token_type => Result3::Ok(t),
@ -45,6 +45,7 @@ pub fn try_token_type(tokens: &Vec<Token>, pos: usize, token_type: TokenType) ->
} }
} }
/// Expects the token at `pos` to be an operator of value `operator`. Doesn't ignore whitespace or newlines
pub fn try_operator(tokens: &Vec<Token>, pos: usize, operator: String) -> Result3<&Token> { pub fn try_operator(tokens: &Vec<Token>, pos: usize, operator: String) -> Result3<&Token> {
match tokens.get(pos) { match tokens.get(pos) {
Some(t) if t.token_type == TokenType::Operator && t.value == operator => Result3::Ok(t), Some(t) if t.token_type == TokenType::Operator && t.value == operator => Result3::Ok(t),
@ -56,12 +57,12 @@ pub fn try_operator(tokens: &Vec<Token>, pos: usize, operator: String) -> Result
} }
} }
/// Expects the token at `pos` to be of type `token_type` /// Expects the token at `pos` to be of type `token_type`, ignoring all whitespace & newlines
pub fn parse_token_type( pub fn parse_token_type(
tokens: &Vec<Token>, tokens: &Vec<Token>,
pos: usize, pos: usize,
token_type: TokenType, token_type: TokenType,
) -> ParseResult<&Token, &Token> { ) -> ParseResult<&Token> {
let mut current_pos = pos; let mut current_pos = pos;
// Ignore all whitespace and newlines // Ignore all whitespace and newlines
@ -81,7 +82,7 @@ pub fn parse_token_type(
Some(t) if t.token_type == TokenType::EOF || t.token_type == TokenType::NewLine => { Some(t) if t.token_type == TokenType::EOF || t.token_type == TokenType::NewLine => {
ParseResult::Unmatched ParseResult::Unmatched
} }
Some(t) => ParseResult::Mismatch(t), Some(t) => ParseResult::Mismatch(t.clone()),
None => ParseResult::Unmatched, None => ParseResult::Unmatched,
} }
} }