def let(se: SExpression, stg: LexicalVarStorage) -> SExpression:
    """
    The ``let`` macro binds variables to a local scope: the expressions
    inside the macro. Like a function, a ``let`` returns the last
    expression in its body. Once the ``let`` returns, the variables are
    unbound, and cannot be accessed anymore. For example::

        (let ((a (+ f g))
              (b 11)
              (c 12))
          (+ a (- b c)))

    In the example above, ``a`` was bound to whatever ``(+ f g)``
    evaluates to, b to ``11``, and ``c`` to ``12``.

    Notice how the above was equivalent to another expression::

        ((lambda (a b c)
           (+ a (- b c))) (+ f g) 11 12)

    You should do a syntax translation from the input to something like that.

    >>> from slyther.types import *
    >>> from slyther.parser import lisp
    >>> from slyther.evaluator import lisp_eval
    >>> stg = LexicalVarStorage(
    ...         {'let': Variable(let),
    ...          'lambda': Variable(lambda_func),
    ...          'print': Variable(print_),
    ...          'x': Variable(10)})
    >>> lisp_eval(lisp('(let ((x 20) (y 30)) (print x) (print y))'), stg)
    20
    30
    NIL
    >>> lisp_eval(Symbol('x'), stg)
    10
    """

    new_environ = {**stg.environ}
    new_local = {**stg.local}
    new_lex_var = LexicalVarStorage(new_environ)
    new_lex_var.local = new_local
    for item in se.car:
        new_lex_var.put(item.car, lisp_eval(item.cdr.car, stg))

    return_val = NIL
    for item in se.cdr:
        return_val = lisp_eval(item, new_lex_var)
    return return_val
예제 #2
0
def test_fork(environ, local):
    stg = LexicalVarStorage(environ)
    stg.local = local
    save_local = dict(stg.local)
    save_environ = dict(stg.environ)
    fork = stg.fork()
    assert isinstance(fork, dict)

    # should not modify locals or environ during fork
    assert stg.local == save_local
    assert stg.environ == save_environ

    for k, v in stg.environ.items():
        if k not in stg.local.keys():
            assert fork[k] is v

    for k, v in stg.local.items():
        assert fork[k] is v