예제 #1
0
    def test_calling_builtin_forces_argument_evaluation(self):
        """Bultins (like the regular lambdas) are call-by-value 
        and the arguments thould therefore be evaluated first"""

        env = Environment({
            'x': integer(2), 
            '+': Builtin(lambda a, b: integer(value_of(a) + value_of(b)))
        })
        ast = ['+', ['cond', 
                        [boolean(True), integer(2)], 
                        [boolean(True), 'whatever']], 
                    'x']
        assert_equals(integer(4), evaluate(ast, env))
예제 #2
0
    def test_eq_on_non_atoms(self):
        """Only atoms can equal with eq

        Two lists are not equal (as measured by `eq`) even if they contains
        the same elements."""

        env = Environment()
        ast = ["eq", ["quote", ["foo", "bar"]], ["quote", ["foo", "bar"]]]
        assert_equals(boolean(False), evaluate(ast, env))
예제 #3
0
 def test_parse_comments(self):
     program = """
     ;; this first line is a comment
     (define variable
         ; here is another comment
         (if #t 
             42 ; inline comment!
             (something else)))
     """
     expected_ast = ['define', 'variable', 
                         ['if', boolean(True), integer(42), ['something', 'else']]]
     assert_equals(expected_ast, parse(program))
예제 #4
0
    def test_calling_function_recursively(self):
        """Tests that a named function is included in the environment
        where it is evaluated"""
        
        oposite = """
            (define oposite
                (lambda (p) 
                    (cond (p #f) (#t #t))))
        """
        fn = """ 
            (define fn 
                ;; Meaningless (albeit recursive) function
                (lambda (x) 
                    (cond (x (fn (oposite x)))
                          (#t 1000))))
        """
        
        env = Environment()
        evaluate(parse(oposite), env)
        evaluate(parse(fn), env)

        assert_equals(integer(1000), evaluate(["fn", boolean(True)], env))
        assert_equals(integer(1000), evaluate(["fn", boolean(False)], env))
예제 #5
0
    def test_atom(self):
        env = Environment()
        assert_equals(boolean(True), 
            evaluate(["atom", boolean(True)], env))

        assert_equals(boolean(True), 
            evaluate(["atom", boolean(False)], env))

        assert_equals(boolean(True), 
            evaluate(["atom", integer(42)], env))

        assert_equals(boolean(True), 
            evaluate(["atom", "foo"], Environment({"foo": "bar"})))

        assert_equals(boolean(False), 
            evaluate(["atom", "foo"], Environment({"foo": ["bar"]})))

        assert_equals(boolean(False), 
            evaluate(["atom", ["quote", ["foo", "bar"]]], env))
예제 #6
0
 def test_expand_single_quoted_symbol(self):
     assert_equals(["foo", ["quote", "bar"]], parse("(foo 'bar)"))
     assert_equals(["foo", ["quote", boolean(True)]], parse("(foo '#t)"))
     assert_equals(["foo", ["quote", '+']], parse("(foo '+)"))
예제 #7
0
 def test_parse_with_types(self):
     program = '(if #f (* 42 x) 100)'
     ast = ['if', boolean(False), ['*', integer(42), 'x'], integer(100)]
     assert_equals(ast, parse(program))
예제 #8
0
    def test_define_with_nonsymbol_as_variable(self):
        """Malformed defines should throw an error"""

        with assert_raises_regexp(LispSyntaxError, "non-symbol"):
            evaluate(["define", boolean(True), integer(42)], Environment())
예제 #9
0
 def test_unparse_list(self):
     assert_equals("(1 2 3)", unparse([integer(1), integer(2), integer(3)]))
     assert_equals("(if #t 42 #f)",
         unparse(["if", boolean(True), integer(42), boolean(False)]))
예제 #10
0
 def test_expand_quasiquoted_symbol(self):
     assert_equals(["quasiquote", "foo"], parse("`foo"))
     assert_equals(["quasiquote", "+"], parse("`+"))
     assert_equals(["quasiquote", boolean(False)], parse("`#f"))
예제 #11
0
    def test_set_bang_on_undefined_variable(self):
        """Only defined variables can be updated."""

        with assert_raises_regexp(LispNamingError, "undefined"):
            evaluate(["set!", "wtf", boolean(True)], Environment())
예제 #12
0
 def test_eval_boolean(self):
     assert_equals(boolean(True), evaluate(boolean(True), Environment()))
     assert_equals(boolean(False), evaluate(boolean(False), Environment()))
예제 #13
0
 def test_simple_lookup_from_env(self):
     env = Environment({"foo": integer(42), "bar": boolean(True)})
     assert_equals(integer(42), evaluate("foo", env))
예제 #14
0
 def test_call_to_non_function(self):
     "Should raise a TypeError when a non-closure is called as a function"
     with assert_raises(LispTypeError):
         evaluate([boolean(True), integer(1), integer(2)], Environment())
     with assert_raises(LispTypeError):
         evaluate(["foo", integer(1), integer(2)], Environment({"foo": integer(42)}))
예제 #15
0
 def test_parse_quote_tick_on_atom(self):
     assert_equals(["quote", integer(1)], parse("'1"))
     assert_equals(["quote", boolean(True)], parse("'#t"))
예제 #16
0
    def test_eq_on_two_equal_atoms(self):
        """Two of the same atom are equal"""

        ast = ["eq", ["quote", "foo"], ["quote", "foo"]]
        assert_equals(boolean(True), evaluate(ast, Environment()))
예제 #17
0
 def test_expand_single_quoted_list(self):
     assert_equals(["foo", ["quote", ["+", integer(1), integer(2)]]], 
         parse("(foo '(+ 1 2))"))
     assert_equals(["foo", ["quote", [boolean(True), boolean(False)]]], 
         parse("(foo '(#t #f))"))
예제 #18
0
    def test_eq_on_two_different_atoms(self):
        """Two different atoms are not equal"""

        ast = ["eq", ["quote", "foo"], ["quote", "bar"]]
        assert_equals(boolean(False), evaluate(ast, Environment()))
예제 #19
0
 def test_expand_unquoted_symbol(self):
     assert_equals(["unquote", "foo"], parse(",foo"))
     assert_equals(["unquote", "+"], parse(",+"))
     assert_equals(["unquote", boolean(False)], parse(",#f"))
예제 #20
0
 def test_unparse_bool(self):
     assert_equals("#t", unparse(boolean(True)))
     assert_equals("#f", unparse(boolean(False)))