Browse Source

Implement assign operators (#95) (#97)

* Operators implemented: +=, -=, /=, *=, %=, &=, |=, ^=, <<=, >>=

* Add parser tests for new operators
pull/110/head
Olle Sandberg 5 years ago committed by Jason Williams
parent
commit
d98b42c8bb
  1. 36
      src/lib/exec.rs
  2. 50
      src/lib/syntax/ast/op.rs
  3. 126
      src/lib/syntax/parser.rs

36
src/lib/exec.rs

@ -11,7 +11,7 @@ use crate::{
syntax::ast::{
constant::Const,
expr::{Expr, ExprDef},
op::{BinOp, BitOp, CompOp, LogOp, NumOp, UnaryOp},
op::{AssignOp, BinOp, BitOp, CompOp, LogOp, NumOp, UnaryOp},
},
};
use gc::{Gc, GcCell};
@ -42,6 +42,21 @@ pub struct InterpreterBuilder {
global: Value,
}
fn exec_assign_op(op: &AssignOp, v_a: ValueData, v_b: ValueData) -> Value {
Gc::new(match *op {
AssignOp::Add => v_a + v_b,
AssignOp::Sub => v_a - v_b,
AssignOp::Mul => v_a * v_b,
AssignOp::Div => v_a / v_b,
AssignOp::Mod => v_a % v_b,
AssignOp::And => v_a & v_b,
AssignOp::Or => v_a | v_b,
AssignOp::Xor => v_a ^ v_b,
AssignOp::Shl => v_a << v_b,
AssignOp::Shr => v_a << v_b,
})
}
impl Executor for Interpreter {
fn new() -> Self {
InterpreterBuilder::new().build()
@ -272,6 +287,25 @@ impl Executor for Interpreter {
LogOp::Or => to_value(v_a || v_b),
})
}
ExprDef::BinOp(BinOp::Assign(ref op), ref a, ref b) => match a.def {
ExprDef::Local(ref name) => {
let v_a = (*self.environment.get_binding_value(&name)).clone();
let v_b = (*self.run(b)?).clone();
let value = exec_assign_op(op, v_a, v_b);
self.environment
.set_mutable_binding(&name, value.clone(), true);
Ok(value)
}
ExprDef::GetConstField(ref obj, ref field) => {
let v_r_a = self.run(obj)?;
let v_a = (*v_r_a.borrow().get_field(field)).clone();
let v_b = (*self.run(b)?).clone();
let value = exec_assign_op(op, v_a, v_b.clone());
v_r_a.borrow().set_field(field.clone(), value.clone());
Ok(value)
}
_ => Ok(Gc::new(ValueData::Undefined)),
},
ExprDef::Construct(ref callee, ref args) => {
let func_object = self.run(callee)?;
let mut v_args = Vec::with_capacity(args.len());

50
src/lib/syntax/ast/op.rs

@ -183,6 +183,8 @@ pub enum BinOp {
Comp(CompOp),
/// Logical operation
Log(LogOp),
/// Assign operation
Assign(AssignOp),
}
impl Operator for BinOp {
@ -207,6 +209,7 @@ impl Operator for BinOp {
BinOp::Bit(BitOp::Or) => 12,
BinOp::Log(LogOp::And) => 13,
BinOp::Log(LogOp::Or) => 14,
BinOp::Assign(_) => 15,
}
}
}
@ -221,6 +224,53 @@ impl Display for BinOp {
BinOp::Bit(ref op) => op.to_string(),
BinOp::Comp(ref op) => op.to_string(),
BinOp::Log(ref op) => op.to_string(),
BinOp::Assign(ref op) => op.to_string(),
}
)
}
}
#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
/// A binary operation between 2 values
pub enum AssignOp {
/// `a += b` - Add assign
Add,
/// `a -= b` - Sub assign
Sub,
/// `a *= b` - Mul assign
Mul,
/// `a /= b` - Div assign
Div,
/// `a %= b` - Modulus assign
Mod,
/// `a &= b` - Bitwise and assign
And,
/// `a |= b` - Bitwise or assign
Or,
/// `a ^= b` - Bitwise xor assign
Xor,
/// `a <<= b` - Left shift assign
Shl,
/// `a >>= b` - Right shift assign
Shr,
}
impl Display for AssignOp {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(
f,
"{}",
match *self {
AssignOp::Add => "+=",
AssignOp::Sub => "-=",
AssignOp::Mul => "*=",
AssignOp::Div => "/=",
AssignOp::Mod => "%=",
AssignOp::And => "&=",
AssignOp::Or => "|=",
AssignOp::Xor => "^=",
AssignOp::Shl => "<<=",
AssignOp::Shr => ">>=",
}
)
}

126
src/lib/syntax/parser.rs

