Skip to content

Commit

Permalink
feat: assignment using compound operators
Browse files Browse the repository at this point in the history
  • Loading branch information
fcoury committed Sep 18, 2024
1 parent 6807779 commit c8170c9
Show file tree
Hide file tree
Showing 3 changed files with 191 additions and 4 deletions.
121 changes: 121 additions & 0 deletions core/src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,18 @@ pub enum Token {
Slash,
#[strum(props(regex = r"^="))]
Equal,
#[strum(props(regex = r"^\+="))]
PlusEqual,
#[strum(props(regex = r"^-\="))]
MinusEqual,
#[strum(props(regex = r"^\*="))]
StarEqual,
#[strum(props(regex = r"^/="))]
SlashEqual,
#[strum(props(regex = r"^%="))]
PercentEqual,
#[strum(props(regex = r"^\^="))]
CaretEqual,
#[strum(props(regex = r"^=="))]
EqualEqual,
#[strum(props(regex = r"^!="))]
Expand All @@ -133,6 +145,8 @@ pub enum Token {
Not,
#[strum(props(regex = r"^\*\*"))]
StarStar,
#[strum(props(regex = r"^\^"))]
Caret,
#[strum(props(regex = r"^%"))]
Percent,
#[strum(props(regex = r"^->"))]
Expand Down Expand Up @@ -440,6 +454,23 @@ mod tests {
);
}

#[test]
fn test_caret() {
let program = r#"m := a ^ b"#;
let mut lexer = Lexer::new(program);
let tokens = lexer.tokenize().unwrap();
assert_eq!(
tokens,
vec![
Token::Identifier("m".to_string()),
Token::ColonEqual,
Token::Identifier("a".to_string()),
Token::Caret,
Token::Identifier("b".to_string()),
]
);
}

#[test]
fn test_arrow() {
let program = r#"OBJ->FIELD"#;
Expand Down Expand Up @@ -487,6 +518,96 @@ mod tests {
);
}

#[test]
fn test_compound_plus() {
let program = "a += 1";
let mut lexer = Lexer::new(program);
let tokens = lexer.tokenize().unwrap();
assert_eq!(
tokens,
vec![
Token::Identifier("a".to_string()),
Token::PlusEqual,
Token::Int(1),
]
);
}

#[test]
fn test_compound_minus() {
let program = "a -= 1";
let mut lexer = Lexer::new(program);
let tokens = lexer.tokenize().unwrap();
assert_eq!(
tokens,
vec![
Token::Identifier("a".to_string()),
Token::MinusEqual,
Token::Int(1),
]
);
}

#[test]
fn test_compound_star() {
let program = "a *= 1";
let mut lexer = Lexer::new(program);
let tokens = lexer.tokenize().unwrap();
assert_eq!(
tokens,
vec![
Token::Identifier("a".to_string()),
Token::StarEqual,
Token::Int(1),
]
);
}

#[test]
fn test_compound_slash() {
let program = "a /= 1";
let mut lexer = Lexer::new(program);
let tokens = lexer.tokenize().unwrap();
assert_eq!(
tokens,
vec![
Token::Identifier("a".to_string()),
Token::SlashEqual,
Token::Int(1),
]
);
}

#[test]
fn test_compound_percent() {
let program = "a %= 1";
let mut lexer = Lexer::new(program);
let tokens = lexer.tokenize().unwrap();
assert_eq!(
tokens,
vec![
Token::Identifier("a".to_string()),
Token::PercentEqual,
Token::Int(1),
]
);
}

#[test]
fn test_compound_caret() {
let program = "a ^= 1";
let mut lexer = Lexer::new(program);
let tokens = lexer.tokenize().unwrap();
assert_eq!(
tokens,
vec![
Token::Identifier("a".to_string()),
Token::CaretEqual,
Token::Int(1),
]
);
}

#[test]
fn test_minus_minus() {
let program = r#"--a"#;
Expand Down
73 changes: 69 additions & 4 deletions core/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl<'a> Parser<'a> {
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::StarStar) | Some(Token::Caret) => Some(BinaryOperator::Exponent),
Some(Token::Percent) => Some(BinaryOperator::Modulo),
Some(Token::And) => Some(BinaryOperator::And),
Some(Token::Or) => Some(BinaryOperator::Or),
Expand All @@ -65,7 +65,7 @@ impl<'a> Parser<'a> {
let exp = match self.peek_token() {
Some(Token::Identifier(name)) => {
self.take_token()?; // consumes identifier
if self.peek_token() == Some(Token::ColonEqual) {
if self.is_assignment() {
self.parse_assignment(name)?
} else if self.peek_token() == Some(Token::OpenParens) {
self.parse_fun_call(name)?
Expand All @@ -89,12 +89,77 @@ impl<'a> Parser<'a> {
Ok(exp)
}

fn is_assignment(&self) -> bool {
self.peek_token() == Some(Token::ColonEqual)
|| self.peek_token() == Some(Token::PlusEqual)
|| self.peek_token() == Some(Token::MinusEqual)
|| self.peek_token() == Some(Token::StarEqual)
|| self.peek_token() == Some(Token::SlashEqual)
|| self.peek_token() == Some(Token::PercentEqual)
|| self.peek_token() == Some(Token::CaretEqual)
}

fn parse_assignment(&mut self, name: String) -> anyhow::Result<Exp> {
let var = Exp::Var(name);
self.expect(Token::ColonEqual)?;
let Some(op) = self.next_token()? else {
anyhow::bail!("Expected assignment operator, found end of file");
};
let exp = self.parse_exp()?;

Ok(Exp::Assignment(Box::new(var), Box::new(exp)))
match op {
Token::ColonEqual => Ok(Exp::Assignment(Box::new(var), Box::new(exp))),
Token::PlusEqual => Ok(Exp::Assignment(
Box::new(var.clone()),
Box::new(Exp::Binary(
Box::new(var),
BinaryOperator::Add,
Box::new(exp),
)),
)),
Token::MinusEqual => Ok(Exp::Assignment(
Box::new(var.clone()),
Box::new(Exp::Binary(
Box::new(var),
BinaryOperator::Subtract,
Box::new(exp),
)),
)),
Token::StarEqual => Ok(Exp::Assignment(
Box::new(var.clone()),
Box::new(Exp::Binary(
Box::new(var),
BinaryOperator::Multiply,
Box::new(exp),
)),
)),
Token::SlashEqual => Ok(Exp::Assignment(
Box::new(var.clone()),
Box::new(Exp::Binary(
Box::new(var),
BinaryOperator::Divide,
Box::new(exp),
)),
)),
Token::PercentEqual => Ok(Exp::Assignment(
Box::new(var.clone()),
Box::new(Exp::Binary(
Box::new(var),
BinaryOperator::Modulo,
Box::new(exp),
)),
)),
Token::CaretEqual => Ok(Exp::Assignment(
Box::new(var.clone()),
Box::new(Exp::Binary(
Box::new(var),
BinaryOperator::Exponent,
Box::new(exp),
)),
)),
_ => {
anyhow::bail!("Expected assignment operator, found {op:?}");
}
}
}

fn parse_fun_call(&mut self, name: String) -> anyhow::Result<Exp> {
Expand Down
1 change: 1 addition & 0 deletions samples/operators.prg
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ nVar1 := 2 + 2
nVar2 := 10 - nVar1
nVar3 := -nVar1
nVar4 := ++nVar2
nVar1 /= 2

0 comments on commit c8170c9

Please sign in to comment.