Ejemplo n.º 1
0
def test_map():
    interpret(
        """
        (define inc
            (lambda (x) (+ 1 x)))
    """, env)
    assert_equals("(2 3 4)", interpret("(map inc '(1 2 3))", env))
Ejemplo n.º 2
0
def test_filter():
    interpret("""
        (define even
            (lambda (x)
                (eq (mod x 2) 0)))
    """, env)
    assert_equals("(2 4 6)", interpret("(filter even '(1 2 3 4 5 6))", env))
Ejemplo n.º 3
0
def test_map():
    """Map applies a given function to all elements of a list."""

    interpret("""
        (define inc
            (lambda (x) (+ 1 x)))
    """, env)
    assert_equals("(2 3 4)", interpret("(map inc '(1 2 3))", env))
Ejemplo n.º 4
0
def test_length():
    """Count the number of element in the list.

    Tip: How many elements are there in the empty list?"""

    assert_equals("5", interpret("(length '(1 2 3 4 5))", env))
    assert_equals("3", interpret("(length '(#t '(1 2 3) 'foo-bar))", env))
    assert_equals("0", interpret("(length '())", env))
Ejemplo n.º 5
0
def test_strings_have_heads_and_tails():
    """
    Next, `head` and `tail` needs to extract the first character and the rest
    of the charactes, respectively, from the string.
    """

    assert_equals('"f"', interpret('(head "foobar")'))
    assert_equals('"oobar"', interpret('(tail "foobar")'))
Ejemplo n.º 6
0
def test_filter():
    interpret(
        """
        (define even
            (lambda (x)
                (eq (mod x 2) 0)))
    """, env)
    assert_equals("(2 4 6)", interpret("(filter even '(1 2 3 4 5 6))", env))
Ejemplo n.º 7
0
def test_length():
    """Count the number of element in the list.

    Tip: How many elements are there in the empty list?"""

    assert_equals("5", interpret("(length '(1 2 3 4 5))", env))
    assert_equals("3", interpret("(length '(#t '(1 2 3) 'foo-bar))", env))
    assert_equals("0", interpret("(length '())", env))
Ejemplo n.º 8
0
def test_reverse():
    """Reverse simply outputs the same list with elements in reverse order.

    Tip: See if you might be able to utilize the function you just made."""

    assert_equals("()", interpret("(reverse '())", env))
    assert_equals("(1)", interpret("(reverse '(1))", env))
    assert_equals("(4 3 2 1)", interpret("(reverse '(1 2 3 4))", env))
Ejemplo n.º 9
0
def test_strings_have_heads_and_tails():
    """
    Next, `head` and `tail` needs to extract the first character and the rest
    of the charactes, respectively, from the string.
    """

    assert_equals('"f"', interpret('(head "foobar")'))
    assert_equals('"oobar"', interpret('(tail "foobar")'))
Ejemplo n.º 10
0
def test_range():
    """Output a list with a range of numbers.

    The two arguments define the bounds of the (inclusive) bounds of the range."""

    assert_equals("(1 2 3 4 5)", interpret("(range 1 5)", env))
    assert_equals("(1)", interpret("(range 1 1)", env))
    assert_equals("()", interpret("(range 2 1)", env))
Ejemplo n.º 11
0
def test_range():
    """Output a list with a range of numbers.

    The two arguments define the bounds of the (inclusive) bounds of the range."""

    assert_equals("(1 2 3 4 5)", interpret("(range 1 5)", env))
    assert_equals("(1)", interpret("(range 1 1)", env))
    assert_equals("()", interpret("(range 2 1)", env))
Ejemplo n.º 12
0
def test_append():
    """Append should merge two lists together."""

    assert_equals("()", interpret("(append '() '())", env))
    assert_equals("(1)", interpret("(append '() '(1))", env))
    assert_equals("(2)", interpret("(append '(2) '())", env))
    assert_equals("(1 2 3 4 5)", interpret("(append '(1 2) '(3 4 5))", env))
    assert_equals("(#t #f 'maybe)", interpret("(append '(#t) '(#f 'maybe))", env))
