Commits

Anonymous committed 3ce03d6

Added some recursion functions

Comments (0)

Files changed (3)

         self.stats = stats
 
 
-    def generate_globalon(self):
+    def generate_globalon(self, opts):
         f = self.create_function([])
+        
+        if opts["numbers"]:
+            gen = self.rng.choice(opts["numbers"])
+            gen.set_rng(self.rng)
+            number = gen()
+        else:
+            number = 1
+        
         f.content.append("global len")
-        f.content.append("len = lambda x : 1")
+        f.content.append("len = lambda x : %s" % (number,))
         return f
 
-    def generate_globaloff(self):
+    def generate_globaloff(self, opts):
         f = self.create_function([])
         f.content.append("global len")
         f.content.append("del len")
 
 
     def generate(self, opts, args_num, globals):
-        fon = self.generate_globalon()
-        foff = self.generate_globaloff()
+        fon = self.generate_globalon(opts)
+        foff = self.generate_globaloff(opts)
 
         self.module.content.insert(0, fon)
         self.module.content.insert(0, foff)
 
         iter_gen = IterableGenerator(self.module, self.stats, self.opts, self.rng)
 
-        iter = iter_gen.get_iterable(["1", "2", "3", "4"])
+        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"]
+
+
+        iter = iter_gen.get_iterable(numbers)
 
         f = self.create_function([])
         f.content.extend(
                         (2.0, "loop_integer"),
                         (1.0, "change_global"),
                         (1.0, "integer_closure"),
+                        (1.0, "tail_recursion"),
                         ],
                 "max_children" : 5,
                 "numbers" : [gen_max_int_gen(), IntegerGen(-1000, 1000)],
                 "numbers" : [gen_max_int_gen(), IntegerGen(-1000, 1000)],
                },
     "change_global" : {
+                "numbers" : [IntegerGen(-10, 10)],
                },
-    "integer_closure" : {},
+    "integer_closure" : {
+                "numbers" : [IntegerGen(-10, 10)]
+               },
+    "tail_recursion" : {
+                "numbers" : [IntegerGen(-10, 10)],
+                "type" : [(1.0, "standard"),(1.0, "closure"),(0.5, "fcall")],
+               },
+
 }
 
 from pygen.cgen import *
 from utils import eval_branches, FunctionGenerator
 from iterables import IterableGenerator, ListComprehensionGenerator 
 from globalsgen import ChangeGlobalGenerator
+from recursion import TailRecursionGenerator
 
 class LoopIntegerGenerator(FunctionGenerator):
     def __init__(self, module, stats, opts, rng):
             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)
+
+
 
     def arith_integer(self, opts, args_num, globals=[]):
         '''Insert a new arithmetic function using only integers'''
         
         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 = [0]",
+                "closure = [%s]" % (number, ),
                 closure,
                 Assignment("func", "=", [closure.name]),
                 "return func",
+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.arith_integer(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, ["20", "0"])]),
+            "return result"])
+        
+        self.module.content.append(func)
+        
+        return func
+