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
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) """