Ejemplo n.º 13
0
def test_reverse():
    """Reverse simply outputs the same list with elements in reverse order.

    Tip: See if you might be able to utilize the function you just made."""

    assert_equals("()", interpret("(reverse '())", env))
    assert_equals("(1)", interpret("(reverse '(1))", env))
    assert_equals("(4 3 2 1)", interpret("(reverse '(1 2 3 4))", env))
Ejemplo n.º 14
0
def test_let_bindings_do_not_affect_outer_environment():
    """
    After the let is evaluated, all of it's bindings are forgotten
    """

    interpret("(define foo 1)", env)

    assert_equals("2", interpret("(let ((foo 2)) foo)", env))
    assert_equals("1", interpret("foo", env))
Ejemplo n.º 15
0
def test_map():
    """Map applies a given function to all elements of a list."""

    interpret(
        """
        (define inc
            (lambda (x) (+ 1 x)))
    """, env)
    assert_equals("(2 3 4)", interpret("(map inc '(1 2 3))", env))
Ejemplo n.º 16
0
def test_filter():
    """Filter removes any element not satisfying a predicate from a list."""

    interpret("""
        (define even
            (lambda (x)
                (eq (mod x 2) 0)))
    """, env)
    assert_equals("(2 4 6)", interpret("(filter even '(1 2 3 4 5 6))", env))
Ejemplo n.º 17
0
def test_let_bindings_do_not_affect_outer_environment():
    """
    After the let is evaluated, all of it's bindings are forgotten
    """

    interpret("(define foo 1)", env)

    assert_equals("2", interpret("(let ((foo 2)) foo)", env))
    assert_equals("1", interpret("foo", env))
Ejemplo n.º 18
0
def test_append():
    """Append should merge two lists together."""

    assert_equals("()", interpret("(append '() '())", env))
    assert_equals("(1)", interpret("(append '() '(1))", env))
    assert_equals("(2)", interpret("(append '(2) '())", env))
    assert_equals("(1 2 3 4 5)", interpret("(append '(1 2) '(3 4 5))", env))
    assert_equals("(#t #f 'maybe)",
                  interpret("(append '(#t) '(#f 'maybe))", env))
Ejemplo n.º 19
0
def test_filter():
    """Filter removes any element not satisfying a predicate from a list."""

    interpret(
        """
        (define even
            (lambda (x)
                (eq (mod x 2) 0)))
    """, env)
    assert_equals("(2 4 6)", interpret("(filter even '(1 2 3 4 5 6))", env))
Ejemplo n.º 20
0
def test_defn_binds_the_variable_just_like_define():
    """
    Like `define`, the `defn` form should bind a variable to the environment.

    This variable should be a closure, just like if we had defined a new
    variable using the old `define` + `lambda` syntax.
    """

    interpret("(defn foo (x) (> x 10))", env)

    assert_is_instance(env.lookup("foo"), Closure)
Ejemplo n.º 21
0
 def test_factorial(self):
     """Simple factorial"""
     env = Environment()
     interpret("""
         (define fact
             (lambda (n)
                 (if (eq n 0)
                     1 
                     (* n (fact (- n 1))))))
     """, env)
     assert_equals("120", interpret("(fact 5)", env))
Ejemplo n.º 22
0
def test_defn_binds_the_variable_just_like_define():
    """
    Like `define`, the `defn` form should bind a variable to the environment.

    This variable should be a closure, just like if we had defined a new
    variable using the old `define` + `lambda` syntax.
    """

    interpret("(defn foo (x) (> x 10))", env)

    assert_is_instance(env.lookup("foo"), Closure)
Ejemplo n.º 23
0
 def test_gcd(self):
     """Greates common dividor"""
     env = Environment()
     interpret("""
         (define gcd
             (lambda (a b)
                 (if (eq b 0)
                     a 
                     (gcd b (mod a b)))))
     """, env)
     assert_equals("6", interpret("(gcd 108 30)", env))
     assert_equals("1", interpret("(gcd 17 5)", env))
Ejemplo n.º 24
0
def test_cond_dosnt_evaluate_all_branches():
    """
    Of all the second tuple elements, only the one we return is ever evaluated.
    """

    interpret("(define foo 42)", env)

    program = """
    (cond ((#f fire-the-missiles)
           (#t foo)
           (#f something-else-we-wont-do)))
    """
    assert_equals("42", interpret(program, env))
