pyfuzz / codegen / recursion.py

 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131``` ```from pygen.cgen import * from arithgen import ArithGen from iterables import IterableGenerator from utils import eval_branches, FunctionGenerator import pgen class TailRecursionGenerator(FunctionGenerator): """ This generates some code to test tail recursion handling. """ def __init__(self, module, stats, opts, rng): self.opts = opts self.module = module self.rng = rng self.stats = stats def generate_standard_tail_call(self, opts): if opts["numbers"]: numbers = [] for i in xrange(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(1, self.rng).generate(["acc", "rest"] + numbers) var = self.next_variable() func.content.append(Assignment(var, '=', [exp])) end = IfStatement("acc == 0", ["return %s" % (var,)], [Assignment("result", "=", [CallStatement(func, ["acc - 1", var])]), "return result"]) func.content.append(end) return func def generate_fcall_tail_call(self, opts): if opts["numbers"]: numbers = [] for i in xrange(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 xrange(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(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 ```