The mal Environment¶
- project:
mal-py
- filename:
env.py
As with the reader, this is held separate.
mal-py
env.py
from reader import S
class Env:
def __init__(
self, outer: Env | None = None, binds: list[str] = None, exprs: list[Any] = None,
):
self.data = {}
self.outer = outer
binds = binds or []
exprs = exprs or []
for b, e in zip(binds, exprs):
self.set(b.name, e)
def set(self, key: str, value):
self.data[key] = value
def get(self, key: str):
if (value := self.data.get(key)) is None:
if self.outer is not None:
return self.outer.get(key)
raise KeyError(key)
return value
The core¶
- filename:
core.py
From step 4, mal calls for a core.ns object that defines all the built-in functions for the language.
This defines a defn decorator that makes adding functions to the namespace nice.
mal-py
core.py
import pathlib
from reader import A, read_str
ns = {}
def defn(name):
def wrap(fn):
ns[name] = fn
return fn
return wrap
Atoms¶
mal-py
core.py
@defn('atom')
def atom(v):
return A(v)
@defn('atom?')
def isatom(a):
return isinstance(a, A)
@defn('deref')
def deref(a):
return a.v
@defn('reset!')
def reset(a, v):
a.v = v
return v
@defn('swap!')
def swap(a, f, *args):
v = f(a.v, *args)
a.v = v
return v
Comparisons¶
mal-py
core.py
@defn('=')
def eql(x, y):
return x == y
@defn('<')
def lt(x, y):
return x < y
@defn('>')
def gt(x, y):
return x > y
@defn('<=')
def lte(x, y):
return x <= y
@defn('>=')
def gte(x, y):
return x >= y
Eval¶
mal-py
core.py
@defn('read-string')
def read(s):
return read_str(s)
@defn('slurp')
def slurp(s):
return pathlib.Path(s).read_text()
Lists¶
It wouldn’t be a Lisp without some list operators.
mal-py
core.py
@defn('cons')
def cons(v, lst):
return [v, *lst]
@defn('concat')
def concat(*lsts):
l = []
for lst in lsts:
l.extend(lst)
return l
@defn('list')
def make_list(*args):
return list(args)
@defn('list?')
def is_list(x):
return isinstance(x, list)
@defn('empty?')
def is_empty(x):
return len(x) == 0
@defn('count')
def count(x):
if not x:
return 0
return len(x)
Math functions¶
Plus, times, divide etc.
mal-py
core.py
@defn('+')
def plus(a, b):
return a + b
@defn('-')
def minus(a, b):
return a - b
@defn('*')
def multiply(a, b):
return a * b
@defn('/')
def divide(a, b):
return int(a/b)
Printing¶
We want to be able to print from within mal
mal-py
core.py
from printer import print_form
@defn('prn')
def printit(f):
print(print_form(f))
Strings¶
mal-py
core.py
@defn('str')
def tostr(*args):
return "".join(args)