Ejemplo n.º 25
0
def test_let_bindings_overshadow_outer_environment():
    """
    Let bindings should shadow definitions in from outer environments
    """

    interpret("(define foo 1)", env)

    program = """
        (let ((foo 2))
             foo)
    """

    assert_equals("2", interpret(program, env))
Ejemplo n.º 26
0
def test_let_bindings_overshadow_outer_environment():
    """
    Let bindings should shadow definitions in from outer environments
    """

    interpret("(define foo 1)", env)

    program = """
        (let ((foo 2))
             foo)
    """

    assert_equals("2", interpret(program, env))
Ejemplo n.º 27
0
def test_empty_strings_behave_as_empty_lists():
    """
    It is common in many languages for strings to behave as lists. This can be
    rather convenient, so let's make it that way here as well.

    We have four basic list functions: `cons`, `head`, `tail` and `empty`.

    To take the easy one first: `empty` should only return `#t` for the empty
    string (and empty lists, as before).
    """

    assert_equals("#t", interpret('(empty "")'))
    assert_equals("#f", interpret('(empty "not empty")'))
Ejemplo n.º 28
0
def test_empty_strings_behave_as_empty_lists():
    """
    It is common in many languages for strings to behave as lists. This can be
    rather convenient, so let's make it that way here as well.

    We have four basic list functions: `cons`, `head`, `tail` and `empty`.

    To take the easy one first: `empty` should only return `#t` for the empty
    string (and empty lists, as before).
    """

    assert_equals("#t", interpret('(empty "")'))
    assert_equals("#f", interpret('(empty "not empty")'))
Ejemplo n.º 29
0
def test_cond_dosnt_evaluate_all_branches():
    """
    Of all the second tuple elements, only the one we return is ever evaluated.
    """

    interpret("(define foo 42)", env)

    program = """
    (cond ((#f fire-the-missiles)
           (#t foo)
           (#f something-else-we-wont-do)))
    """
    assert_equals("42", interpret(program, env))
Ejemplo n.º 30
0
def test_defn_result_in_the_correct_closure():
    """
    The closure created should be no different than from the old syntax.
    """

    interpret("(defn foo-1 (x) (> x 10))", env)
    interpret("(define foo-2 (lambda (x) (> x 10)))", env)

    foo1 = env.lookup("foo-1")
    foo2 = env.lookup("foo-2")

    assert_equals(foo1.body, foo2.body)
    assert_equals(foo1.params, foo2.params)
    assert_equals(foo1.env, foo2.env)
Ejemplo n.º 31
0
def test_defn_result_in_the_correct_closure():
    """
    The closure created should be no different than from the old syntax.
    """

    interpret("(defn foo-1 (x) (> x 10))", env)
    interpret("(define foo-2 (lambda (x) (> x 10)))", env)

    foo1 = env.lookup("foo-1")
    foo2 = env.lookup("foo-2")

    assert_equals(foo1.body, foo2.body)
    assert_equals(foo1.params, foo2.params)
    assert_equals(foo1.env, foo2.env)
Ejemplo n.º 32
0
def repl():
    """Start the interactive Read-Eval-Print-Loop"""
    print()
    print("                 " + faded("                             \`.    T       "))
    print("    Welcome to   " + faded("   .--------------.___________) \   |    T  "))
    print("   the DIY-lisp  " + faded("   |//////////////|___________[ ]   !  T |  "))
    print("       REPL      " + faded("   `--------------'           ) (      | !  "))
    print("                 " + faded("                              '-'      !    "))
    print(faded("  use ^D to exit"))
    print()

    env = Environment()
    interpret_file(join(dirname(relpath(__file__)), '..', 'stdlib.diy'), env)
    while True:
        try:
            source = read_expression()
            print(interpret(source, env))
        except LispError as e:
            print(colored("!", "red"))
            print(faded(str(e.__class__.__name__) + ":"))
            print(str(e))
        except KeyboardInterrupt:
            msg = "Interupted. " + faded("(Use ^D to exit)")
            print("\n" + colored("! ", "red") + msg)
        except EOFError:
            print(faded("\nBye! o/"))
            sys.exit(0)
        except Exception as e:
            print(colored("! ", "red") + faded("The Python is showing through…"))
            print(faded("  " + str(e.__class__.__name__) + ":"))
            print(str(e))
