Browse Source

Added *= += -= /= ^= %=

master
Stephen 2 months ago
parent
commit
9d0e24c425
7 changed files with 176 additions and 6 deletions
  1. +23
    -1
      src/compiler.rs
  2. +22
    -0
      src/parser.rs
  3. +27
    -3
      src/scanner.rs
  4. +21
    -1
      src/stmt.rs
  5. +8
    -0
      src/tokens.rs
  6. +3
    -1
      src/visitor.rs
  7. +72
    -0
      tests/arithmetic.rs

+ 23
- 1
src/compiler.rs View File

@ -4,7 +4,8 @@ use crate::expr::{BinaryExpr, CallExpr, ExprValue, LogicalExpr, UnaryExpr, Varia
use crate::function::Function;
use crate::opcodes::OpCode;
use crate::stmt::{
AssignStmt, ExpressionStmt, ForStmt, IfStmt, InputStmt, PrintStmt, ReturnStmt, Stmt, WhileStmt,
AssignStmt, BinaryAssignStmt, ExpressionStmt, ForStmt, IfStmt, InputStmt, PrintStmt,
ReturnStmt, Stmt, WhileStmt,
};
use crate::tokens::{Token, TokenType};
use crate::visitor::{ExprVisitor, StmtVisitor};
@ -270,6 +271,27 @@ impl StmtVisitor<()> for Compiler {
stmt.return_value.accept(self);
self.emit_opcode(OpCode::Ret);
}
fn visit_binary_assign_stmt(&mut self, stmt: &BinaryAssignStmt, _: usize) -> () {
let var_id = self.get_variable(stmt.name.clone());
self.emit_opcode(OpCode::Var);
self.emit_byte(var_id);
stmt.value.accept(self);
self.emit_opcode(match stmt.operator {
TokenType::PlusEqual => OpCode::Add,
TokenType::MinusEqual => OpCode::Sub,
TokenType::StarEqual => OpCode::Mul,
TokenType::SlashEqual => OpCode::Div,
TokenType::CaretEqual => OpCode::Pow,
TokenType::PercentEqual => OpCode::Mod,
_ => unreachable!(),
});
self.emit_opcode(OpCode::SetVar);
self.emit_byte(var_id);
}
}
impl ExprVisitor<()> for Compiler {


+ 22
- 0
src/parser.rs View File

@ -137,6 +137,28 @@ impl<'a> Parser<'a> {
return Some(Stmt::new_assign(identifier, val, equals.line));
}
if [
TokenType::PlusEqual,
TokenType::MinusEqual,
TokenType::StarEqual,
TokenType::SlashEqual,
TokenType::CaretEqual,
TokenType::PercentEqual,
]
.contains(self.peek_next())
{
let identifier = self.advance();
let operator = self.advance();
let val = self.expression()?;
return Some(Stmt::new_binary_assign(
identifier,
operator.token_type,
val,
operator.line,
));
}
self.expression_statement()
}


+ 27
- 3
src/scanner.rs View File

