Parsing and lexing multiply, divide, modulo, shift operators.

This commit is contained in:
Jesse Brault 2026-03-15 13:41:07 -05:00
parent 4a0a6b8425
commit f0c84fe0c8
4 changed files with 137 additions and 4 deletions

View File

@ -18,8 +18,11 @@ use std::rc::Rc;
pub enum BinaryOperation {
Multiply,
Divide,
Modulo,
Add,
Subtract,
LeftShift,
RightShift,
}
pub struct BinaryExpression {
@ -137,6 +140,9 @@ impl BinaryExpression {
BinaryOperation::Divide => {
todo!()
}
BinaryOperation::Modulo => {
todo!()
}
BinaryOperation::Add => {
handle_diagnostic!(
self.check_op(
@ -160,6 +166,8 @@ impl BinaryExpression {
diagnostics
)
}
BinaryOperation::LeftShift => todo!(),
BinaryOperation::RightShift => todo!(),
}
diagnostics_result!(diagnostics)
@ -183,10 +191,13 @@ impl BinaryExpression {
IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Multiply)
}
BinaryOperation::Divide => IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Divide),
BinaryOperation::Modulo => todo!(),
BinaryOperation::Add => IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Add),
BinaryOperation::Subtract => {
IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Subtract)
}
BinaryOperation::LeftShift => todo!(),
BinaryOperation::RightShift => todo!(),
};
IrOperation::Binary(ir_binary_operation)
}

View File

@ -46,8 +46,18 @@ impl<'a> Lexer<'a> {
self.position + 1,
TokenKind::RightParentheses,
)
} else if chunk.starts_with("*") {
Token::new(self.position, self.position + 1, TokenKind::Star)
} else if chunk.starts_with("/") {
Token::new(self.position, self.position + 1, TokenKind::Slash)
} else if chunk.starts_with("%") {
Token::new(self.position, self.position + 1, TokenKind::Modulo)
} else if chunk.starts_with("+") {
Token::new(self.position, self.position + 1, TokenKind::Plus)
} else if chunk.starts_with("<<") {
Token::new(self.position, self.position + 2, TokenKind::LeftShift)
} else if chunk.starts_with(">>") {
Token::new(self.position, self.position + 2, TokenKind::RightShift)
} else if chunk.starts_with("=") {
Token::new(self.position, self.position + 1, TokenKind::Equals)
} else if chunk.starts_with(",") {

View File

@ -662,17 +662,52 @@ impl<'a> Parser<'a> {
}
fn expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
self.additive_expression()
self.shift_expression()
}
fn shift_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
let mut result = self.additive_expression()?;
while self.current.is_some() {
let current = self.get_current();
match current.kind() {
TokenKind::LeftShift => {
self.advance(); // left shift
let rhs = self.additive_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
result = Expression::Binary(BinaryExpression::new(
result,
rhs,
BinaryOperation::LeftShift,
source_range,
));
}
TokenKind::RightShift => {
self.advance(); // right shift
let rhs = self.additive_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
result = Expression::Binary(BinaryExpression::new(
result,
rhs,
BinaryOperation::RightShift,
source_range,
));
}
_ => break,
}
}
Ok(result)
}
fn additive_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
let mut result = self.prefix_expression()?;
let mut result = self.multiplicative_expression()?;
while self.current.is_some() {
let current = self.get_current();
match current.kind() {
TokenKind::Plus => {
self.advance(); // plus
let rhs = self.prefix_expression()?;
let rhs = self.multiplicative_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
result = Expression::Binary(BinaryExpression::new(
@ -684,7 +719,7 @@ impl<'a> Parser<'a> {
}
TokenKind::Minus => {
self.advance(); // minus
let rhs = self.prefix_expression()?;
let rhs = self.multiplicative_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
result = Expression::Binary(BinaryExpression::new(
@ -700,6 +735,53 @@ impl<'a> Parser<'a> {
Ok(result)
}
fn multiplicative_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
let mut result = self.prefix_expression()?;
while self.current.is_some() {
let current = self.get_current();
match current.kind() {
TokenKind::Star => {
self.advance(); // multiply
let rhs = self.prefix_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
result = Expression::Binary(BinaryExpression::new(
result,
rhs,
BinaryOperation::Multiply,
source_range,
));
}
TokenKind::Slash => {
self.advance(); // slash
let rhs = self.prefix_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
result = Expression::Binary(BinaryExpression::new(
result,
rhs,
BinaryOperation::Divide,
source_range,
))
}
TokenKind::Modulo => {
self.advance(); // modulo
let rhs = self.prefix_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
result = Expression::Binary(BinaryExpression::new(
result,
rhs,
BinaryOperation::Modulo,
source_range,
));
}
_ => break,
}
}
Ok(result)
}
fn prefix_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
// first, collect all consecutive operators
let mut operator_tokens = vec![];
@ -960,6 +1042,31 @@ mod smoke_tests {
",
);
}
#[test]
fn simple_multiply() {
smoke_test("fn main() 1 * 2 end");
}
#[test]
fn simple_divide() {
smoke_test("fn main() 1 / 2 end");
}
#[test]
fn simple_modulo() {
smoke_test("fn main() 1 % 2 end");
}
#[test]
fn simple_left_shift() {
smoke_test("fn main() 2 << 1 end");
}
#[test]
fn simple_right_shift() {
smoke_test("fn main() 4 >> 1 end");
}
}
#[cfg(test)]

View File

@ -42,6 +42,11 @@ pub enum TokenKind {
RightArrow,
Plus,
Minus,
Star,
Slash,
Modulo,
LeftShift,
RightShift,
Class,
Dot,
SelfKw,