Ejemplo n.º 33
0
def test_gcd():
    """Tests Greates Common Dividor (GCD)."""

    program = """
        (define gcd
            (lambda (a b)
                (if (eq b 0)
                    a 
                    (gcd b (mod a b)))))
    """

    env = Environment()
    interpret(program, env)

    assert_equals("6", interpret("(gcd 108 30)", env))
    assert_equals("1", interpret("(gcd 17 5)", env))
Ejemplo n.º 34
0
def test_evaluating_strings():
    """
    Strings is one of the basic data types, and thus an atom. Strings should
    therefore evaluate to themselves.
    """

    random_quote = '"The limits of my language means the limits of my world."'

    assert_equals(random_quote, interpret(random_quote, env))
Ejemplo n.º 35
0
def test_evaluating_strings():
    """
    Strings is one of the basic data types, and thus an atom. Strings should
    therefore evaluate to themselves.
    """

    random_quote = '"The limits of my language means the limits of my world."'

    assert_equals(random_quote, interpret(random_quote, env))
Ejemplo n.º 36
0
def test_parsing_of_strings():
    """
    A final sanity check, to make sure parsing strings works.

    This test should already pass if you've done the above correctly.
    """

    program = "(head '(#t \"()((()()) wtf \\\" ())) is )))) ()() going on \"))"

    assert_equals("#t", interpret(program))
Ejemplo n.º 37
0
def test_parsing_of_strings():
    """
    A final sanity check, to make sure parsing strings works.

    This test should already pass if you've done the above correctly.
    """

    program = "(head '(#t \"()((()()) wtf \\\" ())) is )))) ()() going on \"))"

    assert_equals("#t", interpret(program))
Ejemplo n.º 38
0
def test_let_returns_result_of_the_given_expression():
    """
    The result when evaluating a `let` binding is the evaluation of the 
    expression given as argument.

    Let's first try one without any bindings.
    """

    program = "(let () (if #t 'yep 'nope))"

    assert_equals("yep", interpret(program, env))
Ejemplo n.º 39
0
def test_gcd():
    """Tests Greates Common Dividor (GCD).

    This test is intended to run after you have completed the core of the 
    language, just to make sure that everything is holding together.
    """

    program = """
        (define gcd
            (lambda (a b)
                (if (eq b 0)
                    a 
                    (gcd b (mod a b)))))
    """

    env = Environment()
    interpret(program, env)

    assert_equals("6", interpret("(gcd 108 30)", env))
    assert_equals("1", interpret("(gcd 17 5)", env))
Ejemplo n.º 40
0
def test_cond_evaluates_predicates():
    """
    Remember to evaluate the predicates before checking whether they are true.
    """

    program = """
    (cond (((not #t) 'totally-not-true)
           ((> 4 3) 'tru-dat)))
    """

    assert_equals("tru-dat", interpret(program, env))
Ejemplo n.º 41
0
def test_let_returns_result_of_the_given_expression():
    """
    The result when evaluating a `let` binding is the evaluation of the 
    expression given as argument.

    Let's first try one without any bindings.
    """

    program = "(let () (if #t 'yep 'nope))"

    assert_equals("yep", interpret(program, env))
Ejemplo n.º 42
0
def test_gcd():
    """Tests Greates Common Dividor (GCD).

    This test is intended to run after you have completed the core of the 
    language, just to make sure that everything is holding together.
    """

    program = """
        (define gcd
            (lambda (a b)
                (if (eq b 0)
                    a 
                    (gcd b (mod a b)))))
    """

    env = Environment()
    interpret(program, env)

    assert_equals("6", interpret("(gcd 108 30)", env))
    assert_equals("1", interpret("(gcd 17 5)", env))
