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 curry(se: SExpression, stg: LexicalVarStorage = LexicalVarStorage({})):
    """
    curry returns a user function with given arguments,
    It will return the user function if it is a user function
    
    """
    if isinstance(se, UserFunction):
        return se
Пример #3
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
Пример #4
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)
Пример #5
0
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
    """
    vals = []
    ptrs = []
    pred = se.car
    con = se.cdr
    for item in pred:
        vals.append(item.car)
        ptrs.append(item.cdr.car)
    param = SExpression.from_iterable(vals)
    ptrs = SExpression.from_iterable(ptrs)
    function = UserFunction(params=param, body=con, environ=stg.fork())
    res = SExpression(function, ptrs)

    return res
Пример #6
0
 def __init__(self):
     # load builtins out of slyther.bulitins
     builtins = {
         x.__name__: Variable(x)
         for x in map(
             partial(getattr, slyther.builtins),
             slyther.builtins.__dir__())
         if isinstance(x, BuiltinCallable)}
     # put in the default variables
     builtins.update({
         'NIL': Variable(NIL),
         'nil': Variable(NIL),
         '#t': Variable(Boolean(True)),
         '#f': Variable(Boolean(False)),
     })
     self.stg = LexicalVarStorage(builtins)
Пример #7
0
def lambda_func(se: SExpression, stg: LexicalVarStorage) -> UserFunction:
    """
    Define an anonymous function and return the ``UserFunction``
    object.

    >>> from slyther.types import *
    >>> stg = LexicalVarStorage({})
    >>> stg.put('x', 20)
    >>> f = lambda_func(
    ...     SExpression.from_iterable([
    ...         SExpression.from_iterable(map(Symbol, ['a', 'b', '.', 'c'])),
    ...         SExpression.from_iterable(map(Symbol, ['print', 'a'])),
    ...         SExpression.from_iterable(map(Symbol, ['print', 'b'])),
    ...         SExpression.from_iterable(map(Symbol, ['print', 'c']))]),
    ...     stg)
    >>> f
    (lambda (a b . c) (print a) (print b) (print c))
    >>> f.environ['x'].value
    20
    """
    return UserFunction(se.car, se.cdr, stg.fork())
Пример #8
0
from slyther.parser import lisp
from slyther.evaluator import lisp_eval

collected = {}


@BuiltinFunction
def collect(name, value):
    collected[name] = value
    return value


stg = LexicalVarStorage({
    'collect': Variable(collect),
    'add': Variable(BuiltinFunction(operator.add)),
    '#t': Variable(Boolean(True)),
    '#f': Variable(Boolean(False)),
    'NIL': Variable(NIL)
})


def test_function_args():
    environ = stg.fork()
    func = UserFunction(params=lisp('(x y z)'),
                        body=lisp('''((collect 'z z)
                      (collect 'x x)
                      (collect 'y y)
                      ;; return NIL so that TCO can be implemented
                      ;; without breaking this test
                      NIL)'''),
                        environ=environ.copy())
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)
    """