この記事の続きです．

この記事で終わりです．

# 2.評価

builtin.py(continue)

```special_forms = {
"quote": lambda symbol, *args: symbol,
"lambda": lambda arglist, body, env, hook: lambda *args: hook(body, dict(zip(arglist, args), **env)),
"define": lambda symbol, value, env, hook: [env.update({symbol: hook(value)}), "nil"][-1],
"if": lambda test, trueform, falseform, env, hook: hook(trueform if hook(test) else falseform),
}

functions = {
"atom": lambda symbol: type(symbol) is not list,
"cons": lambda a, d: [a, d],
"car": lambda cons: cons[0],
"cdr": lambda cons: cons[1],
"eq": lambda one, other: "t" if one is other else "nil",
}

constants = {
"nil": (),
"t": True,
}
```

つぎにシンボルから値を取り出す関数を定義します．

builtin.py(end)

```from enum import Enum

Kind = Enum("Kind", ["Special", "Function", "Constant", "Lambda", "Bounded", "Unbounded"])

def symbol_value(symbol, env):
if callable(symbol):
return symbol, Kind.Lambda
elif symbol in special_forms.keys():
return special_forms[symbol], Kind.Special
elif symbol in functions.keys():
return functions[symbol], Kind.Function
elif symbol in constants.keys():
return constants[symbol], Kind.Constant
elif symbol in env.keys():
return env[symbol], Kind.Bounded
else:
return None, Kind.Unbounded
```

eval.py

```from builtin import symbol_value, Kind

env = {}

def eval_sexp(sexp, env=env):
eval_in_env = lambda _: eval_sexp(_, env)
if type(sexp) is list:
car = sexp[0]
func, kind = symbol_value(car if type(car) is str else eval_in_env(car), env)
if kind is Kind.Special:
return func(*sexp[1:], env, eval_sexp)
elif kind is Kind.Unbounded:
raise ValueError("The function {} is unbounded.".format(car))
else:
if not callable(func):
func = eval_in_env(func)
return func(*list(map(eval_in_env, sexp[1:])))
else:
value, kind = symbol_value(sexp, env)
if kind is Kind.Unbounded:
raise ValueError("The symbol {} is unbounded.".format(sexp))
return value
```

test_eval.py

```from eval import eval_sexp

sexp = ["lambda", ["a", "b"] ["cons", ["quote", "c"], ["quote", "d"]]]
print(eval_sexp(sexp))
```

なおこれは`((lambda (a b) (cons a b)) 'c 'd)`に相当します．

```\$ python test_eval.py
['c', 'd']
```

```from read import read
from eval import eval_sexp

```

test.lisp

```((lambda (a b) (cons a b)) 'c 'd)
```

```\$ python test_readeval.py < test.lisp
['c', 'd']
```

# 3.表示

pprint.py(continue)

```def pprint(value, end="\n"):
if value is ():
print("nil", end=end)
elif value is True:
print("t", end=end)
elif type(value) is list:
print("(", end="")
for element in value[:-1]:
pprint(element, end=" ")
pprint(value[-1], end=")\n")
else:
print(value, end=end)
return "nil"
```

これはLispからも使えたほうが便利なのでimportフックで`builtin.functions`に追加します．

pprint.py(end)

```from builtin import functions

functions.update(print=lambda value: pprint(value))
```

test_pprint.py

```from read import read
from eval import eval_sexp
from pprint import pprint

```

test.lisp

```(print ((lambda (a b) (cons a b)) 'c 'd))
```

```\$ python test_pprint.py < test.lisp
(c d)
```

# 4.REPL

repl.lisp

```from io import StringIO
from pprint import pprint
from eval import eval_sexp

try:
stdin = StringIO(input(prompt))
stdin.name = "<stdin>"
return stdin
except EOFError:
return

def repl(prompt="LISP> "):
while line:
try:
except Exception as e:
print(e)