Skip to content

Commit fc97b0a

Browse files
committed
already working
1 parent 9c41cfa commit fc97b0a

File tree

3 files changed

+120
-0
lines changed

3 files changed

+120
-0
lines changed

__init__.py

Whitespace-only changes.

engine.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
from numpy import random
2+
# Mutation operators
3+
# AOR: Arithmetic Operator Replacement: a + b -> a - b
4+
# LCR: Logical Connector Replacement: a and b -> a or b
5+
# ROR: Relational Operator Replacement: a > b -> a < b
6+
# UOI: Unary Operator Insertion: a -> not a (only in conditionals)
7+
# SBR: Statement Block Replacement: stmt -> 0
8+
9+
from typing import Literal, Callable, Any
10+
11+
Node = Any # TODO: fix later
12+
13+
14+
class Converter:
15+
def __init__(self):
16+
pass
17+
18+
def convert_to_div(self, node):
19+
raise NotImplementedError
20+
21+
def convert_to_mult(self, node):
22+
raise NotImplementedError
23+
24+
def convert_to_add(self, node):
25+
raise NotImplementedError
26+
27+
def convert_to_sub(self, node):
28+
raise NotImplementedError
29+
30+
31+
class Engine:
32+
def __init__(self, mutation_rate: float = 0.1, seed=1337):
33+
self.mutation_rate = mutation_rate
34+
self.rng = random.default_rng(seed)
35+
36+
def pick(self, iterable):
37+
return self.rng.choice(iterable)
38+
39+
def mutate(self, node, conv_fn):
40+
if self.rng.random() < self.mutation_rate:
41+
return conv_fn(node)
42+
else:
43+
return node
44+
45+
46+
class Mutator(Converter):
47+
AOR_OPS = ["+", "-", "*", "/"]
48+
49+
def __init__(self, engine: Engine):
50+
self.engine = engine
51+
52+
def mutate_aor(self, node, current: Literal["+", "-", "*", "/"]):
53+
possible = [op for op in self.AOR_OPS if op != current]
54+
picked = self.engine.pick(possible)
55+
56+
conv_fn = None
57+
if picked == "+":
58+
conv_fn = self.convert_to_add
59+
elif picked == "-":
60+
conv_fn = self.convert_to_sub
61+
elif picked == "*":
62+
conv_fn = self.convert_to_mult
63+
elif picked == "/":
64+
conv_fn = self.convert_to_div
65+
else:
66+
raise Exception("Unknown operator")
67+
68+
return self.engine.mutate(node, conv_fn)

python.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import ast
2+
from engine import Mutator, Engine
3+
import astunparse
4+
5+
6+
class PythonMutator(ast.NodeTransformer, Mutator):
7+
def __init__(self, engine: Engine) -> None:
8+
super().__init__(engine)
9+
10+
def convert_to_div(self, node):
11+
return ast.Div()
12+
13+
def convert_to_mult(self, node):
14+
return ast.Mult()
15+
16+
def convert_to_add(self, node):
17+
return ast.Add()
18+
19+
def convert_to_sub(self, node):
20+
return ast.Sub()
21+
22+
def visit_Sub(self, node):
23+
return self.mutate_aor(node, "-")
24+
25+
def visit_Add(self, node):
26+
return self.mutate_aor(node, "+")
27+
28+
def visit_Mult(self, node):
29+
return self.mutate_aor(node, "*")
30+
31+
def visit_Div(self, node):
32+
return self.mutate_aor(node, "/")
33+
34+
35+
if __name__ == "__main__":
36+
import os
37+
CODE = """
38+
def func(a, b):
39+
bleh = 1337
40+
if a > b:
41+
return a - b
42+
elif a < b:
43+
return b - a
44+
else: # a == b
45+
return 0
46+
"""
47+
48+
tree = ast.parse(CODE)
49+
engine = Engine(0.9, int(os.urandom(4).hex(), 16))
50+
mutator = PythonMutator(engine)
51+
tree = mutator.visit(tree)
52+
print(astunparse.unparse(tree))

0 commit comments

Comments
 (0)