@ -75,6 +75,8 @@ impl<'a> Scanner<'a> {
'-' => {
if self.match_next('-') {
TokenType::MinusMinus
} else if self.match_next('=') {
TokenType::MinusEqual
} else {
TokenType::Minus
}
@ -96,23 +98,45 @@ impl<'a> Scanner<'a> {
'+' => {
if self.match_next('+') {
TokenType::PlusPlus
} else if self.match_next('=') {
TokenType::PlusEqual
} else {
TokenType::Plus
}
}
'*' => TokenType::Star,
'*' => {
if self.match_next('=') {
TokenType::StarEqual
} else {
TokenType::Star
}
}
'/' => {
if self.match_next('/') {
while self.peek() != '\n' && !self.is_at_end() {
self.advance();
}
TokenType::NoToken
} else if self.match_next('=') {
TokenType::SlashEqual
} else {
TokenType::Slash
}
}
'^' => TokenType::Caret,
'%' => TokenType::Percent,
'^' => {
if self.match_next('=') {
TokenType::CaretEqual
} else {
TokenType::Caret
}
}
'%' => {
if self.match_next('=') {
TokenType::PercentEqual
} else {
TokenType::Percent
}
}
'=' => TokenType::Equal,
' ' | '\r' | '\t' => TokenType::NoToken,
'\n' => {


+ 21
- 1
src/stmt.rs View File

@ -1,5 +1,5 @@
use crate::expr::Expr;
use crate::tokens::Token;
use crate::tokens::{Token, TokenType};
use crate::visitor::StmtVisitor;
#[derive(Clone)]
@ -18,6 +18,7 @@ enum StmtContent {
While(WhileStmt),
For(ForStmt),
Return(ReturnStmt),
BinaryAssign(BinaryAssignStmt),
}
impl Stmt {
@ -97,6 +98,17 @@ impl Stmt {
}
}
pub fn new_binary_assign(name: Token, operator: TokenType, value: Expr, line: usize) -> Self {
Self {
line,
content: StmtContent::BinaryAssign(BinaryAssignStmt {
name,
operator,
value,
}),
}
}
pub(crate) fn accept<U, V>(&self, visitor: &mut V) -> U
where
V: StmtVisitor<U>,
@ -111,6 +123,7 @@ impl Stmt {
StmtContent::While(stmt) => visitor.visit_while_stmt(stmt, line),
StmtContent::For(stmt) => visitor.visit_for_stmt(stmt, line),
StmtContent::Return(stmt) => visitor.visit_return_stmt(stmt, line),
StmtContent::BinaryAssign(stmt) => visitor.visit_binary_assign_stmt(stmt, line),
}
}
}
@ -161,3 +174,10 @@ pub(crate) struct ForStmt {
pub(crate) struct ReturnStmt {
pub return_value: Expr,
}
#[derive(Clone)]
pub(crate) struct BinaryAssignStmt {
pub name: Token,
pub operator: TokenType,
pub value: Expr,
}

+ 8
- 0
src/tokens.rs View File

@ -11,6 +11,7 @@ pub enum TokenType {
Dot,
Print,
Input,
PlusPlus,
MinusMinus,
Plus,
@ -19,6 +20,13 @@ pub enum TokenType {
Slash,
Caret,
Percent,
PlusEqual,
MinusEqual,
StarEqual,
SlashEqual,
CaretEqual,
PercentEqual,
LeftBrace,
RightBrace,
LeftParen,


+ 3
- 1
src/visitor.rs View File

@ -1,6 +1,7 @@
use crate::expr::{BinaryExpr, CallExpr, ExprValue, LogicalExpr, UnaryExpr, VariableExpr};
use crate::stmt::{
AssignStmt, ExpressionStmt, ForStmt, IfStmt, InputStmt, PrintStmt, ReturnStmt, WhileStmt,
AssignStmt, BinaryAssignStmt, ExpressionStmt, ForStmt, IfStmt, InputStmt, PrintStmt,
ReturnStmt, WhileStmt,
};
// TODO generate these with macros
@ -14,6 +15,7 @@ pub(crate) trait StmtVisitor<U> {
fn visit_while_stmt(&mut self, stmt: &WhileStmt, line: usize) -> U;
fn visit_for_stmt(&mut self, stmt: &ForStmt, line: usize) -> U;
fn visit_return_stmt(&mut self, stmt: &ReturnStmt, line: usize) -> U;
fn visit_binary_assign_stmt(&mut self, stmt: &BinaryAssignStmt, line: usize) -> U;
}
pub(crate) trait ExprVisitor<U> {


+ 72
- 0
tests/arithmetic.rs View File

@ -61,3 +61,75 @@ fn modulus() {
common::test_program("print 1.5 % 1.6\n", "1.5\n");
common::test_program("print 1.5 % 1.4\n", "0.10000000000000009\n");
}
#[test]
fn add_equal() {
common::test_program(
"
a = 2
a += 3
print a
",
"5\n",
);
}
#[test]
fn sub_equal() {
common::test_program(
"
a = 2
a -= 3
print a
",
"-1\n",
);
}
#[test]
fn mul_equal() {
common::test_program(
"
a = 2
a *= 3
print a
",
"6\n",
);
}
#[test]
fn div_equal() {
common::test_program(
"
a = 6
a /= 3
print a
",
"2\n",
);
}
#[test]
fn pow_equal() {
common::test_program(
"
a = 2
a ^= 3
print a
",
"8\n",
);
}
#[test]
fn mod_equal() {
common::test_program(
"
a = 8
a %= 3
print a
",
"2\n",
);
}

Loading…
Cancel
Save