Skip to content

Instantly share code, notes, and snippets.

@ihodes
Created October 11, 2014 16:58
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save ihodes/6ea33e4538dbeba4ee8a to your computer and use it in GitHub Desktop.
def tokenize(string):
return string.replace('(', ' ( ').replace(')', ' ) ').split()
def parse(tokens):
expression, estack = [], []
for token in tokens:
if token is '(':
estack.append(expression)
expression = []
elif token is ')':
expression = estack.pop() + [expression]
else:
expression.append(token)
return expression
def read(string):
return parse(tokenize(string))
class Env(dict):
def __init__(self, vars=(), vals=(), env=None):
self.update(zip(vars, vals))
self.env = env
def lookup(self, var):
if var in self:
return self[var]
elif self.env:
return self.env.lookup(var)
else:
raise ValueError('"' + var + '" not in scope.')
FUNCTIONS = {'atom': lambda x: not isinstance(x, list), 'eq': lambda x, y: x == y,
'cons': lambda x, y: [x] + y if y else [x], 'car': lambda x: x[0],
'cdr': lambda x: x[1:]}
def eval(expr, env):
if expr == 'nil':
return None
elif isinstance(expr, str):
return env.lookup(expr)
elif expr[0] == 'quote':
return expr[1]
elif expr[0] == 'cond':
_, test, texpr, eexpr = expr
return eval(texpr) if eval(test) else eval(eexpr)
elif expr[0] == 'lambda':
_, vars, expr = expr
return lambda *args: eval(expr, Env(vars=vars, vals=args, env=env))
elif expr[0] == 'label':
_, var, expr = expr
env[var] = eval(expr, env)
return (var, eval(expr, env))
else:
expr = [eval(e, env) for e in expr]
return expr[0](*expr[1:])
def pr(expr):
if expr is None:
return 'nil'
elif isinstance(expr, list):
return '(' + ' '.join(pr(e) for e in expr) + ')'
else:
return expr
def loop(env, prompt):
while True:
try:
string = raw_input(prompt)
if string[0] == '%' and string[1:5] == 'load':
with open(string[6:] + '.scm') as f:
string = f.read()
else:
while string.count('(') != string.count(')'):
string = string + raw_input(' ')
for val in (eval(expr, env) for expr in read(string)):
print(pr(val))
except EOFError:
print "\nExiting REPL..."
break
except Exception as e:
print "Error: ", e
GLOBAL = Env()
GLOBAL.update(FUNCTIONS)
if __name__ == '__main__':
loop(global_env, '> ')
assert (tokenize('(apply max (cons (+ 1 2) somelist))') ==
['(', 'apply', 'max', '(', 'cons', '(', '+', '1', '2', ')', 'somelist', ')', ')'])
assert (parse(['(', 'apply', 'max', '(', 'cons', '(', '+', '1', '2', ')', 'somelist', ')', ')'])[0] == ['apply', 'max', ['cons', ['+', '1', '2'], 'somelist']])
assert print_(['cons', '1', ['+', '1', '2']]) == '(cons 1 (+ 1 2))'
assert eval(['cons', ['quote', 'apple'], 'nil'], GLOBAL) == ['apple']
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment