Skip to content

Commit

Permalink
feat: binary operations
Browse files Browse the repository at this point in the history
  • Loading branch information
fcoury committed Sep 18, 2024
1 parent a9a17d7 commit bc6c375
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 2 deletions.
1 change: 1 addition & 0 deletions core/src/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ pub fn emit_ir(
result
}
Exp::Unary(_, _) => todo!(),
Exp::Binary(_, _, _) => todo!(),
};

Ok(val)
Expand Down
125 changes: 123 additions & 2 deletions core/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,44 @@ impl<'a> Parser<'a> {
}

fn parse_exp(&mut self) -> anyhow::Result<Exp> {
let left = self.parse_lhs()?;

if let Some(op) = self.parse_binary_operator()? {
let right = self.parse_exp()?;
return Ok(Exp::Binary(Box::new(left), op, Box::new(right)));
}

Ok(left)
}

fn parse_binary_operator(&mut self) -> anyhow::Result<Option<BinaryOperator>> {
let res = match self.peek_token() {
Some(Token::Plus) => Some(BinaryOperator::Add),
Some(Token::Minus) => Some(BinaryOperator::Subtract),
Some(Token::Star) => Some(BinaryOperator::Multiply),
Some(Token::Slash) => Some(BinaryOperator::Divide),
Some(Token::StarStar) => Some(BinaryOperator::Exponent),
Some(Token::Percent) => Some(BinaryOperator::Modulo),
Some(Token::And) => Some(BinaryOperator::And),
Some(Token::Or) => Some(BinaryOperator::Or),
Some(Token::Less) => Some(BinaryOperator::LessThan),
Some(Token::LessEqual) => Some(BinaryOperator::LessThanEqual),
Some(Token::Greater) => Some(BinaryOperator::GreaterThan),
Some(Token::GreaterEqual) => Some(BinaryOperator::GreaterThanEqual),
Some(Token::LessGreater) | Some(Token::BangEqual) | Some(Token::Hash) => {
Some(BinaryOperator::NotEqual)
}
_ => None,
};

if res.is_some() {
self.take_token()?;
}

Ok(res)
}

fn parse_lhs(&mut self) -> anyhow::Result<Exp> {
let exp = match self.peek_token() {
Some(Token::Identifier(name)) => {
self.take_token()?; // consumes identifier
Expand All @@ -40,7 +78,7 @@ impl<'a> Parser<'a> {
Exp::Constant(n)
}
Some(_) => {
self.parse_unary()?
self.parse_unary_prefix()?
// anyhow::bail!("Expected expression, found {token:?}");
}
None => {
Expand Down Expand Up @@ -75,9 +113,15 @@ impl<'a> Parser<'a> {
Ok(Exp::FunCall(name, args))
}

fn parse_unary(&mut self) -> anyhow::Result<Exp> {
fn parse_unary_prefix(&mut self) -> anyhow::Result<Exp> {
let operator = match self.next_token()? {
Some(Token::Not) => UnaryOperator::Not,
Some(Token::And) => UnaryOperator::And,
Some(Token::Plus) => UnaryOperator::Positive,
Some(Token::Minus) => UnaryOperator::Negative,
Some(Token::PlusPlus) => UnaryOperator::Increment,
Some(Token::MinusMinus) => UnaryOperator::Decrement,
Some(Token::At) => UnaryOperator::Ref,
Some(token) => {
return Err(anyhow::anyhow!(
"Expected unary operator, found {:?}",
Expand Down Expand Up @@ -150,11 +194,45 @@ pub enum Exp {
Assignment(Box<Exp>, Box<Exp>),
FunCall(String, Vec<Exp>),
Unary(UnaryOperator, Box<Exp>),
Binary(Box<Exp>, BinaryOperator, Box<Exp>),
}

#[derive(Debug, Clone, PartialEq)]
pub enum UnaryOperator {
Not,
And,
Positive,
Negative,
Increment,
Decrement,
Ref,
}

#[derive(Debug, Clone, PartialEq)]
pub enum BinaryOperator {
Add,
Subtract,
Multiply,
Divide,
Exponent,
Modulo,

And,
Or,

LessThan,
LessThanEqual,
GreaterThan,
GreaterThanEqual,
Equal,
NotEqual,

// TODO: implement those
SimpleAssign,
CompoundAssign,
SubstringComparison,
AliasAssignment,
Send,
}

#[cfg(test)]
Expand All @@ -163,6 +241,49 @@ mod tests {

use super::*;

#[test]
fn binary_subtraction() {
let program = r#"nVar2 := 10 - nVar1"#;
let mut lexer = Lexer::new(program);
let tokens = lexer.tokenize().unwrap();
let mut parser = Parser::new(&tokens);
let program = parser.parse().unwrap();

assert_eq!(
program,
Program {
statements: vec![Statement::Expression(Exp::Assignment(
Box::new(Exp::Var("nVar2".into())),
Box::new(Exp::Binary(
Box::new(Exp::Constant(10)),
BinaryOperator::Subtract,
Box::new(Exp::Var("nVar1".into()),)
))
))]
}
);
}

#[test]
fn binary_add() {
let program = r#"2 + 3"#;
let mut lexer = Lexer::new(program);
let tokens = lexer.tokenize().unwrap();
let mut parser = Parser::new(&tokens);
let program = parser.parse().unwrap();

assert_eq!(
program,
Program {
statements: vec![Statement::Expression(Exp::Binary(
Box::new(Exp::Constant(2)),
BinaryOperator::Add,
Box::new(Exp::Constant(3)),
))]
}
);
}

#[test]
fn unary_not() {
let program = r#".NOT. a"#;
Expand Down
4 changes: 4 additions & 0 deletions samples/operators.prg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
nVar1 := 2 + 2
nVar2 := 10 - nVar1
nVar3 := -nVar1
nVar4 := ++nVar2

0 comments on commit bc6c375

Please sign in to comment.