def generate_fcall_tail_call(self, opts): if opts["numbers"]: numbers = [] for i in range(4): gen = self.rng.choice(opts["numbers"]) gen.set_rng(self.rng) numbers.append(gen()) else: numbers = ["1", "2", "3", "4"] func = self.create_function(["acc", "rest"]) # generate an arith_integer function gen = pgen.ArithIntegerGenerator( self.module, self.stats, self.opts, self.rng) c = gen.generate(self.opts["arith_integer"], 2) self.module.content.insert(0, c) args = self.rng.sample(["acc", "rest"] + numbers, 2) result = self.next_variable() call = Assignment(result, '=', [CallStatement(c, args)]) func.content.append(call) end = IfStatement("acc == 0", ["return %s" % (result,)], [Assignment( "result", "=", [CallStatement(func, ["acc - 1", result])]), "return result"]) func.content.append(end) return func
def generate_closure_tail_call(self, opts): if opts["numbers"]: numbers = [] for i in range(4): gen = self.rng.choice(opts["numbers"]) gen.set_rng(self.rng) numbers.append(gen()) else: numbers = ["1", "2", "3", "4"] func = self.create_function(["acc", "rest"]) exp = ArithGen( 5, self.rng).generate(["closure[0]", "acc", "rest"] + numbers) var = self.next_variable() func.content.append(Assignment(var, '=', [exp])) func.content.append(Assignment("closure[0]", '+=', [var])) end = IfStatement("acc == 0", ["return %s" % (var,)], [Assignment( "result", "=", [CallStatement(func, ["acc - 1", var])]), "return result"]) func.content.append(end) return func
def generate_duck(self, literals): """Generate a duck typing callsite.""" c, m = self.make_class_function() c_super, m_super = self.make_class_function() m_super.name = m.name self.make_fill(m) self.make_fill(m_super) class_var = self.next_variable() clause = self.rng.choice( list( literals)) + " < " + self.rng.choice( list( literals)) i = IfStatement(clause, [Assignment(class_var, '=', [CallStatement(c, [])])], [Assignment( class_var, '=', [CallStatement(c_super, [])])] ) result = [i] l = self.make_loop(literals, class_var, m) result.append(l) return result
def generate(self, args_num, pliterals): """Returns a CallStatement.""" args = self.generate_arguments(args_num) f = self.create_function(args) self.module.content.insert(0, f) literals = list(args) + [ n.set_rng(self.rng) for n in [gen_max_int_gen(), IntegerGen(-1000, 1000)] ] if self.stats.prog_size > 0: self.generate_child(f, literals) for i in range(10): result = self.next_variable() exp = ArithGen(2, self.rng).generate(literals) literals.append(result) f.content.append(Assignment(result, '=', [exp])) f.content.append("yield %s" % (result, )) pargs = self.rng.sample(pliterals, args_num) return CallStatement(f, pargs)
def generate(self, opts, args_num, globals=[], procedure=False): """Insert a new arithmetic function using only integers.""" args = self.generate_arguments(args_num) f = self.create_function(args) literals = set(args) | set(globals) children = min(self.rng.randint(0, opts['max_children']), self.stats.prog_size) if children > 0: self.stats.prog_size -= children for i in range(children): self.generate_child(opts, f, literals) numbers = [n.set_rng(self.rng) for n in opts['numbers']] branch_type = eval_branches(self.rng, opts['type']) if branch_type == 'thin': gen = ArithGen(2, self.rng) for i in range(self.rng.randint(10, 25)): self.generate_statement(opts, f, gen, literals, numbers) if branch_type == 'fat': gen = ArithGen(20, self.rng) for i in range(self.rng.randint(0, 5)): self.generate_statement(opts, f, gen, literals, numbers) exp = ArithGen(10, self.rng).generate(list(literals) + numbers) if not procedure: f.content.append(Assignment('result', '=', [exp])) f.content.append('return result') return f
def generate(self): """Instantiates a new module and fills it randomly.""" self.module = Module(main=True) self.func_number = 1 self.arg_number = 1 lopts = self.opts["module"] self.prog_size = lopts["prog_size"] self.module_size = lopts["module_size"] - self.prog_size while self.module_size > 0 or self.prog_size > 0: main = [] loop = ForLoop('i', ['range(%d)' % (lopts["mainloop"], )], main) if "children" in lopts: branch = eval_branches(self.rng, lopts["children"]) if branch == "arith_integer": main.append(Assignment('x', '=', ['5'])) f = self.arith_integer(self.opts[branch], 2) main.append( Assignment('x', '=', [CallStatement(f, ['x', 'i'])])) main.append("print(x, end='')") self.module.content.insert(0, f) if branch == "arith_float": main.append(Assignment('x', '=', ['5.0'])) main.append("print(x, end='')") self.module.main_body.append( "print('prog_size: %d')" % (lopts["prog_size"] - self.prog_size, )) self.module.main_body.append("print('func_number: %d')" % (self.func_number, )) self.module.main_body.append("print('arg_number: %d')" % (self.arg_number, )) self.module.main_body.append(loop) created_size = lopts["prog_size"] - self.prog_size refill = min(created_size, self.module_size) self.module_size -= refill self.prog_size += refill self.module.content.insert(0, 'from __future__ import print_function') return self.module
def generate(self, opts, args_num, globals): """Insert a new function with a loop containing some integer operations.""" args = self.generate_arguments(args_num) literals = set(args) | set(globals) numbers = [n.set_rng(self.rng) for n in opts['numbers']] f = self.create_function(args) result = self.next_variable() literals.add(result) iter = self.get_iterable(opts, literals) loop_var = self.next_variable() literals.add(loop_var) l = ForLoop(loop_var, iter) if opts['if'] > self.rng.random(): exp1 = ArithGen(1, self.rng).generate(list(literals) + numbers) exp2 = ArithGen(1, self.rng).generate(list(literals) + numbers) clause = ' '.join([ self.rng.choice(list(literals)), '<', self.rng.choice(list(literals)) ]) i = IfStatement(clause, [Assignment(result, '+=', [exp1])], [Assignment(result, '+=', [exp2])]) l.content.append(i) else: exp = ArithGen(1, self.rng).generate(list(literals) + numbers) l.content.append(Assignment(result, '+=', [exp])) f.content.append(Assignment(result, '=', ['0'])) f.content.append(l) f.content.append('return ' + result) return f
def fill_some_arith(self, m): def low_numbers(): return str(self.rng.randint(-1, 1)) numbers = [gen_max_int_gen().set_rng(self.rng), low_numbers] exp = ArithGen(5, self.rng).generate(m.args + numbers) m.content.extend([ Assignment('result', '=', [exp]), 'return result', ])
def generate_statement(self, opts, f, gen, literals, numbers): if opts['if'] > self.rng.random(): result = self.next_variable() exp1 = gen.generate_one_hot_encoded(list(literals) + numbers) exp2 = gen.generate_one_hot_encoded(list(literals) + numbers) clause = self.rng.choice(list(literals)) + ' < ' + self.rng.choice( list(literals)) i = IfStatement(clause, [Assignment(result, '=', [exp1])], [Assignment(result, '=', [exp2])]) f.content.append(i) else: result = self.next_variable() exp = gen.generate_one_hot_encoded(list(literals) + numbers) f.content.append(Assignment(result, '=', [exp])) literals.add(result)
def generate_child(self, func, literals): """Insert a function call to calculate some numbers.""" gen = pgen.ArithIntegerGenerator(self.module, self.stats, self.opts, self.rng) c = gen.generate(self.opts["arith_integer"], 2) self.module.content.insert(0, c) args = self.rng.sample(literals, 2) result = self.next_variable() call = Assignment(result, '=', [CallStatement(c, args)]) func.content.append(call) func.content.append("yield %s" % (result, ))
def generate(self, opts, args_num, globals=[]): """Insert a new arithmetic function using only integers.""" args = self.generate_arguments(args_num) closure = self.create_function(args) gen = self.create_function([]) if opts['numbers']: number_gen = self.rng.choice(opts['numbers']) number_gen.set_rng(self.rng) number = number_gen() else: number = 0 gen.content.extend([ 'closure = [%s]' % (number, ), closure, Assignment('func', '=', [closure.name]), 'return func', ]) c_var = self.next_variable() self.module.content.insert(0, gen) self.module.content.insert( 1, Assignment(c_var, '=', [CallStatement(gen, [])])) gen_ai = ArithIntegerGenerator(self.module, self.stats, self.opts, self.rng) f = gen_ai.generate(self.opts['arith_integer'], args_num, []) self.module.content.insert(0, f) closure.content.append( Assignment('closure[0]', '+=', [CallStatement(f, args)])) closure.content.append('return closure[0]') return c_var
def generate(self, opts, args_num, globals): args = self.generate_arguments(args_num) func = self.create_function(args) branch = eval_branches(self.rng, opts["type"]) if branch == "standard": rec = self.generate_standard_tail_call(opts) elif branch == "closure": func.content.append(Assignment("closure", "=", ["[0]"])) rec = self.generate_closure_tail_call(opts) else: rec = self.generate_fcall_tail_call(opts) func.content.append(rec) func.content.extend( [Assignment("result", "=", [CallStatement(rec, ["10", "0"])]), "return result"]) self.module.content.append(func) return func
def generate_monomorphic(self, literals): """Generates a monomorphic callsite.""" c, m = self.make_class_function() self.make_fill(m) result = [] class_var = self.next_variable() result.append(Assignment(class_var, '=', [CallStatement(c, [])])) l = self.make_loop(literals, class_var, m) result.append(l) return result
def make_loop(self, literals, class_var, m): loop_var = self.next_variable() iter = self.get_iterable(literals) l = ForLoop(loop_var, iter) loop_literals = list(literals) + [loop_var] args = [self.rng.choice(loop_literals) for i in m.args] if self.rng.random() < 0.5: func = class_var + '.' + m.name else: # Sometimes copy the function into a variable func = self.next_variable() l.content.append(Assignment(func, '=', [class_var + '.' + m.name])) l.content.append(CallStatement(func, args)) return l
def generate(self, opts, args_num, globals): fon = self.generate_globalon(opts) foff = self.generate_globaloff(opts) self.module.content.insert(0, fon) self.module.content.insert(0, foff) from . import iterables iter_gen = iterables.IterableGenerator( self.module, self.stats, self.opts, self.rng) if opts["numbers"]: numbers = [] for i in range(4): gen = self.rng.choice(opts["numbers"]) gen.set_rng(self.rng) numbers.append(gen()) else: numbers = ["1", "2", "3", "4"] iter = iter_gen.get_iterable(numbers) f = self.create_function([]) f.content.extend( [ CallStatement(fon, []), Assignment("result", '=', [CallStatement("len", iter)]), CallStatement(foff, []), "return result" ] ) return f
def generate_child(self, opts, f, literals): branch = eval_branches(self.rng, opts['children']) if branch == 'arith_integer': gen = ArithIntegerGenerator(self.module, self.stats, self.opts, self.rng) c = gen.generate(opts, 2) self.module.content.insert(0, c) args = self.rng.sample(list(literals), 2) result = self.next_variable() call = Assignment(result, '=', [CallStatement(c, args)]) f.content.append(call) literals.add(result) if branch == ('arith_integer', 'local'): gen = ArithIntegerGenerator(self.module, self.stats, self.opts, self.rng) c = gen.generate(opts, 2, list(literals)) f.content.append(c) args = self.rng.sample(list(literals), 2) result = self.next_variable() call = Assignment(result, '=', [CallStatement(c, args)]) f.content.append(call) literals.add(result) if branch == 'loop_integer': gen = LoopIntegerGenerator(self.module, self.stats, self.opts, self.rng) c = gen.generate(self.opts['loop_integer'], 2, []) self.module.content.insert(0, c) args = self.rng.sample(list(literals), 2) result = self.next_variable() call = Assignment(result, '=', [CallStatement(c, args)]) f.content.append(call) literals.add(result) if branch == 'change_global': gen = ChangeGlobalGenerator(self.module, self.stats, self.opts, self.rng) c = gen.generate(self.opts['change_global'], 0, []) self.module.content.insert(0, c) result = self.next_variable() call = Assignment(result, '=', [CallStatement(c, [])]) f.content.append(call) literals.add(result) if branch == 'integer_closure': gen = IntegerClosureGenerator(self.module, self.stats, self.opts, self.rng) func = gen.generate(self.opts['integer_closure'], 2, []) args = self.rng.sample(list(literals), 2) result = self.next_variable() call = Assignment(result, '=', [CallStatement(func, args)]) f.content.append(call) literals.add(result) if branch == 'tail_recursion': gen = TailRecursionGenerator(self.module, self.stats, self.opts, self.rng) func = gen.generate(self.opts['tail_recursion'], 2, []) args = self.rng.sample(list(literals), 2) result = self.next_variable() call = Assignment(result, '=', [CallStatement(func, args)]) f.content.append(call) literals.add(result) if branch == 'classes': from . import classes gen = classes.ClassGenerator(self.module, self.stats, self.opts, self.rng) result = gen.generate_inline(literals) f.content.extend(result)