예제 #1
0
 def test_to_cps(self):
     js_raw_ast = JsAst("aa")
     cps_ast = _cps_js_raw(js_raw_ast, lambda x: x)
     self.assertEqual(cps_ast, js_raw_ast)
     atom_ast = LiteralAst(1.0)
     cps_ast = to_cps(atom_ast, lambda x: x)
     self.assertEqual(atom_ast, cps_ast)
     let_ast = LetAst([], LiteralAst(False))
     cps_ast = to_cps(let_ast, lambda x: x)
     self.assertEqual(cps_ast, LiteralAst(False))
     prog_ast = ProgAst([])
     cps_ast = to_cps(prog_ast, lambda x: x)
     self.assertEqual(cps_ast, LiteralAst(False))
     prog_ast = ProgAst([LiteralAst(1)])
     cps_ast = to_cps(prog_ast, lambda x: x)
     self.assertEqual(cps_ast, LiteralAst(1))
     prog_ast = ProgAst([LiteralAst(1), LiteralAst(2)])
     cps_ast = to_cps(prog_ast, lambda x: x)
     self.assertEqual(cps_ast, ProgAst([LiteralAst(1), LiteralAst(2)]))
     if_ast = IfAst(LiteralAst(1), LiteralAst(2), LiteralAst(3))
     cps_ast: CallAst = to_cps(if_ast, lambda x: x)
     expected_ast = CallAst(
         LambdaAst(
             '', cps_ast.func.params,
             IfAst(LiteralAst(1),
                   CallAst(VarAst(cps_ast.func.params[0]), [LiteralAst(2)]),
                   CallAst(VarAst(cps_ast.func.params[0]),
                           [LiteralAst(3)]))), [
                               LambdaAst('', cps_ast.args[0].params,
                                         VarAst(cps_ast.args[0].params[0]))
                           ])
     self.assertEqual(cps_ast, expected_ast)
     lambda_ast = LambdaAst('', ['x', 'y'], LiteralAst(1))
     cps_ast = to_cps(lambda_ast, lambda x: x)
     expected_ast = LambdaAst(
         '', [cps_ast.params[0]] + ['x', 'y'],
         CallAst(VarAst(cps_ast.params[0]), [LiteralAst(1)]))
     self.assertEqual(cps_ast, expected_ast)
     binary_ast = BinaryAst('+', LiteralAst(1), LiteralAst(2))
     cps_ast = to_cps(binary_ast, lambda x: x)
     self.assertEqual(cps_ast, binary_ast)
     parse = Parser(TokenStream(InputStream("a = foo(10);")))
     cps_ast = to_cps(parse(), lambda x: x)
     expected_ast = CallAst(VarAst('foo'), [
         LambdaAst(
             '', [cps_ast.args[0].params[0]],
             AssignAst(VarAst('a'), VarAst(cps_ast.args[0].params[0]))),
         LiteralAst(10)
     ])
     self.assertEqual(cps_ast, expected_ast)
예제 #2
0
 def _optimize_prog_ast(self, ast: ProgAst) -> Ast:
     prog = ast.prog
     if not prog:
         self.changes += 1
         return LiteralAst(False)
     if len(prog) == 1:
         # self.changes += 1
         return self._optimize_aux(prog[0])
     if not has_side_effect(prog[0]):
         self.changes += 1
         return self._optimize_aux(ProgAst(prog[1:]))
     return ProgAst([
         self._optimize_aux(prog[0]),
         self._optimize_aux(ProgAst(prog[1:]))
     ])
예제 #3
0
파일: parse.py 프로젝트: Firkraag/pyLambda
 def _parse_toplevel(self) -> ProgAst:
     prog = []
     while not self._token_stream.eof():
         prog.append(self._parse_expression())
         if not self._token_stream.eof():
             self._skip_punc(";")
     return ProgAst(prog)
예제 #4
0
 def cps_body(body: List[Ast]) -> Ast:
     if not body:
         return k(LiteralAst(False))
     if len(body) == 1:
         return to_cps(body[0], k)
     return to_cps(body[0],
                   lambda first: ProgAst([first, cps_body(body[1:])]))
예제 #5
0
파일: parse.py 프로젝트: Firkraag/pyLambda
 def _parse_prog(self) -> ProgAst:
     """
     If the prog is empty, then it just returns FALSE.
     If it has a single expression, it is returned instead of a "prog" node.
     Otherwise it returns a "prog" node containing the expressions.
     :return:
     """
     prog = self._delimited("{", "}", ";", self._parse_expression)
     # if len(prog) == 0:
     #     return LiteralAst(False)
     # if len(prog) == 1:
     #     return prog[0]
     return ProgAst(prog)
