Skip to content

Commit

Permalink
✨ (parser): Add variable declarations
Browse files Browse the repository at this point in the history
semver: minor
  • Loading branch information
Somfic committed Jun 12, 2024
1 parent ce67c27 commit 08e6609
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 27 deletions.
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub mod scanner;
pub mod transpiler;

fn main() -> Result<()> {
let code = "1 * (2 + 3); 'aaaaa'; a + 1 + 2; b * ( a + 3);";
let code = "var x = 1 * (2 + 3); 'aaaaa'; a + 1 + 2; b * ( a + 3);";
let file = SimpleFile::new("main", code);

let tokens = scanner::Scanner::new(code.to_owned()).collect::<Vec<_>>();
Expand Down
34 changes: 15 additions & 19 deletions src/parser/lookup.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
use crate::scanner::lexeme::{Lexeme, TokenType, TokenValue};
use core::panic;
use std::collections::HashMap;

use super::{
ast::{BinaryOperation, Expression, Statement},
macros::{expect_expression, expect_token},
statement::parse_variable_declaration,
Diagnostic, Parser,
statement, Diagnostic, Parser,
};
use crate::scanner::lexeme::{Lexeme, TokenType, TokenValue};
use core::panic;
use std::collections::HashMap;

#[derive(Debug, PartialEq, PartialOrd)]
pub enum BindingPower {
Expand Down Expand Up @@ -70,8 +68,8 @@ impl Default for Lookup {
TokenType::Plus,
BindingPower::Additive,
|parser, cursor, lhs, _binding| {
let (rhs, cursor) =
super::expression::parse(parser, cursor + 1, &BindingPower::Additive)?;
let (_, cursor) = expect_token!(parser, cursor, TokenType::Plus)?;
let (rhs, cursor) = expect_expression!(parser, cursor, &BindingPower::Additive)?;
Ok((
Expression::Binary(Box::new(lhs), BinaryOperation::Plus, Box::new(rhs)),
cursor,
Expand All @@ -83,8 +81,8 @@ impl Default for Lookup {
TokenType::Minus,
BindingPower::Additive,
|parser, cursor, lhs, _binding| {
let (rhs, cursor) =
super::expression::parse(parser, cursor + 1, &BindingPower::Additive)?;
let (_, cursor) = expect_token!(parser, cursor, TokenType::Minus)?;
let (rhs, cursor) = expect_expression!(parser, cursor, &BindingPower::Additive)?;
Ok((
Expression::Binary(Box::new(lhs), BinaryOperation::Minus, Box::new(rhs)),
cursor,
Expand All @@ -97,8 +95,9 @@ impl Default for Lookup {
TokenType::Star,
BindingPower::Multiplicative,
|parser, cursor, lhs, _binding| {
let (_, cursor) = expect_token!(parser, cursor, TokenType::Star)?;
let (rhs, cursor) =
super::expression::parse(parser, cursor + 1, &BindingPower::Multiplicative)?;
expect_expression!(parser, cursor, &BindingPower::Multiplicative)?;
Ok((
Expression::Binary(Box::new(lhs), BinaryOperation::Times, Box::new(rhs)),
cursor,
Expand All @@ -110,8 +109,9 @@ impl Default for Lookup {
TokenType::Slash,
BindingPower::Multiplicative,
|parser, cursor, lhs, _binding| {
let (_, cursor) = expect_token!(parser, cursor, TokenType::Slash)?;
let (rhs, cursor) =
super::expression::parse(parser, cursor + 1, &BindingPower::Multiplicative)?;
expect_expression!(parser, cursor, &BindingPower::Multiplicative)?;
Ok((
Expression::Binary(Box::new(lhs), BinaryOperation::Divide, Box::new(rhs)),
cursor,
Expand Down Expand Up @@ -160,20 +160,16 @@ impl Default for Lookup {
panic!("expect_token! should return a valid token and handle the error case");
});

lookup.add_statement_handler(TokenType::Semicolon, |parser, cursor| {
let (expression, cursor) = expression::parse(parser, cursor, &BindingPower::Primary)?;
let (_, cursor) = expect_token!(parser, cursor, TokenType::Semicolon)?;
Ok((Statement::Expression(expression), cursor))
});

lookup.add_expression_handler(TokenType::ParenOpen, |parser, cursor| {
let (_, cursor) = expect_token!(parser, cursor, TokenType::ParenOpen)?;
let (expression, cursor) = expression::parse(parser, cursor, &BindingPower::None)?;
let (expression, cursor) = expect_expression!(parser, cursor, &BindingPower::None)?;
let (_, cursor) = expect_token!(parser, cursor, TokenType::ParenClose)?;

Ok((Expression::Grouping(Box::new(expression)), cursor))
});

lookup.add_statement_handler(TokenType::Var, statement::parse_declaration);

lookup
}
}
2 changes: 2 additions & 0 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ impl Iterator for Parser {
}
Err(diagnostic) => {
self.cursor += 1;
// TODO: Diagnostic::combine here?
Some(Err(diagnostic))
}
}
Expand All @@ -82,6 +83,7 @@ impl Diagnostic {
}
}

#[allow(dead_code)]
fn combine(diagnostics: Vec<Diagnostic>) -> Diagnostic {
let min_range = diagnostics
.iter()
Expand Down
41 changes: 34 additions & 7 deletions src/parser/statement.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::scanner::lexeme::{Lexeme, Range, TokenType};
use core::panic;

use crate::scanner::lexeme::{Lexeme, Range, TokenType, TokenValue};

use super::{
expression, lookup::BindingPower, macros::expect_token, Diagnostic, Parser, Statement,
Expand All @@ -19,14 +21,39 @@ pub fn parse(parser: &Parser, cursor: usize) -> Result<(Statement, usize), Diagn

let lexeme = lexeme.unwrap();

if let Lexeme::Invalid(_) = lexeme {
return Err(Diagnostic::error(lexeme.range(), "Invalid token"));
}
let token = match lexeme {
Lexeme::Valid(token) => token,
Lexeme::Invalid(_) => return Err(Diagnostic::error(lexeme.range(), "Invalid token")),
};

let (expression, new_cursor) = expression::parse(parser, cursor, &BindingPower::None)?;
let statement_handler = parser.lookup.statement_lookup.get(&token.token_type);

// Expect a semicolon
let (_, cursor) = expect_token!(parser, new_cursor, TokenType::Semicolon)?;
match statement_handler {
Some(statement_handler) => statement_handler(parser, cursor),
None => parse_expression(parser, cursor),
}
}

pub fn parse_expression(parser: &Parser, cursor: usize) -> Result<(Statement, usize), Diagnostic> {
let (expression, cursor) = expression::parse(parser, cursor, &BindingPower::None)?;
let (_, cursor) = expect_token!(parser, cursor, TokenType::Semicolon)?;

Ok((Statement::Expression(expression), cursor))
}

pub fn parse_declaration(parser: &Parser, cursor: usize) -> Result<(Statement, usize), Diagnostic> {
let (_, cursor) = expect_token!(parser, cursor, TokenType::Var)?;
let (identifier, cursor) = expect_token!(parser, cursor, TokenType::Identifier)?;
let identifier = match &identifier.value {
TokenValue::Identifier(identifier) => identifier,
_ => panic!("expect_token! should return a valid token and handle the error case"),
};
let (_, cursor) = expect_token!(parser, cursor, TokenType::Equal)?;
let (expression, cursor) = expression::parse(parser, cursor, &BindingPower::None)?;
let (_, cursor) = expect_token!(parser, cursor, TokenType::Semicolon)?;

Ok((
Statement::Declaration(identifier.clone(), expression),
cursor,
))
}
4 changes: 4 additions & 0 deletions src/transpiler/bend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,9 @@ fn transpile_statement(statement: &Statement) -> String {
let expression = transpile_expression(expression);
format!("{};\n", expression)
}
Statement::Declaration(identifier, expression) => {
let expression = transpile_expression(expression);
format!("let {} = {};\n", identifier, expression)
}
}
}

0 comments on commit 08e6609

Please sign in to comment.