[Syntax] Refactor the expression parser to use ParseResult
This commit is contained in:
parent
e02a95f065
commit
799cda1bf0
@ -17,6 +17,7 @@ impl Transpilable for Expression {
|
||||
}
|
||||
Expression::Boolean(value) => String::from(if *value { "true" } else { "false" }),
|
||||
Expression::Identifier(value) => format!("{}", *value),
|
||||
Expression::FunctionCall(_) => todo!("FunctionCall codegen is not implemented yet"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use self::functions::FunctionCall;
|
||||
|
||||
pub mod functions;
|
||||
pub mod statement;
|
||||
pub mod var_binding;
|
||||
@ -32,4 +34,5 @@ pub enum Expression {
|
||||
String(Box<String>),
|
||||
Boolean(bool),
|
||||
Identifier(Box<String>),
|
||||
FunctionCall(FunctionCall),
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::ast::var_binding::{Binding, ValBinding, VarBinding};
|
||||
use super::utils::{try_operator, parse_token_type};
|
||||
use super::utils::{parse_token_type, try_operator};
|
||||
use super::{expression, ParseResult};
|
||||
use crate::error_handling::SyntaxError;
|
||||
use crate::lexic::token::{Token, TokenType};
|
||||
@ -30,7 +30,8 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Binding,
|
||||
/*
|
||||
* identifier
|
||||
*/
|
||||
let (identifier, next_pos) = match parse_token_type(tokens, current_pos, TokenType::Identifier) {
|
||||
let (identifier, next_pos) = match parse_token_type(tokens, current_pos, TokenType::Identifier)
|
||||
{
|
||||
ParseResult::Ok(t, n) => (t, n),
|
||||
ParseResult::Mismatch(token) => {
|
||||
// The parser found a token, but it's not an identifier
|
||||
@ -38,7 +39,7 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Binding,
|
||||
error_start: token.position,
|
||||
error_end: token.get_end_position(),
|
||||
reason: "??".into(),
|
||||
})
|
||||
});
|
||||
}
|
||||
ParseResult::Err(error) => {
|
||||
return ParseResult::Err(error);
|
||||
@ -60,7 +61,7 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Binding,
|
||||
/*
|
||||
* Equal (=) operator
|
||||
*/
|
||||
let equal_operator: &Token = match try_operator(tokens, current_pos, String::from("=")) {
|
||||
let equal_operator = match try_operator(tokens, current_pos, String::from("=")) {
|
||||
Result3::Ok(t) => t,
|
||||
Result3::Err(t) => {
|
||||
// The parser found a token, but it's not the `=` operator
|
||||
@ -80,15 +81,16 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Binding,
|
||||
}
|
||||
};
|
||||
|
||||
let expression = expression::try_parse(tokens, current_pos + 1);
|
||||
if expression.is_none() {
|
||||
return ParseResult::Err(SyntaxError {
|
||||
reason: String::from("Expected an expression after the equal `=` operator"),
|
||||
error_start: equal_operator.position,
|
||||
error_end: equal_operator.get_end_position(),
|
||||
});
|
||||
}
|
||||
let expression = expression.unwrap();
|
||||
let (expression, _next) = match expression::try_parse(tokens, current_pos + 1) {
|
||||
ParseResult::Ok(exp, next) => (exp, next),
|
||||
_ => {
|
||||
return ParseResult::Err(SyntaxError {
|
||||
reason: String::from("Expected an expression after the equal `=` operator"),
|
||||
error_start: equal_operator.position,
|
||||
error_end: equal_operator.get_end_position(),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let binding = if is_val {
|
||||
Binding::Val(ValBinding {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::ast::Expression;
|
||||
use super::{ast::Expression, ParseResult};
|
||||
use crate::lexic::token::{Token, TokenType};
|
||||
|
||||
/// An expression can be:
|
||||
@ -7,16 +7,36 @@ use crate::lexic::token::{Token, TokenType};
|
||||
/// - A string
|
||||
/// - A boolean
|
||||
/// - An identifier
|
||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> Option<Expression> {
|
||||
tokens.get(pos).and_then(|token| match token.token_type {
|
||||
TokenType::Number => Some(Expression::Number(Box::new(token.value.clone()))),
|
||||
TokenType::String => Some(Expression::String(Box::new(token.value.clone()))),
|
||||
TokenType::Identifier if token.value == "true" || token.value == "false" => {
|
||||
Some(Expression::Boolean(token.value == "true"))
|
||||
}
|
||||
TokenType::Identifier => Some(Expression::Identifier(Box::new(token.value.clone()))),
|
||||
_ => None,
|
||||
})
|
||||
/// - A function call
|
||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
|
||||
/*
|
||||
match function_call::try_parse(tokens, pos) {
|
||||
super::ParseResult::Ok(_, _) => todo!(),
|
||||
super::ParseResult::Err(_) => todo!(),
|
||||
super::ParseResult::Mismatch(_) => todo!(),
|
||||
super::ParseResult::Unmatched => todo!(),
|
||||
}
|
||||
*/
|
||||
|
||||
match tokens.get(pos) {
|
||||
Some(token) => match token.token_type {
|
||||
TokenType::Number => {
|
||||
ParseResult::Ok(Expression::Number(Box::new(token.value.clone())), pos + 1)
|
||||
}
|
||||
TokenType::String => {
|
||||
ParseResult::Ok(Expression::String(Box::new(token.value.clone())), pos + 1)
|
||||
}
|
||||
TokenType::Identifier if token.value == "true" || token.value == "false" => {
|
||||
ParseResult::Ok(Expression::Boolean(token.value == "true"), pos + 1)
|
||||
}
|
||||
TokenType::Identifier => ParseResult::Ok(
|
||||
Expression::Identifier(Box::new(token.value.clone())),
|
||||
pos + 1,
|
||||
),
|
||||
_ => ParseResult::Unmatched,
|
||||
},
|
||||
None => ParseResult::Unmatched,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -27,10 +47,10 @@ mod tests {
|
||||
#[test]
|
||||
fn should_parse_a_number() {
|
||||
let tokens = get_tokens(&String::from("40")).unwrap();
|
||||
let expression = try_parse(&tokens, 0).unwrap();
|
||||
let expression = try_parse(&tokens, 0);
|
||||
|
||||
match expression {
|
||||
Expression::Number(value) => assert_eq!("40", format!("{}", value)),
|
||||
ParseResult::Ok(Expression::Number(value), _) => assert_eq!("40", format!("{}", value)),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
@ -38,10 +58,12 @@ mod tests {
|
||||
#[test]
|
||||
fn should_parse_a_string() {
|
||||
let tokens = get_tokens(&String::from("\"Hello\"")).unwrap();
|
||||
let expression = try_parse(&tokens, 0).unwrap();
|
||||
let expression = try_parse(&tokens, 0);
|
||||
|
||||
match expression {
|
||||
Expression::String(value) => assert_eq!("\"Hello\"", format!("{}", value)),
|
||||
ParseResult::Ok(Expression::String(value), _) => {
|
||||
assert_eq!("\"Hello\"", format!("{}", value))
|
||||
}
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
@ -49,10 +71,10 @@ mod tests {
|
||||
#[test]
|
||||
fn should_parse_a_boolean() {
|
||||
let tokens = get_tokens(&String::from("true")).unwrap();
|
||||
let expression = try_parse(&tokens, 0).unwrap();
|
||||
let expression = try_parse(&tokens, 0);
|
||||
|
||||
match expression {
|
||||
Expression::Boolean(value) => assert!(value),
|
||||
ParseResult::Ok(Expression::Boolean(value), _) => assert!(value),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
@ -60,10 +82,12 @@ mod tests {
|
||||
#[test]
|
||||
fn should_parse_an_identifier() {
|
||||
let tokens = get_tokens(&String::from("someIdentifier")).unwrap();
|
||||
let expression = try_parse(&tokens, 0).unwrap();
|
||||
let expression = try_parse(&tokens, 0);
|
||||
|
||||
match expression {
|
||||
Expression::Identifier(value) => assert_eq!("someIdentifier", format!("{}", value)),
|
||||
ParseResult::Ok(Expression::Identifier(value), _) => {
|
||||
assert_eq!("someIdentifier", format!("{}", value))
|
||||
}
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
@ -17,16 +17,18 @@ use self::ast::TopLevelDeclaration;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ParseResult<A, B> {
|
||||
/// The parsing was a success
|
||||
/// The parsing was a success. The first element is the parsed construct,
|
||||
/// the second element is the position of the next token to parse
|
||||
Ok(A, usize),
|
||||
/// 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),
|
||||
/// A construct different from the one expected was found
|
||||
/// Some special value was expected, but something else was found.
|
||||
/// The inside element is the something else found.
|
||||
Mismatch(B),
|
||||
/// No construct was found
|
||||
/// This parsing didn't succeed, but it's not a fatal error.
|
||||
Unmatched,
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,6 @@ pub fn try_operator(tokens: &Vec<Token>, pos: usize, operator: String) -> Result
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Expects the token at `pos` to be of type `token_type`
|
||||
pub fn parse_token_type(
|
||||
tokens: &Vec<Token>,
|
||||
@ -58,4 +57,3 @@ pub fn parse_token_type(
|
||||
None => ParseResult::Unmatched,
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user