예제 #6
0
 def test__cps_prog(self):
     prog_ast = ProgAst([])
     cps_ast = _cps_prog(prog_ast, lambda x: x)
     self.assertEqual(cps_ast, LiteralAst(False))
     prog_ast = ProgAst([LiteralAst(1)])
     cps_ast = _cps_prog(prog_ast, lambda x: x)
     self.assertEqual(cps_ast, LiteralAst(1))
     prog_ast = ProgAst([LiteralAst(1), LiteralAst(2)])
     cps_ast = _cps_prog(prog_ast, lambda x: x)
     self.assertEqual(cps_ast, ProgAst([
         LiteralAst(1),
         LiteralAst(2),
     ]))
     prog_ast = ProgAst([LiteralAst(1), LiteralAst(2), LiteralAst(3)])
     cps_ast = _cps_prog(prog_ast, lambda x: x)
     self.assertEqual(
         cps_ast,
         ProgAst([LiteralAst(1),
                  ProgAst([LiteralAst(2), LiteralAst(3)])]))
예제 #7
0
    def _unwrap_iife(self, iife_ast: CallAst) -> ProgAst:
        """
        unwrap iife, assign iife func params to iife args,
        then execute iife func body in closure.
        :param iife_ast:
        :return:
        """
        assert isinstance(iife_ast.func, LambdaAst)
        assert isinstance(self.closure, LambdaAst)

        def rename_iife_param(param: str) -> str:
            """
            If iife param collides with closure, rename it.
            :param param:
            :return:
            """
            self.closure = cast(LambdaAst, self.closure)
            env: Environment = self.closure.env
            var_define: VarDefine = iife_func.env.get(param)
            if param in env.vars:
                param = gensym(param + '$')
            self.closure.iife_params.append(param)
            env.define(param, True)
            # change all references to iife params since we may change param names
            for ref in var_define.refs:
                ref.name = param
            return param

        iife_func = iife_ast.func
        iife_args = iife_ast.args
        assert len(iife_func.params) >= len(iife_args)
        prog: List[Ast] = [
            AssignAst(VarAst(rename_iife_param(param)), arg)
            for param, arg in zip_longest(
                iife_func.params, iife_args, fillvalue=LiteralAst(False))
        ]

        prog.append(self._optimize_aux(iife_func.body))
        return ProgAst(prog)
