Last active
April 6, 2024 12:42
-
-
Save ytaki0801/bb624dadcfc0e4696f59ad71d6f6be62 to your computer and use it in GitHub Desktop.
A Pure LISP Interpreter with dynamic-scope named-let in pseudocode-style Python 3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#### | |
#### letLISP.py: | |
#### A Pure LISP Interpreter | |
#### with dynamic-scope named-let | |
#### in pseudocode-style Python 3 | |
#### | |
#### (C) 2022 TAKIZAWA Yozo | |
#### This code is licensed under CC0. | |
#### https://creativecommons.org/publicdomain/zero/1.0/ | |
#### | |
from sys import argv, stdin | |
def cons(x, y): | |
return [x] + y | |
def car(x): | |
return x[0] | |
def cdr(x): | |
return x[1:] | |
def null(x): | |
return x == [] | |
def pair(x): | |
r = isinstance(x, list) | |
return r and not null(x) | |
def atom(x): | |
r = isinstance(x, str) | |
return r or null(x) | |
def eq(x, y): | |
if atom(x) and atom(y): | |
return x == y | |
else: | |
return False | |
def intp(x): | |
try: | |
r = int(x) | |
return True | |
except ValueError: | |
return False | |
LH = False | |
def put_c1(x): | |
global LH | |
LH = x | |
def get_c1(f): | |
if not LH: | |
try: | |
return f.read(1) | |
except EOFError: | |
pass | |
else: | |
lh = LH | |
put_c1(False) | |
return lh | |
def tstring(t): | |
return ''.join(t) | |
def skip_spaces(f): | |
c = get_c1(f); | |
while c in ' \t\n\r': | |
c = get_c1(f) | |
put_c1(c) | |
def get_token(f): | |
c = get_c1(f) | |
t = [] | |
while True: | |
if c in ' \t\n\r': | |
if not t: | |
skip_spaces(f); | |
c = get_c1(f) | |
else: | |
return tstring(t) | |
elif c == '(' or c == "'": | |
skip_spaces(f) | |
return c | |
elif c == ')': | |
if not t: | |
return c | |
else: | |
put_c1(c) | |
return tstring(t) | |
else: | |
t += [c] | |
c = get_c1(f) | |
def srlist(f): | |
t = get_token(f) | |
if t == ')': | |
return [] | |
elif t == '(': | |
h = srlist(f) | |
return cons(h, srlist(f)) | |
elif t == "'": | |
h = cons('quote', [sread(f)]) | |
return cons(h, srlist(f)) | |
else: | |
return cons(t, srlist(f)) | |
def sread(f): | |
t = get_token(f) | |
if t == '(': | |
return srlist(f) | |
if t == "'": | |
return cons('quote', [sread(f)]) | |
else: | |
return t | |
def output(x): | |
print(x, end='', flush=True) | |
def swlist(x): | |
swrite(car(x)) | |
if not null(cdr(x)): | |
output(' ') | |
swlist(cdr(x)) | |
def swrite(s): | |
if pair(s): | |
output('(') | |
swlist(s) | |
output(')') | |
elif null(s): | |
output('()') | |
else: | |
output(s) | |
def add(x, y): | |
return str(int(x) + int(y)) | |
def sub(x, y): | |
return str(int(x) - int(y)) | |
def mul(x, y): | |
return str(int(x) * int(y)) | |
def quo(x, y): | |
return str(int(x) // int(y)) | |
def rem(x, y): | |
return str(int(x) % int(y)) | |
def eqn(x, y): | |
return int(x) == int(y) | |
def lt(x, y): | |
return int(x) < int(y) | |
def sread_std(): | |
return sread(stdin) | |
G = {'cons' : cons, | |
'car' : car, | |
'cdr' : cdr, | |
'pair?' : pair, | |
'eq?' : eq, | |
'+' : add, | |
'-' : sub, | |
'*' : mul, | |
'quotient' : quo, | |
'remainder': rem, | |
'<' : lt, | |
'=' : eqn, | |
'read' : sread_std, | |
'write' : swrite} | |
def quote_syntax(s, e): | |
return s[1] | |
def if_syntax(s, e): | |
if ev(s[1], e): | |
return ev(s[2], e) | |
else: | |
return ev(s[3], e) | |
def let_syntax(s, e): | |
vs, rs, v = [], [], s[2] | |
while v: | |
vs += [car(v)[0]] | |
rs += [car(v)[1]] | |
v = cdr(v) | |
r = [['fn', [s[1]], [s[1]] + rs], | |
['fn', vs, s[3]]] | |
return ev(r, e) | |
def apply_function(s, e): | |
f = ev(car(s), e) | |
a = [] | |
s = cdr(s) | |
while s: | |
a += [ev(car(s), e)] | |
s = cdr(s) | |
if callable(f): | |
return f(*a) | |
else: | |
va = dict(zip(f[1], a)) | |
e1 = {**e, **va} | |
return ev(f[2], e1) | |
def ev(s, e): | |
if atom(s): | |
if intp(s): | |
return s | |
elif s in G: | |
return G[s] | |
else: | |
return e[s] | |
elif car(s) == 'quote': | |
return quote_syntax(s, e) | |
elif car(s) == 'if': | |
return if_syntax(s, e) | |
elif car(s) == 'fn': | |
return s | |
elif car(s) == 'let': | |
return let_syntax(s, e) | |
else: | |
return apply_function(s, e) | |
if len(argv) < 2: | |
s = sread(stdin) | |
else: | |
with open(argv[1]) as f: | |
s = sread(f) | |
ev(s, {}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment