Beispiel #1
0
def test_set():
    """Ensure set mutates bindings."""
    env = prelude.env()

    # ensure we can't set non-existent bindings
    bad_call = wtypes.List(
        [wtypes.Integer(1),
         wtypes.Symbol('x'),
         wtypes.Symbol('set!')])
    with pytest.raises(exceptions.WispException):
        assert bad_call.eval(env)

    # ensure we can set previously-existent bindings
    define_call = wtypes.List(
        [wtypes.Integer(1),
         wtypes.Symbol('x'),
         wtypes.Symbol('define')])
    define_call.eval(env)
    assert wtypes.Symbol('x').eval(env) == wtypes.Integer(1)

    set_call = wtypes.List(
        [wtypes.Integer(2),
         wtypes.Symbol('x'),
         wtypes.Symbol('set!')])
    set_call.eval(env)
    assert wtypes.Symbol('x').eval(env) == wtypes.Integer(2)
Beispiel #2
0
def test_begin():
    """Ensure begin return the last expression."""
    env = prelude.env()
    call = wtypes.List([
        wtypes.List([
            wtypes.Integer(1),
            wtypes.Integer(2),
            wtypes.Symbol('+'),
        ]),
        wtypes.List([
            wtypes.Integer(1),
            wtypes.Integer(1),
            wtypes.Symbol('+'),
        ]),
        wtypes.Symbol('begin')
    ])
    assert call.eval(env) == wtypes.Integer(3)
Beispiel #3
0
def cons(args: typing.List[wtypes.Expression],
         env: wisp.env.Environment) -> wtypes.List:
    """Attach the first argument to the head of the list in the second."""
    head, rest = args
    if isinstance(rest, wtypes.List):
        return wtypes.List([head] + rest.items)
    else:
        raise exceptions.type_error(wtypes.List, rest)
Beispiel #4
0
def test_cond():
    """Ensure we evaluate cond properly."""
    env = prelude.env()
    call = wtypes.List([
        wtypes.List([
            wtypes.String('two'),
            wtypes.List(
                [wtypes.Integer(2),
                 wtypes.Integer(2),
                 wtypes.Symbol('eq?')])
        ]),
        wtypes.List([
            wtypes.String('one'),
            wtypes.List(
                [wtypes.Integer(1),
                 wtypes.Integer(1),
                 wtypes.Symbol('eq?')])
        ]),
        wtypes.List([
            wtypes.String('not-one'),
            wtypes.List(
                [wtypes.Integer(2),
                 wtypes.Integer(1),
                 wtypes.Symbol('eq?')])
        ]),
        wtypes.Symbol('cond')
    ])
    result = call.eval(env)
    assert result == wtypes.String('one')
Beispiel #5
0
def test_eval_list():
    """Ensure lists are evaluated as post-fix function calls."""
    env = wisp.env.Environment({'+': wtypes.Function(
        lambda xs, _: wtypes.Integer(xs[0].val + xs[1].val)
    )})
    res = wtypes.List([
            wtypes.Integer(1), wtypes.Integer(2), wtypes.Symbol('+')
    ]).eval(env)
    assert res == wtypes.Integer(3)
Beispiel #6
0
def test_cdr():
    """Ensure cdr takes the rest."""
    env = prelude.env()
    res = env[wtypes.Symbol('cdr')].call([
        quoted_list([wtypes.Integer(1),
                     wtypes.Integer(2),
                     wtypes.Integer(3)])
    ], env)
    assert res == wtypes.List([wtypes.Integer(2), wtypes.Integer(3)])
Beispiel #7
0
def test_bad_lambda():
    """Ensure we handle lambdas which raise exceptions."""
    env = prelude.env()

    # define a lambda calling a non-existent symbol
    bad_lambda = env[wtypes.Symbol('lambda')].call([
        wtypes.List([wtypes.Symbol('x')]),
        wtypes.List([wtypes.Symbol('snakes')])
    ], env)

    # raise an exception when we call it
    call = wtypes.List([wtypes.Integer(2), bad_lambda])
    with pytest.raises(exceptions.WispException):
        call.eval(env)

    # ensure we didn't pollute even though the call raised an exception
    with pytest.raises(exceptions.WispException):
        env[wtypes.Symbol('x')]
