Ejemplo n.º 1
0
    def __call__(self, *args: Any):
        """
        Evaluates lambdas body with passed arguments.

        Args/Kwarg:
            `*args`:
                Arguments to evaluate the body with.

        Evaluation is done by firstly pushing captured definition
        environment, then pushing environment created by
        associating values passed to the call with
        names provided during lambda definition; onto the
        environment stack and then evaluating the lambdas body.

        Environments are always popped from the stack even if
        exception happens during evaluation.

        If lambda was used to define a top-level function then
        it captures a global environment. In this case, on call,
        only arguments environment is pushed onto the stack
        as pushing a global one would create a reference cycle
        for the environments.
        """
        func_args = [x for x in self._func_args]
        if len(func_args) != len(args):
            raise EvaluationError(
                f"number of call arguments doesn't match"
                f" expected {len(func_args)} got {len(args)}")
        env_init = dict(zip(func_args, args))
        call_env = Env(env_init)
        self._push_envs(call_env)
        try:
            return self._evaluator.eval(self._body)
        finally:
            self._pop_envs()
Ejemplo n.º 2
0
def eval(source, init_env=None):
    if init_env is None:
        init_env = Env(STD_ENV)
    evaluator = Evaluator(init_env)
    comp = ObjectCompiler()
    ast = parser.parse(lexer.lex(source))
    code = ast.accept(comp)
    return evaluator.eval(code)
Ejemplo n.º 3
0
def test_set_form_setting_value_in_outer_scope(sym, val):
    env = Env()
    eval(f"(define {sym} (quote ()))", env)
    eval(
        f"""
        (define a (lambda () (set! {sym} {val})))
    """,
        env,
    )
    eval("(a)", env)
    assert env[obj.Symbol(sym)] == val
Ejemplo n.º 4
0
    def push_env(self, env: Env):
        """
        Pushes new environment onto the stack.

        Assertion is made to make sure that the same
        environment is not pushed twice as that would
        create a reference cycle. And probably that
        is not what you want anyway.
        """
        assert env is not self._current_env
        env.parent = self._current_env
        self._current_env = env
Ejemplo n.º 5
0
def test_lambda_env_capture(val):
    m = mock.Mock()
    env = Env({obj.Symbol("func"): m})
    eval(
        """
        (define a
            (lambda (x)
                (lambda () (func x))))
        """,
        init_env=env,
    )
    eval(f"(define b (a {val}))", init_env=env)
    eval("(b)", init_env=env)
    m.assert_called_once_with(val)
Ejemplo n.º 6
0
    def __init__(self, env: Env = None):
        """
        Creates new `PylisperConsole`.

        Args/Kwargs:
            `env`:
                Optional environment to run code with.
                If `None` then `STD_ENV` is used.
        """
        super().__init__()
        if env is None:
            env = Env(STD_ENV)
        self.env = env
        self.eval = Evaluator(env)
        self.comp = ObjectCompiler()
Ejemplo n.º 7
0
def test_recursive_function_call(val):
    m = mock.Mock()
    env = Env({obj.Symbol("func"): m, **STD_ENV})
    calls = [mock.call(x) for x in range(val, 0, -1)]
    eval(
        """
        (define a
            (lambda (acc _)
                (cond
                    ((= acc 0) #t)
                    (#t (a (- acc 1) (func acc))))))
        """,
        init_env=env,
    )
    assert eval(f"(a {val} (func {val}))", init_env=env)
    m.assert_has_calls(calls)
Ejemplo n.º 8
0
def test_set_form_setting_value_in_inner_scope(sym, outer, inner):
    m = mock.Mock()
    env = Env({obj.Symbol("func"): m})
    eval(f"(define {sym} {outer})", env)
    eval(
        f"""
        (define a
            (lambda ({sym})
                (begin
                    (set! {sym} {inner})
                    (func {sym}))))
    """,
        env,
    )
    eval("(a (quote ()))", env)
    m.assert_called_once_with(inner)
    assert env[obj.Symbol(sym)] == outer
Ejemplo n.º 9
0
def test_against_env_reference_cycle():
    env = Env(STD_ENV)
    eval(
        """
        (define a
            (lambda (acc)
                (cond
                    ((= acc 0) #t)
                    (#t (a (- acc 1))))))
    """,
        init_env=env,
    )
    assert eval("(a 10)", env)
    eval(
        """
        (define a
            (lambda (acc)
                (cond
                    ((= acc 0) #t)
                    (#t (a (- acc 1))))))
    """,
        init_env=env,
    )
    assert eval("(a 10)", env)
Ejemplo n.º 10
0
def test_lambda_evaluation(val):
    m = mock.Mock()
    env = Env({obj.Symbol("func"): m})
    eval(f"((lambda (x) (func x)) {val})", init_env=env)
    m.assert_called_once_with(val)
Ejemplo n.º 11
0
def test_symbol_evaluation(sym, val):
    env = Env()
    eval(f"(define {sym} {val})", init_env=env)
    assert eval(sym, init_env=env) == val
Ejemplo n.º 12
0
def test_function_call(fst, snd):
    m = mock.Mock()
    env = Env({obj.Symbol("func"): m})
    eval(f"(func {fst} {snd})", init_env=env)
    m.assert_called_once_with(fst, snd)
Ejemplo n.º 13
0
def test_symbol_definition(sym, val):
    env = Env()
    eval(f"(define {sym} {val})", init_env=env)
    assert obj.Symbol(sym) in env
    assert env[obj.Symbol(sym)] == val
Ejemplo n.º 14
0
def test_set_form_on_some_cell_in_list(init, val):
    env = Env(STD_ENV)
    list_vals = " ".join(map(str, init))
    eval(f"(define loc (quote ({list_vals})))", env)
    eval(f"(set! (car (cdr (cdr loc))) {val})", env)
    assert env[obj.Symbol("loc")].cdr.cdr.value == val
Ejemplo n.º 15
0
def test_set_form_evaluation(sym, val):
    env = Env()
    eval(f"(define {sym} (quote ()))", env)
    eval(f"(set! {sym} {val})", env)
    assert env[obj.Symbol(sym)] == val