Ejemplo n.º 43
0
def test_cond_evaluates_predicates():
    """
    Remember to evaluate the predicates before checking whether they are true.
    """

    program = """
    (cond (((not #t) 'totally-not-true)
           ((> 4 3) 'tru-dat)))
    """

    assert_equals("tru-dat", interpret(program, env))
Ejemplo n.º 44
0
def test_let_bindings_have_access_to_previous_bindings():
    """
    Each new binding should have access to the previous bindings in the list
    """

    program = """
        (let ((foo 10)
              (bar (+ foo 5)))
             bar)
    """

    assert_equals("15", interpret(program, env))
Ejemplo n.º 45
0
def test_cond_not_evaluating_more_predicateds_than_neccessary():
    """
    Once we find a predicate that evaluates to `#t`, no more predicates should
    be evaluated.
    """

    program = """
    (cond ((#f 1)
           (#t 2)
           (dont-evaluate-me! 3)))
    """
    assert_equals("2", interpret(program, env))
Ejemplo n.º 46
0
def test_let_extends_environment():
    """
    The evaluation of the inner expression should have available the bindings
    provided within the first argument.
    """

    program = """
        (let ((foo (+ 1000 42)))
             foo)
    """

    assert_equals("1042", interpret(program, env))
Ejemplo n.º 47
0
def test_cond_not_evaluating_more_predicateds_than_neccessary():
    """
    Once we find a predicate that evaluates to `#t`, no more predicates should
    be evaluated.
    """

    program = """
    (cond ((#f 1)
           (#t 2)
           (dont-evaluate-me! 3)))
    """
    assert_equals("2", interpret(program, env))
Ejemplo n.º 48
0
def test_let_extends_environment():
    """
    The evaluation of the inner expression should have available the bindings
    provided within the first argument.
    """

    program = """
        (let ((foo (+ 1000 42)))
             foo)
    """

    assert_equals("1042", interpret(program, env))
Ejemplo n.º 49
0
def test_let_bindings_have_access_to_previous_bindings():
    """
    Each new binding should have access to the previous bindings in the list
    """

    program = """
        (let ((foo 10)
              (bar (+ foo 5)))
             bar)
    """

    assert_equals("15", interpret(program, env))
Ejemplo n.º 50
0
def test_reduce():
    """Reduce, also known as fold, reduce a list into a single value.

    It does this by combining elements two by two, untill there is only
    one left.

    If this is unfamiliar to you, have a look at:
    http://en.wikipedia.org/wiki/Fold_(higher-order_function)"""

    interpret("""
        (define max 
            (lambda (a b) 
                (if (> a b) a b)))
    """, env)

    # Evaluates as (max 1 (max 6 (max 3 (max 2 0)))) -> 6
    assert_equals("6", interpret("(reduce max 0 '(1 6 3 2))", env))


    interpret("""
        (define add
            (lambda (a b) (+ a b)))
    """, env)

    # Lets see if we can improve a bit on `sum` while we're at it
    assert_equals("10", interpret("(reduce add 0 (range 1 4))", env))
Ejemplo n.º 51
0
def test_reduce():
    """Reduce, also known as fold, reduce a list into a single value.

    It does this by combining elements two by two, untill there is only
    one left.

    If this is unfamiliar to you, have a look at:
    http://en.wikipedia.org/wiki/Fold_(higher-order_function)"""

    interpret(
        """
        (define max 
            (lambda (a b) 
                (if (> a b) a b)))
    """, env)

    # Evaluates as (max 1 (max 6 (max 3 (max 2 0)))) -> 6
    assert_equals("6", interpret("(reduce max 0 '(1 6 3 2))", env))

    interpret(
        """
        (define add 
            (lambda (a b) (+ a b)))
    """, env)

    # Lets see if we can improve a bit on `sum` while we're at it
    assert_equals("10", interpret("(reduce add 0 (range 1 4))", env))
Ejemplo n.º 52
0
def test_sort():
    assert_equals("()", interpret("'()", env))
    assert_equals("(1)", interpret("'(1)", env))
    assert_equals("(1 2 3 4 5 6 7)", interpret("(sort '(6 3 7 2 4 1 5))", env))
    assert_equals("(1 2 3 4 5 6 7)", interpret("(sort '(1 2 3 4 5 6 7))", env))
    assert_equals("(1 2 3 4 5 6 7)", interpret("(sort '(7 6 5 4 3 2 1))", env))
    assert_equals("(1 1 1)", interpret("(sort '(1 1 1))", env))