Beispiel #8
0
def test_define():
    """Ensure define binds values to symbols."""
    env = prelude.env()

    res = env[wtypes.Symbol('define')].call(
        [wtypes.Symbol('a'),
         quoted_list([wtypes.String('apple')])], env)
    assert res == wtypes.Symbol('a')
    assert env[wtypes.Symbol('a')] == wtypes.List([wtypes.String('apple')])
Beispiel #9
0
def test_parse_list():
    """Ensure we can parse lists."""
    assert parser.parse_expr.parse('(1    abc "abc" #t #f +)') == wtypes.List([
        wtypes.Integer(1),
        wtypes.Symbol('abc'),
        wtypes.String('abc'),
        wtypes.Bool(True),
        wtypes.Bool(False),
        wtypes.Symbol('+'),
    ])
Beispiel #10
0
def test_cons():
    """Ensure cons sticks things together."""
    env = prelude.env()
    res = env[wtypes.Symbol('cons')].call([
        wtypes.Integer(1),
        quoted_list([wtypes.Integer(2), wtypes.Integer(3)])
    ], env)
    assert res == wtypes.List(
        [wtypes.Integer(1),
         wtypes.Integer(2),
         wtypes.Integer(3)])
Beispiel #11
0
def test_lambda():
    """Ensure lambdas can be defined and called."""
    env = prelude.env()

    # define a lambda performing x - y
    sub_lambda = env[wtypes.Symbol('lambda')].call([
        wtypes.List([wtypes.Symbol('x'),
                     wtypes.Symbol('y')]),
        wtypes.List(
            [wtypes.Symbol('y'),
             wtypes.Symbol('x'),
             wtypes.Symbol('-')]),
    ], env)

    # ensure we can call the above lambda
    call = wtypes.List([wtypes.Integer(1), wtypes.Integer(3), sub_lambda])
    res = call.eval(env)
    assert res == wtypes.Integer(2)

    # ensure we didn't pollute the environment with bindings from the call.
    with pytest.raises(exceptions.WispException):
        env[wtypes.Symbol('x')]
Beispiel #12
0
def test_cond_with_else():
    """Ensure we handle else expressions."""
    env = prelude.env()
    call = wtypes.List([
        wtypes.List([wtypes.String('else-case'),
                     wtypes.Symbol('else')]),
        wtypes.List([
            wtypes.String('not-two'),
            wtypes.List(
                [wtypes.Integer(3),
                 wtypes.Integer(2),
                 wtypes.Symbol('eq?')])
        ]),
        wtypes.List([
            wtypes.String('not-one'),
            wtypes.List(
                [wtypes.Integer(2),
                 wtypes.Integer(1),
                 wtypes.Symbol('eq?')])
        ]),
        wtypes.Symbol('cond')
    ])
    result = call.eval(env)
    assert result == wtypes.String('else-case')
Beispiel #13
0
def quoted_list(elems):
    """Build a quoted list consisting of the given elements, safe from eval."""
    return wtypes.List([wtypes.List(elems), wtypes.Symbol('quote')])
