예제 #1
0
 def test_expand_simple_macro_once(self):
     """expand-1 should expand macro call expression once"""
     env = default_env()
     interpret("""(define swp 
                     (macro (foo bar) 
                         (list bar foo)))""", env)
     assert_equals("(42 #t)", interpret("(expand-1 '(swp #t 42))", env))
예제 #2
0
    def test_if_with_variable_lookup(self):
        """Test evaluation of expressions (variable lookup) within if form"""

        env = default_env()
        interpret("(define pred #f)", env)
        interpret("(define else 42)", env)
        assert_equals("42", interpret("(if pred then else)", env))
예제 #3
0
    def test_expanding_recursive_macro(self):
        """Recursive macros just keep on expanding if recursive call is root

        Based on this clojure example:

            user=> (defmacro test [x] `(test ~x))
            #'user/test
            user=> (macroexpand-1 '(test true))
            (user/test true)
            user=> (macroexpand-1 (macroexpand-1 (macroexpand-1 '(test true))))
            (user/test true)
            user=> (macroexpand '(test true))
            StackOverflowError   clojure.lang.ASeq.more (ASeq.java:116)
        """

        env = Environment()
        interpret("""(define test 
                        (macro (x) 
                            `(test ,x)))""", env)
        assert_equals("(test #t)", 
            interpret("(expand-1 '(test #t))", env))  
        assert_equals("(test #t)", 
            interpret("(expand-1 (expand-1 '(test #t)))", env))  
        assert_equals("(test #t)", 
            interpret("(expand-1 (expand-1 (expand-1 '(test #t))))", env))  
예제 #4
0
    def test_creating_lists(self):
        """Test different ways to create lists"""

        xs = "(1 2 #t 4)"
        assert_equals(xs, interpret("(quote (1 2 #t 4))", self.env))
        assert_equals(xs, interpret("(cons 1 (cons 2 (cons #t (cons 4 '()))))", self.env))
        assert_equals(xs, interpret("(list 1 2 #t 4)", self.env))
예제 #5
0
    def test_deconstruction_of_lists(self):
        """Tests picking elements from lists using car and cdr"""

        interpret("(define lst (list 1 2 3 4 5))", self.env)
        assert_equals("1", interpret("(car lst)", self.env))
        assert_equals("2", interpret("(car (cdr lst))", self.env))
        assert_equals("(3 4 5)", interpret("(cdr (cdr lst))", self.env))
예제 #6
0
    def test_arithmetic_functions(self):
        """Sanity check for the builtin artihmetic functions"""

        assert_equals("5", interpret('(+ 2 3)', self.env))
        assert_equals("3", interpret('(- 5 2)', self.env))
        assert_equals("8", interpret('(* 4 2)', self.env))
        assert_equals("8", interpret('(/ 16 2)', self.env))
        assert_equals("1", interpret('(mod 5 2)', self.env))
예제 #7
0
    def test_expand_1_only_expands_once(self):
        """when used on recursive macro, expand-1 only expands once"""

        env = Environment()
        interpret("""(define add-foo 
                        (macro (lst) 
                            `(add-foo (cons foo ,lst))))""", env)
        assert_equals("(add-foo (cons foo nil))", 
            interpret("(expand-1 '(add-foo nil))", env))        
예제 #8
0
 def test_factorial(self):
     """Simple factorial"""
     env = default_env()
     interpret("""
         (define fact
             (lambda (n)
                 (if (<= n 1)
                     1 
                     (* n (fact (- n 1))))))
     """, env)
     assert_equals("120", interpret("(fact 5)", env))
예제 #9
0
    def test_macro_call_expands_macro_then_evaluates_expression(self):
        """A macro call should evaluate as a call to the expanded macro"""

        env = Environment()
        interpret("(define fooify (lambda (x) `(foo foo ,x foo)))", env)
        interpret("""(define test 
                        (macro (foo) 
                            `(fooify ,foo)))""", env)

        assert_equals("(foo foo bar foo)",
            interpret("(test 'bar)", env))  
예제 #10
0
    def IGNORED_test_check_nil_test_fn(self):
        """Test the `nil?` function

        `nil?` returns #t on empty lists, and #f otherwise"""

        env = default_env()
        assert_equals("#t", interpret("(nil? (list))"))
        assert_equals("#t", interpret("(nil? 'nil)"))
        assert_equals("#t", interpret("(nil? (cdr (list 1)))"))

        assert_equals("#f", interpret("(nil? 'foo)"))
        assert_equals("#f", interpret("(nil? (list 'foo 'bar))"))
예제 #11
0
 def test_gcd(self):
     """Greates common dividor"""
     env = default_env()
     interpret("""
         (define gcd
             (lambda (a b)
                 (if (= 0 b)
                     a 
                     (gcd b (mod a b)))))
     """, env)
     assert_equals("6", interpret("(gcd 108 30)", env))
     assert_equals("1", interpret("(gcd 17 5)", env))
예제 #12
0
    def test_expand_expands_until_form_is_not_macro_call(self):
        """Expansion continues until root element of result isn't macro call.

        Clojure example:

            user=> (defmacro unless [pred a b] `(if ~pred ~b ~a))
            #'user/unless
            user=> (defmacro test [x] `(unless ~x 'foo 'bar))
            #'user/test
            user=> (macroexpand-1 '(test true))
            (user/unless true (quote user/foo) (quote user/bar))
            user=> (macroexpand '(test true))
            (if true (quote user/bar) (quote user/foo))
        """
        env = Environment()

        interpret("""(define unless 
                        (macro (pred a b) 
                            `(if ,pred ,b ,a)))""", env)
        interpret("""(define test 
                        (macro (x) 
                            `(unless ,x 'foo 'bar)))""", env)

        assert_equals("(unless #t 'foo 'bar)", 
            interpret("(expand-1 '(test #t))", env))  
        
        assert_equals("(if #t 'bar 'foo)",
            interpret("(expand '(test #t))", env))  
예제 #13
0
    def test_expand_1_on_non_macro_returns_unchanged(self):
        """expand-1, when called with a form that is not a macro call, 
        should return that form"""

        assert_equals("42", interpret("(expand-1 '42)", Environment()))
예제 #14
0
    def test_list_nil(self):
        """Test the predefined nil value"""

        assert_equals(interpret("(quote ())"), interpret("nil"))
        assert_equals("()", interpret("nil"))
예제 #15
0
    def test_comparator_functions(self):
        """Sanity check for the builtin comparators"""

        assert_equals("#f", interpret('(= 2 3)', self.env))
        assert_equals("#t", interpret('(= #t #t)', self.env))
        assert_equals("#f", interpret('(> 1 2)', self.env))
        assert_equals("#t", interpret('(> 2 1)', self.env))
        assert_equals("#t", interpret('(< 1 2)', self.env))
        assert_equals("#f", interpret('(< 2 1)', self.env))
        assert_equals("#t", interpret('(>= 2 1)', self.env))
        assert_equals("#t", interpret('(>= 2 2)', self.env))
        assert_equals("#f", interpret('(>= 2 3)', self.env))
        assert_equals("#f", interpret('(<= 2 1)', self.env))
        assert_equals("#t", interpret('(<= 2 2)', self.env))
        assert_equals("#t", interpret('(<= 2 3)', self.env))
예제 #16
0
 def test_simple_if_statement(self):
     assert_equals("42", interpret("(if #t 42 1000)"))
예제 #17
0
    def test_if_expands_to_cond_statement(self):
        """Test the expansion of an if statement into the corresponding cond"""

        assert_equals("(cond (#t 42) (#t 100))", interpret("(expand-1 '(if #t 42 100))"))