예제 #8
0
 def test_evaluate(self):
     ast = LiteralAst(1.0)
     environment = Environment()
     evaluate(ast, environment, lambda value: self.assertEqual(value, 1.0))
     ast = LiteralAst(True)
     environment = Environment()
     evaluate(ast, environment, self.assertTrue)
     ast = LiteralAst(False)
     environment = Environment()
     evaluate(ast, environment, self.assertFalse)
     ast = LiteralAst("aaa")
     evaluate(ast, Environment(),
              lambda value: self.assertEqual(value, "aaa"))
     ast = BinaryAst('+', LiteralAst(1), LiteralAst(2))
     evaluate(ast, Environment(),
              lambda value: self.assertEqual(value, 3.0))
     ast = ProgAst([])
     evaluate(ast, Environment(), self.assertFalse)
     ast = ProgAst([LiteralAst(1)])
     evaluate(ast, Environment(),
              lambda value: self.assertEqual(value, 1.0))
     ast = ProgAst([LiteralAst(1), LiteralAst(2)])
     evaluate(ast, Environment(),
              lambda value: self.assertEqual(value, 2.0))
     ast = AssignAst(LiteralAst(1), LiteralAst("a"))
     with self.assertRaises(Exception):
         evaluate(ast, Environment(), lambda value: value)
     ast = ProgAst([AssignAst(VarAst('a'), LiteralAst("foo")), VarAst('a')])
     evaluate(ast, Environment(),
              lambda value: self.assertEqual(value, "foo"))
     ast = AssignAst(VarAst("a"), LiteralAst("foo"))
     with self.assertRaises(Exception):
         evaluate(ast, Environment(Environment()), lambda value: value)
     ast = CallAst(
         LambdaAst("", ["a"], VarAst("a")),
         [LiteralAst(1)],
     )
     evaluate(ast, Environment(),
              lambda value: self.assertEqual(value, 1.0))
     ast = CallAst(LambdaAst("", ["a"], VarAst("a")), [LiteralAst("abc")])
     evaluate(ast, Environment(),
              lambda value: self.assertEqual(value, "abc"))
     # # (λ loop (n) if n > 0 then n + loop(n - 1) else 0) (10)
     ast = CallAst(
         LambdaAst(
             "loop", ["n"],
             IfAst(
                 BinaryAst(">", VarAst("n"), LiteralAst(0)),
                 BinaryAst(
                     "+", VarAst("n"),
                     CallAst(VarAst("loop"),
                             [BinaryAst('-', VarAst('n'), LiteralAst(1))])),
                 LiteralAst(0))), [LiteralAst(10)])
     evaluate(ast, Environment(),
              lambda value: self.assertEqual(value, 55.0))
     # # let (x) x;
     ast = LetAst([VarDefAst("x", None)], VarAst("x"))
     evaluate(ast, Environment(), self.assertFalse)
     # # let (x = 2, y = x + 1, z = x + y) x + y + z
     ast = LetAst([
         VarDefAst("x", LiteralAst(2)),
         VarDefAst("y", BinaryAst("+", VarAst("x"), LiteralAst(1))),
         VarDefAst("z", BinaryAst("+", VarAst("x"), VarAst("y")))
     ], BinaryAst("+", BinaryAst("+", VarAst("x"), VarAst("y")),
                  VarAst("z")))
     evaluate(ast, Environment(),
              lambda value: self.assertEqual(value, 10.0))
     # # the second expression will result an errors,
     # since x, y, z are bound to the let body
     # # let (x = 2, y = x + 1, z = x + y) x + y + z; x + y + z
     ast = ProgAst([
         LetAst([
             VarDefAst('x', LiteralAst(2)),
             VarDefAst('y', BinaryAst('+', VarAst('x'), LiteralAst(1))),
             VarDefAst('z', BinaryAst('+', VarAst('x'), VarAst('y')))
         ],
                BinaryAst('+', BinaryAst('+', VarAst('x'), VarAst('y')),
                          VarAst('z'))),
         BinaryAst('+', BinaryAst('+', VarAst('x'), VarAst('y')),
                   VarAst('z'))
     ])
     with self.assertRaises(Exception):
         evaluate(ast, Environment(), lambda value: value)
     ast = IfAst(LiteralAst(""), LiteralAst(1), None)
     evaluate(ast, Environment(),
              lambda value: self.assertEqual(value, 1.0))
     ast = IfAst(LiteralAst(False), LiteralAst(1), LiteralAst(2))
     evaluate(ast, Environment(),
              lambda value: self.assertEqual(value, 2.0))
     ast = IfAst(LiteralAst(False), LiteralAst(1), LiteralAst(False))
     evaluate(ast, Environment(), self.assertFalse)
     ast = {"type": "foo", "value": 'foo'}
     with self.assertRaises(Exception):
         evaluate(ast, Environment(), lambda value: value)
     # fib = λ(n) if n < 2 then n else fib(n - 1) + fib(n - 2);
     # fib(6);
     #
     ast = ProgAst([
         AssignAst(
             VarAst('fib'),
             LambdaAst(
                 'n', ['n'],
                 IfAst(
                     BinaryAst('<', VarAst('n'), LiteralAst(2)),
                     VarAst('n'),
                     BinaryAst(
                         '+',
                         CallAst(
                             VarAst('fib'),
                             [BinaryAst('-', VarAst('n'), LiteralAst(1))]),
                         CallAst(
                             VarAst('fib'),
                             [BinaryAst('-', VarAst('n'), LiteralAst(2))
                              ]))))),
         CallAst(VarAst('fib'), [LiteralAst(6)])
     ])
     evaluate(ast, Environment(),
              lambda value: self.assertEqual(value, 8.0))
     ast = IfAst(LiteralAst(False), LiteralAst(1), LiteralAst(False))
     evaluate(ast, Environment(), self.assertFalse)
     ast = CallAst(LiteralAst(1), [])
     with self.assertRaises(Exception):
         evaluate(ast, Environment(), self.assertFalse)
     code = """
     2 + twice(3, 4)
     """
     global_env = Environment()
     for name, func in primitive.items():
         global_env.define(name, func)
     parser = Parser(TokenStream(InputStream(code)))
     evaluate(parser(), global_env, lambda result: result)
