mal: Step 3ΒΆ

project:

mal-py

filename:

step3_env.py

read

mal-py step3_env.py
import itertools

from env import Env
from reader import S, read_str

def read(ins):
    return read_str(ins)

eval

mal-py step3_env.py
def evaluate(form, env: Env):
    match form:
        case S(name):
            return env.get(name)
        case []:
            return []
        case [*fs]:
            match fs[0]:
                case S('def!'):
                    env.set(fs[1].name, v := evaluate(fs[2], env))
                    return v
                case S('let*'):
                    letenv = Env(env)
                    for binding, expr in itertools.batched(fs[1], n=2):
                        letenv.set(binding.name, evaluate(expr, letenv))
                    return evaluate(fs[2], letenv)

                case _:
                    f, *args = [evaluate(f, env) for f in fs]
                    return f(*args)
        case _:
            return form

print

mal-py step3_env.py
from printer import print_form

def printit(form):
    return print_form(form)

rep

mal-py step3_env.py
def rep(ins: str, env: Env):
    try:
        return printit(evaluate(read(ins), env))
    except EOFError:
        return f"EOF"
    except KeyError as e:
        return f"{e.args[0]!r} not found"
    except Exception as e:
        print(f"RuntimeError: {e}")
        # import pdb; pdb.post_mortem()

repl

mal-py step3_env.py
def repl(ins: io.TextIO):
    env = Env()
    env.set('+', lambda a,b: a+b)
    env.set('-', lambda a,b: a-b)
    env.set('*', lambda a,b: a*b)
    env.set('/', lambda a,b: int(a/b))

    print("user> ", end='', flush=True)
    while (line := ins.readline()) != "":
        print(rep(line, env))
        print("user> ", end='', flush=True)


if __name__ == "__main__":
    import sys
    repl(sys.stdin)