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 define(se: SExpression, stg: LexicalVarStorage):
    """
    Define a variable or a function to a value, calling ``put`` on
    the storage::

        ; variable
        (define var-name evaluate-me)

        ; lambda function
        (define func-name (lambda (args...) (body1) ... (bodyN)))

        ; SE-named function
        (define (func-name args...) (body1) ... (bodyN))

    .. note::

        If defining a function (either by ``lambda`` or by SE-named
        syntax), the definition **must** be made visible from within
        that function's ``environ``, or recursion will not work!

    >>> from slyther.types import *
    >>> from slyther.parser import lisp
    >>> se = lisp('((twirl alpha beta) (print alpha) (print beta))')
    >>> name = Symbol('twirl')
    >>> args = lisp('(alpha beta)')
    >>> body = lisp('((print alpha) (print beta))')
    >>> stg = LexicalVarStorage({})
    >>> stg.put('NIL', NIL)
    >>> stg.put('define', define)
    >>> stg.put('lambda', lambda_func)
    >>> from slyther.evaluator import lisp_eval
    >>> lisp_eval(define(cons(cons(name, args), body), stg), stg)
    NIL
    >>> lisp_eval(define(lisp('(x 10)'), stg), stg)
    NIL
    >>> stg[name].value
    (lambda (alpha beta) (print alpha) (print beta))
    >>> stg[name].value.environ['twirl'].value
    (lambda (alpha beta) (print alpha) (print beta))
    >>> stg['x'].value
    10
    >>> stg[name].value.environ['x'].value
    Traceback (most recent call last):
        ...
    KeyError: 'x'
    """
    key = se.car
    value = se.cdr

    if isinstance(key, SExpression):
        function = UserFunction(params=key.cdr, body=value, environ=stg.fork())
        key = key.car
        function.environ[key] = Variable(function)
        stg.put(key, function)
    elif isinstance(key, Symbol):
        stg.put(key, lisp_eval(value.car, stg))
    else:
        stg.put(key, value)
def define(se: SExpression, stg: LexicalVarStorage):
    """
    Define a variable or a function to a value, calling ``put`` on
    the storage::

        ; variable
        (define var-name evaluate-me)

        ; lambda function
        (define func-name (lambda (args...) (body1) ... (bodyN)))

        ; SE-named function
        (define (func-name args...) (body1) ... (bodyN))

    .. note::

        If defining a function (either by ``lambda`` or by SE-named
        syntax), the definition **must** be made visible from within
        that function's ``environ``, or recursion will not work!

    >>> from slyther.types import *
    >>> from slyther.parser import lisp
    >>> se = lisp('((twirl alpha beta) (print alpha) (print beta))')
    >>> name = Symbol('twirl')
    >>> args = lisp('(alpha beta)')
    >>> body = lisp('((print alpha) (print beta))')
    >>> stg = LexicalVarStorage({})
    >>> stg.put('NIL', NIL)
    >>> stg.put('define', define) # so that you can return a define if you want
    >>> stg.put('lambda', lambda_func)
    >>> from slyther.evaluator import lisp_eval
    >>> lisp_eval(define(cons(cons(name, args), body), stg), stg)
    NIL
    >>> lisp_eval(define(lisp('(x 10)'), stg), stg)
    NIL
    >>> stg[name].value
    (lambda (alpha beta) (print alpha) (print beta))
    >>> stg[name].value.environ['twirl'].value
    (lambda (alpha beta) (print alpha) (print beta))
    >>> stg['x'].value
    10
    >>> stg[name].value.environ['x'].value
    Traceback (most recent call last):
        ...
    KeyError: 'x'
    """
    '''
    if isinstance(se.car, Symbol):
        if isinstance(se.cdr, Variable):
            stg.put(str(se.car), se.cdr)
        else:
            f= lambda_func(se.cdr, stg)
            f.environ.put(str(se.car), f)
    else:
        f= UserFunction(se.cdr, se.cdr.cdr, stg)
        f.environ.put(str(se.car), f)
        '''
    '''
    if isinstance(se.car, Symbol):
        stg.put(str(se.car), se.cdr)
    elif callable(se.car):

        f= lambda_func(se.cdr, stg)
        f.environ.put(str(se.car), f)
        stg.put(str(se.car.car), f)
    elif callable(se.car.car):
        f= UserFunction(se.cdr, se.cdr.cdr, stg)
        f.environ.put(str(se.car), f)
        stg.put(str(se.car.car), f)
    '''

    if isinstance(se.car, SExpression):
        f = UserFunction(se.car.cdr, se.cdr, stg.fork())
        f.environ[str(se.car.car)] = Variable(f)
        stg.put(str(se.car.car), f)
    else:
        f = lisp_eval(se.cdr.car, stg)
        if isinstance(f, UserFunction):
            f.environ[str(se.car)] = Variable(f)
            stg.put(str(se.car), f)
        else:
            stg.put(str(se.car), f)
    """