Skip to content

Commit

Permalink
syntest handles binary op assign
Browse files Browse the repository at this point in the history
  • Loading branch information
dcodesdev committed Jun 8, 2024
1 parent a245928 commit 11daae8
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 9 deletions.
1 change: 1 addition & 0 deletions crates/syntest/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ mod mutation;
mod syntest;
mod var;

pub use mutation::Mutation;
pub use syntest::Syntest;
pub use var::{LocalVariable, Value};
125 changes: 117 additions & 8 deletions crates/syntest/src/syntest.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::fs;
use std::path::PathBuf;
use std::rc::Rc;
use syn::{parse_file, punctuated::Punctuated, token::PathSep, Expr, Lit, Pat, PathSegment, Stmt};
use syn::{
parse_file, punctuated::Punctuated, token::PathSep, BinOp, Expr, Lit, Pat, PathSegment, Stmt,
};

use crate::{func::Func, mac::Mac, var::LocalVariable, Value};

Expand Down Expand Up @@ -146,6 +148,20 @@ impl Syntest {
Expr::Binary(binary_expr) => {
self.match_expr(&binary_expr.left, variables);
self.match_expr(&binary_expr.right, variables);

if let Expr::Lit(expr_lit) = &*binary_expr.right {
if let Expr::Path(left_expr) = &*binary_expr.left {
let segments = &left_expr.path.segments;
let ident = segments.iter().last().unwrap().ident.to_string();

self.update_value_by_op(
variables,
&ident,
&binary_expr.op,
self.lit_to_usize(&expr_lit.lit),
);
}
};
}
Expr::Path(path_expr) => {
self.set_used_by_segments(variables, &path_expr.path.segments);
Expand All @@ -161,7 +177,7 @@ impl Syntest {
let ident = segments.iter().last().unwrap().ident.to_string();

match &*assign_expr.right {
Expr::Lit(lit) => self.update_value_by_lit(&lit.lit, variables, &ident),
Expr::Lit(lit) => self.replace_value_by_lit(&lit.lit, variables, &ident),
Expr::Path(path_expr) => {
self.set_used_by_segments(variables, &path_expr.path.segments)
}
Expand All @@ -174,7 +190,7 @@ impl Syntest {
}
}

fn update_value_by_lit(&self, lit: &Lit, variables: &mut Vec<LocalVariable>, ident: &str) {
fn replace_value_by_lit(&self, lit: &Lit, variables: &mut Vec<LocalVariable>, ident: &str) {
variables.iter_mut().for_each(|var| {
if ident != var.name() {
return;
Expand All @@ -183,23 +199,61 @@ impl Syntest {
match lit {
Lit::Int(lit_int) => {
let new_value = lit_int.base10_parse().unwrap();
var.update_value(Value::Int(new_value))
var.replace_value(Value::Int(new_value))
}
Lit::Str(lit_str) => {
let new_value = lit_str.value();
var.update_value(Value::Str(new_value))
var.replace_value(Value::Str(new_value))
}
Lit::Float(lit_float) => {
let new_value = lit_float.base10_parse().unwrap();
var.update_value(Value::Float(new_value))
var.replace_value(Value::Float(new_value))
}
Lit::Char(lit_char) => {
let new_value = lit_char.value();
var.update_value(Value::Char(new_value))
var.replace_value(Value::Char(new_value))
}
Lit::Bool(lit_bool) => {
let new_value = lit_bool.value();
var.update_value(Value::Bool(new_value))
var.replace_value(Value::Bool(new_value))
}
_ => {}
}
});
}

fn update_value_by_op(
&self,
variables: &mut Vec<LocalVariable>,
ident: &str,
op: &BinOp,
num: usize,
) {
variables.iter_mut().for_each(|var| {
if ident != var.name() {
return;
};

match op {
BinOp::AddAssign(_) => {
if let Value::Int(value) = var.value() {
var.replace_value(Value::Int(value + num));
}
}
BinOp::SubAssign(_) => {
if let Value::Int(value) = var.value() {
var.replace_value(Value::Int(value - num));
}
}
BinOp::MulAssign(_) => {
if let Value::Int(value) = var.value() {
var.replace_value(Value::Int(value * num));
}
}
BinOp::DivAssign(_) => {
if let Value::Int(value) = var.value() {
var.replace_value(Value::Int(value / num));
}
}
_ => {}
}
Expand Down Expand Up @@ -252,6 +306,13 @@ impl Syntest {
.filter(|var| var.name() == var_name)
.count()
}

fn lit_to_usize(&self, lit: &Lit) -> usize {
match lit {
Lit::Int(lit_int) => lit_int.base10_parse().unwrap(),
_ => 0,
}
}
}

impl From<&str> for Syntest {
Expand Down Expand Up @@ -668,4 +729,52 @@ mod tests {
}
});
}

#[test]
pub fn test_op_equals() {
let content = r#"
pub fn test_fn() {
let mut mutable_var = 10;
mutable_var += 10;
mutable_var -= 5;
mutable_var *= 2;
mutable_var /= 2;
}
"#;

let syntest = Syntest::from_code(content).unwrap();

let vars = syntest.variables("test_fn");

vars.iter().for_each(|var| match var {
LocalVariable::Int {
name,
value,
used,
mutable,
mutations,
} => match name.as_str() {
"mutable_var" => {
assert_eq!(*value, 15);
assert_eq!(*used, true);
assert_eq!(*mutable, true);
assert_eq!(
mutations,
&vec![
Mutation::new(Value::Int(10), Value::Int(20)),
Mutation::new(Value::Int(20), Value::Int(15)),
Mutation::new(Value::Int(15), Value::Int(30)),
Mutation::new(Value::Int(30), Value::Int(15))
]
);
}
_ => {
panic!("Invalid variable name")
}
},
_ => {
panic!("Invalid variable type")
}
});
}
}
28 changes: 27 additions & 1 deletion crates/syntest/src/var.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use proc_macro2::TokenTree;
use std::fmt::Display;
use syn::Lit;

use crate::mutation::Mutation;

Expand Down Expand Up @@ -115,7 +116,7 @@ impl LocalVariable {
}
}

pub fn update_value(&mut self, new_value: Value) {
pub fn replace_value(&mut self, new_value: Value) {
match self {
LocalVariable::Str {
value, mutations, ..
Expand Down Expand Up @@ -168,6 +169,18 @@ impl LocalVariable {
}
}
}

pub fn mutations(&self) -> &Vec<Mutation> {
match self {
LocalVariable::Str { mutations, .. } => mutations,
LocalVariable::Int { mutations, .. } => mutations,
LocalVariable::Float { mutations, .. } => mutations,
LocalVariable::Char { mutations, .. } => mutations,
LocalVariable::Bool { mutations, .. } => mutations,
LocalVariable::Closure { mutations, .. } => mutations,
LocalVariable::Other { mutations, .. } => mutations,
}
}
}

#[derive(Debug, PartialEq, Clone)]
Expand Down Expand Up @@ -201,6 +214,19 @@ impl From<TokenTree> for Value {
}
}

impl From<Lit> for Value {
fn from(lit: Lit) -> Self {
match lit {
Lit::Str(lit) => Value::Str(lit.value()),
Lit::Int(lit) => Value::Int(lit.base10_parse().unwrap()),
Lit::Float(lit) => Value::Float(lit.base10_parse().unwrap()),
Lit::Char(lit) => Value::Char(lit.value()),
Lit::Bool(lit) => Value::Bool(lit.value),
_ => Value::Other,
}
}
}

impl Display for LocalVariable {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name())
Expand Down

0 comments on commit 11daae8

Please sign in to comment.