feat: parse conditionals
This commit is contained in:
parent
6ff782a20e
commit
72bd8c50c9
@ -19,6 +19,10 @@
|
|||||||
- Begin work on the code formatter
|
- Begin work on the code formatter
|
||||||
- Remove all panic! and todo!
|
- Remove all panic! and todo!
|
||||||
|
|
||||||
|
## v0.1.2
|
||||||
|
|
||||||
|
- [x] Parse conditionals
|
||||||
|
|
||||||
|
|
||||||
## v0.1.1
|
## v0.1.1
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@ fn str_is_keyword(s: &String) -> Option<TokenType> {
|
|||||||
"val" => Some(TokenType::VAL),
|
"val" => Some(TokenType::VAL),
|
||||||
"var" => Some(TokenType::VAR),
|
"var" => Some(TokenType::VAR),
|
||||||
"fun" => Some(TokenType::FUN),
|
"fun" => Some(TokenType::FUN),
|
||||||
|
"if" => Some(TokenType::IF),
|
||||||
|
"else" => Some(TokenType::ELSE),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,8 @@ pub enum TokenType {
|
|||||||
VAR,
|
VAR,
|
||||||
EOF,
|
EOF,
|
||||||
FUN,
|
FUN,
|
||||||
|
IF,
|
||||||
|
ELSE,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Debug, Clone, PartialEq)]
|
#[derive(Serialize, Debug, Clone, PartialEq)]
|
||||||
|
@ -49,6 +49,7 @@ impl SemanticCheck for FunctionDeclaration<'_> {
|
|||||||
|
|
||||||
return Err(MistiError::Semantic(error));
|
return Err(MistiError::Semantic(error));
|
||||||
}
|
}
|
||||||
|
BlockMember::Stmt(Statement::Conditional(_)) => unimplemented!("check conditional"),
|
||||||
BlockMember::Expr(e) => e.check_semantics(scope)?,
|
BlockMember::Expr(e) => e.check_semantics(scope)?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ impl SemanticCheck for Statement<'_> {
|
|||||||
match self {
|
match self {
|
||||||
Statement::Binding(b) => b.check_semantics(scope),
|
Statement::Binding(b) => b.check_semantics(scope),
|
||||||
Statement::FnDecl(f) => f.check_semantics(scope),
|
Statement::FnDecl(f) => f.check_semantics(scope),
|
||||||
|
Statement::Conditional(_) => unimplemented!("check conditional"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,24 @@ pub enum ModuleMembers<'a> {
|
|||||||
pub enum Statement<'a> {
|
pub enum Statement<'a> {
|
||||||
Binding(VariableBinding<'a>),
|
Binding(VariableBinding<'a>),
|
||||||
FnDecl(FunctionDeclaration<'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)]
|
#[derive(Debug)]
|
||||||
pub struct FunctionDeclaration<'a> {
|
pub struct FunctionDeclaration<'a> {
|
||||||
pub identifier: &'a Token,
|
pub identifier: &'a Token,
|
||||||
|
181
src/syntax/parsers/conditional.rs
Normal file
181
src/syntax/parsers/conditional.rs
Normal 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))
|
||||||
|
}
|
||||||
|
}
|
@ -4,3 +4,4 @@ pub mod expression;
|
|||||||
pub mod function_declaration;
|
pub mod function_declaration;
|
||||||
pub mod module;
|
pub mod module;
|
||||||
pub mod statement;
|
pub mod statement;
|
||||||
|
pub mod conditional;
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
use crate::syntax::{
|
use crate::{
|
||||||
ast::{var_binding::VariableBinding, FunctionDeclaration, Statement},
|
lexic::token::Token,
|
||||||
parseable::{Parseable, ParsingError},
|
syntax::{
|
||||||
|
ast::{var_binding::VariableBinding, Conditional, FunctionDeclaration, Statement},
|
||||||
|
parseable::{Parseable, ParsingError, ParsingResult},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'a> Parseable<'a> for Statement<'a> {
|
impl<'a> Parseable<'a> for Statement<'a> {
|
||||||
type Item = Statement<'a>;
|
type Item = Statement<'a>;
|
||||||
|
|
||||||
fn try_parse(
|
fn try_parse(tokens: &'a Vec<Token>, current_pos: usize) -> ParsingResult<'a, Self::Item> {
|
||||||
tokens: &'a Vec<crate::lexic::token::Token>,
|
|
||||||
current_pos: usize,
|
|
||||||
) -> crate::syntax::parseable::ParsingResult<'a, Self::Item> {
|
|
||||||
// Try to parse a variable binding
|
// Try to parse a variable binding
|
||||||
match VariableBinding::try_parse(tokens, current_pos) {
|
match VariableBinding::try_parse(tokens, current_pos) {
|
||||||
Ok((prod, next)) => {
|
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.
|
// Here nothing was parsed.
|
||||||
Err(ParsingError::Unmatched)
|
Err(ParsingError::Unmatched)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user