Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#[derive(Debug)]
pub enum BcompError {
ParseError(String),
}

impl std::fmt::Display for BcompError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Generic error occurred")
}
}

impl std::error::Error for BcompError {}
12 changes: 12 additions & 0 deletions src/lexer/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,16 @@ impl Token {
_ => panic!("Not Identifier!"),
}
}

/// Informs on if the current toekn is a comparison token
pub fn is_comparison(&self) -> bool {
match *self {
Self::Equal => true,
Self::Less => true,
Self::LessEqual => true,
Self::Greater => true,
Self::GreaterEqual => true,
_ => false,
}
}
}
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod emitter;
mod error;
mod lexer;
mod parser;

Expand Down
143 changes: 93 additions & 50 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,20 @@
//!
//! This is one of the harder modules to create as I am not familiar with it at all
//! Do not be afraid to modify any of the strucutre I have laid out here
use core::panic;

use crate::{
error::BcompError,
lexer::{
Lexer,
token::{self, Token},
},
parser::ast::{ASTBinaryOperator, ASTBinaryOperatorKind, ASTExpression, ASTStatement},
parser::ast::ExpressionNode,
};
pub mod ast;
mod expressions;
mod nodes;
use expressions::*;

#[allow(dead_code)]
pub struct Parser {
Expand Down Expand Up @@ -45,66 +51,85 @@ impl Parser {
}
}

pub fn next_statement(&mut self) -> Option<ASTStatement> {
self.parse_statement()
}
/// Parses a comparison as a top level expression, since in the order of operations comparisons happen last
fn parse_comparison(&mut self) -> Option<Box<dyn ExpressionNode>> {
let left_side = self.parse_expression()?;

fn parse_statement(&mut self) -> Option<ASTStatement> {
//let token = self.current()?;
let expr = self.parse_expression()?;
Some(ASTStatement::expression(expr))
}
let mut token = self.pop()?;
if token.is_comparison() {
// saves the current operation
let operation = token.clone();

let right_side = self.parse_expression()?;
token = self.pop()?;

fn parse_expression(&mut self) -> Option<ASTExpression> {
self.parse_binary_expression(0)
// Match what our operation was
Some(match operation {
Token::Less => Box::new(LessNode::new(left_side, right_side)),
Token::LessEqual => Box::new(LessEqualNode::new(left_side, right_side)),
Token::Equal => Box::new(EqualNode::new(left_side, right_side)),
Token::Greater => Box::new(GreaterNode::new(left_side, right_side)),
Token::GreaterEqual => Box::new(GreaterEqualNode::new(left_side, right_side)),
_ => panic!("Invalid operation provided"),
})
} else {
None
}
}

fn parse_binary_expression(&mut self, precedence: u8) -> Option<ASTExpression> {
let mut left = self.parse_primary_expression()?;
while let Some(operator) = self.parse_binary_operator() {
self.position += 1;
let operator_precedence = operator.precedence();
if operator_precedence < precedence {
break;
fn parse_expression(&mut self) -> Option<Box<dyn ExpressionNode>> {
let mut left_expression = self.parse_factor()?;

let mut token = self.pop()?;

// while multiplication or divide
while token == token::Token::Plus || token == token::Token::Minus {
let operation = token.clone();
let next_factor = self.parse_factor()?;
match operation {
Token::Star => {
left_expression = Box::new(MultNode::new(left_expression, next_factor))
}
Token::Slash => {
left_expression = Box::new(DivNode::new(left_expression, next_factor))
}
_ => panic!("Unknown factor found"),
}
let right: ASTExpression = self.parse_binary_expression(operator_precedence)?;
left = ASTExpression::binary(operator, left, right);

// grabs next token
token = self.pop()?;
}

Some(left)
Some(left_expression)
}

fn parse_binary_operator(&mut self) -> Option<ASTBinaryOperator> {
let token: Token = self.current()?;
let kind: Option<ASTBinaryOperatorKind> = match token {
token::Token::Plus => Some(ASTBinaryOperatorKind::Plus),
token::Token::Minus => Some(ASTBinaryOperatorKind::Minus),
token::Token::Asterisk => Some(ASTBinaryOperatorKind::Mult),
token::Token::Slash => Some(ASTBinaryOperatorKind::Divide),
_ => None,
};
kind.map(|kind: ASTBinaryOperatorKind| ASTBinaryOperator::new(kind, token.clone()))
}
fn parse_factor(&mut self) -> Option<Box<dyn ExpressionNode>> {
let mut left_factor = self.parse_id()?;

fn parse_primary_expression(&mut self) -> Option<ASTExpression> {
let token: Token = self.current()?;
// match basic expression types
match token {
token::Token::Integer(int) => {
self.position += 1;
Some(ASTExpression::number(int as f64))
}
token::Token::LParen => {
self.position += 1;
let expr: ASTExpression = self.parse_expression()?;
let token: Token = self.current()?;
if token != token::Token::RParen {
panic!("Expected Right Parentheses");
}
self.position += 1;
Some(ASTExpression::paren(expr))
let mut token = self.pop()?;

// while multiplication or divide
while token == token::Token::Star || token == token::Token::Slash {
let operation = token.clone();
let next_factor = self.parse_id()?;
match operation {
Token::Star => left_factor = Box::new(MultNode::new(left_factor, next_factor)),
Token::Slash => left_factor = Box::new(DivNode::new(left_factor, next_factor)),
_ => panic!("Unknown factor found"),
}
_ => None,

// grabs next token
token = self.pop()?;
}

Some(left_factor)
}

fn parse_id(&mut self) -> Option<Box<dyn ExpressionNode>> {
// Current token is right before the id type
match self.pop()? {
Token::Integer(val) => Some(Box::new(IntNode::new(val))),
_ => panic!("Invalid id found"),
}
}

Expand All @@ -115,4 +140,22 @@ impl Parser {
fn current(&self) -> Option<Token> {
self.peek(0)
}

/// Gets the next token an incriments the current position
fn pop(&mut self) -> Option<Token> {
self.position += 1;
self.peek(0)
}

fn expect(&self, token: token::Token) -> Result<(), BcompError> {
if self.current() != Some(token) {
panic!("Uh oh");
Err(BcompError::ParseError(format!(
"Invalid token found at location {}",
self.position
)))
} else {
Ok(())
}
}
}
Loading
Loading