@ -1,7 +1,7 @@
use crate::syntax::ast::constant::Const;
use crate::syntax::ast::expr::{Expr, ExprDef};
use crate::syntax::ast::keyword::Keyword;
use crate::syntax::ast::op::{BinOp, BitOp, CompOp, LogOp, NumOp, Operator, UnaryOp};
use crate::syntax::ast::op::{AssignOp, BinOp, BitOp, CompOp, LogOp, NumOp, Operator, UnaryOp};
use crate::syntax::ast::punc::Punctuator;
use crate::syntax::ast::token::{Token, TokenData};
use std::collections::btree_map::BTreeMap;
@ -662,6 +662,36 @@ impl Parser {
let next = self.parse()?;
result = mk!(self, ExprDef::Assign(Box::new(expr), Box::new(next)));
}
TokenData::Punctuator(Punctuator::AssignAdd) => {
result = self.binop(BinOp::Assign(AssignOp::Add), expr)?
}
TokenData::Punctuator(Punctuator::AssignSub) => {
result = self.binop(BinOp::Assign(AssignOp::Sub), expr)?
}
TokenData::Punctuator(Punctuator::AssignMul) => {
result = self.binop(BinOp::Assign(AssignOp::Mul), expr)?
}
TokenData::Punctuator(Punctuator::AssignDiv) => {
result = self.binop(BinOp::Assign(AssignOp::Div), expr)?
}
TokenData::Punctuator(Punctuator::AssignAnd) => {
result = self.binop(BinOp::Assign(AssignOp::And), expr)?
}
TokenData::Punctuator(Punctuator::AssignOr) => {
result = self.binop(BinOp::Assign(AssignOp::Or), expr)?
}
TokenData::Punctuator(Punctuator::AssignXor) => {
result = self.binop(BinOp::Assign(AssignOp::Xor), expr)?
}
TokenData::Punctuator(Punctuator::AssignRightSh) => {
result = self.binop(BinOp::Assign(AssignOp::Shr), expr)?
}
TokenData::Punctuator(Punctuator::AssignLeftSh) => {
result = self.binop(BinOp::Assign(AssignOp::Shl), expr)?
}
TokenData::Punctuator(Punctuator::AssignMod) => {
result = self.binop(BinOp::Assign(AssignOp::Mod), expr)?
}
TokenData::Punctuator(Punctuator::Arrow) => {
self.pos += 1;
let mut args = Vec::with_capacity(1);
@ -1243,5 +1273,99 @@ mod tests {
Expr::new(ExprDef::Local(String::from("b"))),
)],
);
// Check assign ops
check_parser(
"a += b",
&[create_bin_op(
BinOp::Assign(AssignOp::Add),
Expr::new(ExprDef::Local(String::from("a"))),
Expr::new(ExprDef::Local(String::from("b"))),
)],
);
check_parser(
"a -= b",
&[create_bin_op(
BinOp::Assign(AssignOp::Sub),
Expr::new(ExprDef::Local(String::from("a"))),
Expr::new(ExprDef::Local(String::from("b"))),
)],
);
check_parser(
"a *= b",
&[create_bin_op(
BinOp::Assign(AssignOp::Mul),
Expr::new(ExprDef::Local(String::from("a"))),
Expr::new(ExprDef::Local(String::from("b"))),
)],
);
check_parser(
"a /= b",
&[create_bin_op(
BinOp::Assign(AssignOp::Div),
Expr::new(ExprDef::Local(String::from("a"))),
Expr::new(ExprDef::Local(String::from("b"))),
)],
);
check_parser(
"a %= b",
&[create_bin_op(
BinOp::Assign(AssignOp::Mod),
Expr::new(ExprDef::Local(String::from("a"))),
Expr::new(ExprDef::Local(String::from("b"))),
)],
);
check_parser(
"a &= b",
&[create_bin_op(
BinOp::Assign(AssignOp::And),
Expr::new(ExprDef::Local(String::from("a"))),
Expr::new(ExprDef::Local(String::from("b"))),
)],
);
check_parser(
"a |= b",
&[create_bin_op(
BinOp::Assign(AssignOp::Or),
Expr::new(ExprDef::Local(String::from("a"))),
Expr::new(ExprDef::Local(String::from("b"))),
)],
);
check_parser(
"a ^= b",
&[create_bin_op(
BinOp::Assign(AssignOp::Xor),
Expr::new(ExprDef::Local(String::from("a"))),
Expr::new(ExprDef::Local(String::from("b"))),
)],
);
check_parser(
"a <<= b",
&[create_bin_op(
BinOp::Assign(AssignOp::Shl),
Expr::new(ExprDef::Local(String::from("a"))),
Expr::new(ExprDef::Local(String::from("b"))),
)],
);
check_parser(
"a >>= b",
&[create_bin_op(
BinOp::Assign(AssignOp::Shr),
Expr::new(ExprDef::Local(String::from("a"))),
Expr::new(ExprDef::Local(String::from("b"))),
)],
);
check_parser(
"a %= 10 / 2",
&[create_bin_op(
BinOp::Assign(AssignOp::Mod),
Expr::new(ExprDef::Local(String::from("a"))),
create_bin_op(
BinOp::Num(NumOp::Div),
Expr::new(ExprDef::Const(Const::Num(10.0))),
Expr::new(ExprDef::Const(Const::Num(2.0))),
),
)],
);
}
}

Loading…
Cancel
Save