예제 #9
0
 def test_evaluate(self):
     ast = LiteralAst(1.0)
     environment = Environment()
     self.assertEqual(evaluate(ast, environment), 1.0)
     ast = LiteralAst(True)
     environment = Environment()
     self.assertEqual(evaluate(ast, environment), True)
     ast = LiteralAst(False)
     environment = Environment()
     self.assertEqual(evaluate(ast, environment), False)
     ast = LiteralAst("aaa")
     self.assertEqual(evaluate(ast, Environment()), "aaa")
     ast = BinaryAst('+', LiteralAst(1), LiteralAst(2))
     self.assertEqual(evaluate(ast, Environment()), 3.0)
     ast = ProgAst([])
     self.assertEqual(evaluate(ast, Environment()), False)
     ast = ProgAst([LiteralAst(1)])
     self.assertEqual(evaluate(ast, Environment()), 1.0)
     ast = ProgAst([LiteralAst(1), LiteralAst(2)])
     self.assertEqual(evaluate(ast, Environment()), 2.0)
     ast = AssignAst(LiteralAst(1), LiteralAst("a"))
     with self.assertRaises(Exception):
         evaluate(ast, Environment())
     ast = ProgAst([AssignAst(VarAst('a'), LiteralAst("foo")), VarAst('a')])
     self.assertEqual(evaluate(ast, Environment()), "foo")
     ast = AssignAst(VarAst("a"), LiteralAst("foo"))
     with self.assertRaises(Exception):
         evaluate(ast, Environment(Environment()))
     ast = CallAst(
         LambdaAst("", ["a"], VarAst("a")),
         [LiteralAst(1)],
     )
     self.assertEqual(evaluate(ast, Environment()), 1.0)
     ast = CallAst(
         LambdaAst("", ["a"], VarAst("a")),
         [LiteralAst("abc")],
     )
     self.assertEqual(evaluate(ast, Environment()), "abc")
     # (λ loop (n) if n > 0 then n + loop(n - 1) else 0) (10)
     ast = CallAst(
         LambdaAst(
             "loop",
             ["n"],
             IfAst(
                 BinaryAst(">", VarAst("n"), LiteralAst(0)),
                 BinaryAst(
                     "+", VarAst("n"),
                     CallAst(VarAst("loop"),
                             [BinaryAst('-', VarAst('n'), LiteralAst(1))])),
                 LiteralAst(0),
             ),
         ), [LiteralAst(10)])
     self.assertEqual(evaluate(ast, Environment()), 55.0)
     # let (x) x;
     ast = LetAst([VarDefAst("x", None)], VarAst("x"))
     self.assertEqual(evaluate(ast, Environment()), False)
     # let (x = 2, y = x + 1, z = x + y) x + y + z
     ast = LetAst([
         VarDefAst("x", LiteralAst(2)),
         VarDefAst("y", BinaryAst("+", VarAst("x"), LiteralAst(1))),
         VarDefAst("z", BinaryAst("+", VarAst("x"), VarAst("y"))),
     ],
                  BinaryAst(
                      "+",
                      BinaryAst("+", VarAst("x"), VarAst("y")),
                      VarAst("z"),
                  ))
     self.assertEqual(evaluate(ast, Environment()), 10.0)
     # the second expression will result an errors,
     # since x, y, z are bound to the let body
     # let (x = 2, y = x + 1, z = x + y) x + y + z; x + y + z
     ast = ProgAst([
         LetAst(
             [
                 VarDefAst('x', LiteralAst(2)),
                 VarDefAst('y', BinaryAst('+', VarAst('x'), LiteralAst(1))),
                 VarDefAst('z', BinaryAst('+', VarAst('x'), VarAst('y'))),
             ],
             BinaryAst(
                 '+',
                 BinaryAst('+', VarAst('x'), VarAst('y')),
                 VarAst('z'),
             ),
         ),
         BinaryAst(
             '+',
             BinaryAst('+', VarAst('x'), VarAst('y')),
             VarAst('z'),
         ),
     ])
     with self.assertRaises(Exception):
         evaluate(ast, Environment())
     ast = IfAst(
         LiteralAst(""),
         LiteralAst(1),
         None,
     )
     self.assertEqual(evaluate(ast, Environment()), 1.0)
     ast = IfAst(
         LiteralAst(False),
         LiteralAst(1),
         LiteralAst(2),
     )
     self.assertEqual(evaluate(ast, Environment()), 2.0)
     ast = IfAst(
         LiteralAst(False),
         LiteralAst(1),
         LiteralAst(False),
     )
     self.assertEqual(evaluate(ast, Environment()), False)
     ast = {"type": "foo", "value": 'foo'}
     with self.assertRaises(Exception):
         evaluate(ast, Environment())