feat: parse conditionals

master
Araozu 2024-08-27 16:09:12 -05:00
parent 6ff782a20e
commit 72bd8c50c9
9 changed files with 222 additions and 7 deletions

View File

@ -19,6 +19,10 @@
- Begin work on the code formatter
- Remove all panic! and todo!
## v0.1.2
- [x] Parse conditionals
## v0.1.1

View File

@ -7,6 +7,8 @@ fn str_is_keyword(s: &String) -> Option<TokenType> {
"val" => Some(TokenType::VAL),
"var" => Some(TokenType::VAR),
"fun" => Some(TokenType::FUN),
"if" => Some(TokenType::IF),
"else" => Some(TokenType::ELSE),
_ => None,
}
}

View File

@ -24,6 +24,8 @@ pub enum TokenType {
VAR,
EOF,
FUN,
IF,
ELSE,
}
#[derive(Serialize, Debug, Clone, PartialEq)]

View File

@ -49,6 +49,7 @@ impl SemanticCheck for FunctionDeclaration<'_> {
return Err(MistiError::Semantic(error));
}
BlockMember::Stmt(Statement::Conditional(_)) => unimplemented!("check conditional"),
BlockMember::Expr(e) => e.check_semantics(scope)?,
}
}

View File

@ -22,6 +22,7 @@ impl SemanticCheck for Statement<'_> {
match self {
Statement::Binding(b) => b.check_semantics(scope),
Statement::FnDecl(f) => f.check_semantics(scope),
Statement::Conditional(_) => unimplemented!("check conditional"),
}
}
}

View File

@ -31,8 +31,24 @@ pub enum ModuleMembers<'a> {
pub enum Statement<'a> {
Binding(VariableBinding<'a>),
FnDecl(FunctionDeclaration<'a>),
// TODO: Implement conditionals as expressions
Conditional(Conditional<'a>),
}
#[derive(Debug)]
pub struct Conditional<'a> {
pub if_member: Condition<'a>,
pub else_if_members: Vec<Condition<'a>>,
pub else_block: Option<Block<'a>>
}
#[derive(Debug)]
pub struct Condition<'a> {
pub condition: Expression<'a>,
pub body: Block<'a>,
}
#[derive(Debug)]
pub struct FunctionDeclaration<'a> {
pub identifier: &'a Token,

View File