Beispiel #14
0
def test_closures():
    """Ensure we handle closures properly."""
    env = prelude.env()
    counter_def = wtypes.List([
        wtypes.List([
            wtypes.List([
                wtypes.List([
                    wtypes.Symbol('x'),
                    wtypes.List([
                        wtypes.List([
                            wtypes.Integer(1),
                            wtypes.Symbol('x'),
                            wtypes.Symbol('+')
                        ]),
                        wtypes.Symbol('x'),
                        wtypes.Symbol('set!')
                    ]),
                    wtypes.Symbol('begin')
                ]),
                wtypes.List([]),
                wtypes.Symbol('lambda')
            ]),
            wtypes.List([wtypes.Symbol('x')]),
            wtypes.Symbol('lambda')
        ]),
        wtypes.Symbol('make-counter'),
        wtypes.Symbol('define'),
    ])
    counter_def.eval(env)

    counter = wtypes.List([
        wtypes.List([wtypes.Integer(0),
                     wtypes.Symbol('make-counter')]),
        wtypes.Symbol('c'),
        wtypes.Symbol('define'),
    ])
    counter.eval(env)

    call = wtypes.List([wtypes.Symbol('c')])

    assert call.eval(env) == wtypes.Integer(1)
    assert call.eval(env) == wtypes.Integer(2)
    assert call.eval(env) == wtypes.Integer(3)

    # ensure 'x' from the closure hasn't leaked into the global scope.
    with pytest.raises(exceptions.WispException):
        env[wtypes.Symbol('x')]
Beispiel #15
0
def test_recursion():
    """Ensure we can handle simple recursion."""
    env = prelude.env()
    fib_def = wtypes.List([
        wtypes.List([
            wtypes.List([
                wtypes.List([
                    wtypes.List([
                        wtypes.List([
                            wtypes.List([
                                wtypes.Integer(2),
                                wtypes.Symbol('n'),
                                wtypes.Symbol('-')
                            ]),
                            wtypes.Symbol('fib')
                        ]),
                        wtypes.List([
                            wtypes.List([
                                wtypes.Integer(1),
                                wtypes.Symbol('n'),
                                wtypes.Symbol('-')
                            ]),
                            wtypes.Symbol('fib')
                        ]),
                        wtypes.Symbol('+')
                    ]),
                    wtypes.Symbol('else')
                ]),
                wtypes.List([
                    wtypes.Integer(1),
                    wtypes.List([
                        wtypes.Integer(1),
                        wtypes.Symbol('n'),
                        wtypes.Symbol('eq?')
                    ])
                ]),
                wtypes.List([
                    wtypes.Integer(0),
                    wtypes.List([
                        wtypes.Integer(0),
                        wtypes.Symbol('n'),
                        wtypes.Symbol('eq?')
                    ])
                ]),
                wtypes.Symbol('cond')
            ]),
            wtypes.List([wtypes.Symbol('n')]),
            wtypes.Symbol('lambda')
        ]),
        wtypes.Symbol('fib'),
        wtypes.Symbol('define'),
    ])
    fib_def.eval(env)

    call = wtypes.List([wtypes.Integer(0), wtypes.Symbol('fib')])
    assert call.eval(env) == wtypes.Integer(0)

    call = wtypes.List([wtypes.Integer(1), wtypes.Symbol('fib')])
    assert call.eval(env) == wtypes.Integer(1)

    call = wtypes.List([wtypes.Integer(5), wtypes.Symbol('fib')])
    assert call.eval(env) == wtypes.Integer(5)

    call = wtypes.List([wtypes.Integer(6), wtypes.Symbol('fib')])
    assert call.eval(env) == wtypes.Integer(8)

    call = wtypes.List([wtypes.Integer(7), wtypes.Symbol('fib')])
    assert call.eval(env) == wtypes.Integer(13)
Beispiel #16
0
def test_eval_empty_list():
    """Ensure empty lists are evaluated to empty lists."""
    assert wtypes.List([]).eval({}) == wtypes.List([])
Beispiel #17
0
def cdr(args: typing.List[wtypes.Expression],
        env: wisp.env.Environment) -> wtypes.List:
    """Return all but the first element of the given list."""
    return __list_op(lambda wlst: wtypes.List(wlst.items[1:]), args)
Beispiel #18
0
def test_eval_list_without_a_func():
    """Ensure an error is raised when applying non-functions."""
    with pytest.raises(exceptions.WispException):
        wtypes.List([wtypes.Integer(1)]).eval({})
Beispiel #19
0
def parse_list():
    """Parse a list as a ()-enclosed sequence of expressions."""
    yield parsec.string('(')
    vals = yield parsec.sepBy(parse_expr, parsec.many1(parsec.space()))
    yield parsec.string(')')
    return wtypes.List(vals)