Ejemplo n.º 53
0
def test_cond_returnes_false_as_default():
    """
    If we evalaute all the predicates, only to find that none of them turned out 
    to be true, then `cond` should return `#f`.
    """

    program = """
    (cond ((#f 'no)
           (#f 'nope)
           (#f 'i-dont-even)))
    """

    assert_equals("#f", interpret(program, env))
Ejemplo n.º 54
0
def test_cond_returnes_false_as_default():
    """
    If we evalaute all the predicates, only to find that none of them turned out 
    to be true, then `cond` should return `#f`.
    """

    program = """
    (cond ((#f 'no)
           (#f 'nope)
           (#f 'i-dont-even)))
    """

    assert_equals("#f", interpret(program, env))
Ejemplo n.º 55
0
def test_cond_returns_right_branch():
    """
    `cond` takes as arguments a list of tuples (two-element lists, or "conses").

    The first element of each tuple is evaluated in order, until one evaluates 
    to `#t`. The second element of that tuple is returned.
    """

    program = """
    (cond ((#f 'foo)
           (#t 'bar)
           (#f 'baz)))
    """
    assert_equals("bar", interpret(program, env))
Ejemplo n.º 56
0
def test_cond_returns_right_branch():
    """
    `cond` takes as arguments a list of tuples (two-element lists, or "conses").

    The first element of each tuple is evaluated in order, until one evaluates 
    to `#t`. The second element of that tuple is returned.
    """

    program = """
    (cond ((#f 'foo)
           (#t 'bar)
           (#f 'baz)))
    """
    assert_equals("bar", interpret(program, env))
Ejemplo n.º 57
0
def test_sort():
    assert_equals("()", interpret("'()", env))
    assert_equals("(1)", interpret("'(1)", env))
    assert_equals("(1 2 3 4 5 6 7)",
                  interpret("(sort '(6 3 7 2 4 1 5))", env))
    assert_equals("(1 2 3 4 5 6 7)",
                  interpret("(sort '(1 2 3 4 5 6 7))", env))
    assert_equals("(1 2 3 4 5 6 7)",
                  interpret("(sort '(7 6 5 4 3 2 1))", env))
    assert_equals("(1 1 1)",
                  interpret("(sort '(1 1 1))", env))
Ejemplo n.º 58
0
def repl():
    """Start the interactive Read-Eval-Print-Loop"""
    print()
    print("                 " +
          faded("                             \`.    T       "))
    print("    Welcome to   " +
          faded("   .--------------.___________) \   |    T  "))
    print("   the DIY-lisp  " +
          faded("   |//////////////|___________[ ]   !  T |  "))
    print("       REPL      " +
          faded("   `--------------'           ) (      | !  "))
    print("                 " +
          faded("                              '-'      !    "))
    print(faded("  use ^D to exit"))
    print()

    env = Environment()
    interpret_file(join(dirname(relpath(__file__)), '..', 'stdlib.diy'), env)
    while True:
        try:
            source = read_expression()
            print(interpret(source, env))
        except LispError as e:
            print(colored("!", "red"))
            print(faded(str(e.__class__.__name__) + ":"))
            print(str(e))
        except KeyboardInterrupt:
            msg = "Interupted. " + faded("(Use ^D to exit)")
            print("\n" + colored("! ", "red") + msg)
        except EOFError:
            print(faded("\nBye! o/"))
            sys.exit(0)
        except Exception as e:
            print(
                colored("! ", "red") + faded("The Python is showing through…"))
            print(faded("  " + str(e.__class__.__name__) + ":"))
            print(str(e))
Ejemplo n.º 59
0
def test_sum():
    """Calculate the sum of all elements in the list."""

    assert_equals("5", interpret("(sum '(1 1 1 1 1))", env))
    assert_equals("10", interpret("(sum '(1 2 3 4))", env))
    assert_equals("0", interpret("(sum '())", env))