@ -0,0 +1,181 @@
use crate::{
error_handling::SyntaxError,
lexic::token::{Token, TokenType},
syntax::{
ast::{Block, Condition, Conditional, Expression, Positionable},
parseable::{Parseable, ParsingError, ParsingResult},
utils::parse_token_type,
},
};
impl<'a> Parseable<'a> for Conditional<'a> {
type Item = Conditional<'a>;
fn try_parse(tokens: &'a Vec<Token>, current_pos: usize) -> ParsingResult<'a, Self::Item> {
// if keyword
let (if_token, next) = match parse_token_type(tokens, current_pos, TokenType::IF) {
Ok(tuple) => tuple,
_ => return Err(ParsingError::Unmatched),
};
// if condition
let (if_expression, next) = match Expression::try_parse(tokens, next) {
Ok(tuple) => tuple,
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
Err(ParsingError::Mismatch(wrong_token)) => {
return Err(ParsingError::Err(SyntaxError {
reason: String::from("Expected an expression after the if token"),
error_start: wrong_token.position,
error_end: wrong_token.get_end_position(),
}));
}
Err(ParsingError::Unmatched) => {
return Err(ParsingError::Err(SyntaxError {
reason: String::from("Expected an expression after the if token"),
error_start: if_token.position,
error_end: if_token.get_end_position(),
}));
}
};
// if block
let (if_block, next) = match Block::try_parse(tokens, next) {
Ok(t) => t,
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
Err(ParsingError::Mismatch(wrong_token)) => {
return Err(ParsingError::Err(SyntaxError {
reason: String::from("Expected a block after the condition"),
error_start: wrong_token.position,
error_end: wrong_token.get_end_position(),
}));
}
Err(ParsingError::Unmatched) => {
let (error_start, error_end) = if_expression.get_position();
return Err(ParsingError::Err(SyntaxError {
reason: String::from("Expected a block after the condition"),
error_start,
error_end,
}));
}
};
let mut else_if_members = Vec::<Condition>::new();
let mut current_pos = next;
let tokens_len = tokens.len();
// many else if
while current_pos < tokens_len {
// else token
let (_, next) = match parse_token_type(tokens, current_pos, TokenType::ELSE) {
Ok(tuple) => tuple,
_ => {
break;
}
};
// if token
let (if_token, next) = match parse_token_type(tokens, next, TokenType::IF) {
Ok(tuple) => tuple,
// This might be a else {}, not a else if {}
_ => {
break;
}
};
// condition
let (condition, next) = match Expression::try_parse(tokens, next) {
Ok(tuple) => tuple,
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
Err(ParsingError::Mismatch(wrong_token)) => {
return Err(ParsingError::Err(SyntaxError {
reason: String::from("Expected an expression after the if token"),
error_start: wrong_token.position,
error_end: wrong_token.get_end_position(),
}));
}
Err(ParsingError::Unmatched) => {
return Err(ParsingError::Err(SyntaxError {
reason: String::from("Expected an expression after the if token"),
error_start: if_token.position,
error_end: if_token.get_end_position(),
}));
}
};
// block
let (block, next) = match Block::try_parse(tokens, next) {
Ok(t) => t,
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
Err(ParsingError::Mismatch(wrong_token)) => {
return Err(ParsingError::Err(SyntaxError {
reason: String::from("Expected a block after the condition"),
error_start: wrong_token.position,
error_end: wrong_token.get_end_position(),
}));
}
Err(ParsingError::Unmatched) => {
let (error_start, error_end) = condition.get_position();
return Err(ParsingError::Err(SyntaxError {
reason: String::from("Expected a block after the condition"),
error_start,
error_end,
}));
}
};
else_if_members.push(Condition {
condition,
body: block,
});
current_pos = next;
}
// else
let (else_block, next) = {
match parse_token_type(tokens, current_pos, TokenType::ELSE) {
Ok((else_token, next)) => {
// block
let (block, next) = match Block::try_parse(tokens, next) {
Ok(t) => t,
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
Err(ParsingError::Mismatch(wrong_token)) => {
return Err(ParsingError::Err(SyntaxError {
reason: String::from(
"Expected a block after the else keyword",
),
error_start: wrong_token.position,
error_end: wrong_token.get_end_position(),
}));
}
Err(ParsingError::Unmatched) => {
return Err(ParsingError::Err(SyntaxError {
reason: String::from(
"Expected a block after the else keyword",
),
error_start: else_token.position,
error_end: else_token.get_end_position(),
}));
}
};
(Some(block), next)
}
_ => (None, current_pos),
}
};
// return
let result = Conditional {
if_member: Condition {
condition: if_expression,
body: if_block,
},
else_if_members,
else_block,
};
Ok((result, next))
}
}

View File

@ -4,3 +4,4 @@ pub mod expression;
pub mod function_declaration;
pub mod module;
pub mod statement;
pub mod conditional;

View File

@ -1,15 +1,15 @@
use crate::syntax::{
ast::{var_binding::VariableBinding, FunctionDeclaration, Statement},
parseable::{Parseable, ParsingError},
use crate::{
lexic::token::Token,
syntax::{
ast::{var_binding::VariableBinding, Conditional, FunctionDeclaration, Statement},
parseable::{Parseable, ParsingError, ParsingResult},
},
};
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> {
fn try_parse(tokens: &'a Vec<Token>, current_pos: usize) -> ParsingResult<'a, Self::Item> {
// Try to parse a variable binding
match VariableBinding::try_parse(tokens, current_pos) {
Ok((prod, next)) => {
@ -34,6 +34,13 @@ impl<'a> Parseable<'a> for Statement<'a> {
_ => {}
}
// Try to parse a conditional
match Conditional::try_parse(tokens, current_pos) {
Ok((prod, next)) => return Ok((Statement::Conditional(prod), next)),
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
_ => {}
}
// Here nothing was parsed.
Err(ParsingError::Unmatched)
}