Created
May 17, 2016 11:23
-
-
Save jorinvo/2b9d6fe996694313454a72ecf6f82d75 to your computer and use it in GitHub Desktop.
Experiments writing a LISP interpreter in Python. Thanks https://maryrosecook.com/blog/post/little-lisp-interpreter
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
class Library: | |
@staticmethod | |
def first(x): | |
return x[0] | |
@staticmethod | |
def add(*x): | |
if type(x[0]) == list: | |
return sum(x[0]) | |
else: | |
return sum(x) | |
@staticmethod | |
def max(*x): | |
if type(x[0]) == list: | |
return max(x[0]) | |
else: | |
return max(x) | |
@staticmethod | |
def square(x): | |
return x * x | |
@staticmethod | |
def map(fn, l): | |
return [fn(x) for x in l] | |
@staticmethod | |
def ifelse(cond, then_val, else_val): | |
if cond == 1: | |
return then_val | |
elif cond == 0: | |
return else_val | |
else: | |
raise Exception('Non-boolean condition: %s' % (cond)) | |
library = { | |
'first': Library.first, | |
'+': Library.add, | |
'max': Library.max, | |
'square': Library.square, | |
'map': Library.map, | |
'if': Library.ifelse | |
} |
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
from library import library | |
def tokenize(lisp_str): | |
return lisp_str.replace('(', ' ( ').replace(')', ' ) ').split() | |
def parenthesize(tokens, tree=[]): | |
if not tokens: | |
return tree.pop() | |
token = tokens.pop(0) | |
if token == '(': | |
return parenthesize(tokens, tree + [parenthesize(tokens)]) | |
elif token == ')': | |
return tree | |
else: | |
return parenthesize(tokens, tree + [categorize(token)]) | |
def categorize(token): | |
try: | |
return ('lit', float(token)) | |
except: | |
return ('id', token) | |
def interpret(val, context=None): | |
if not context: | |
return interpret(val, library) | |
elif type(val) == list: | |
l = [interpret(x, context) for x in val] | |
if callable(l[0]): | |
return l[0](*l[1:]) | |
else: | |
return l | |
elif val[0] == 'id': | |
try: | |
return context[val[1]] | |
except KeyError as key: | |
raise Exception('Function %s not in context' % (key)) | |
else: | |
# lit | |
return val[1] | |
if __name__ == '__main__': | |
test_input = ''' | |
( | |
(+ 1 7) | |
(+ (2.5 4)) | |
(map square (1 2 3)) | |
1 | |
(first ( | |
(first ((square 3))) | |
1 | |
(first (4 5)) | |
)) | |
(if 1 10 20) | |
(if (first (0 1)) 10 20) | |
) | |
''' | |
tokens = tokenize(test_input) | |
tree = parenthesize(tokens) | |
print(interpret(tree)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment