155 lines
4.6 KiB
Python
155 lines
4.6 KiB
Python
import math
|
|
import string
|
|
from functools import reduce
|
|
|
|
def prettyprint(expression) -> str:
|
|
if type(expression) is list:
|
|
retvalue = "("
|
|
for x in expression:
|
|
retvalue += prettyprint(x) + " "
|
|
return retvalue.rstrip() + ")"
|
|
elif type(expression) is bool:
|
|
return "T" if expression else "NIL"
|
|
elif str():
|
|
return expression.upper()
|
|
else:
|
|
return str(expression)
|
|
|
|
|
|
class Function:
|
|
def __init__(self, parameters, expression):
|
|
self.parameters = parameters
|
|
self.expression = expression
|
|
|
|
class Lisp:
|
|
def __init__(self, env=None):
|
|
if env is None:
|
|
self.env = {}
|
|
else:
|
|
self.env = env
|
|
|
|
def evaluate(self, expression):
|
|
if type(expression) is not list:
|
|
if expression in self.env.keys():
|
|
return self.env[expression]
|
|
return expression
|
|
operation = expression[0]
|
|
if type(operation) is list:
|
|
operation = self.evaluate(operation)
|
|
if type(operation) is list:
|
|
raise TypeError("This value is not a valid operation: " + str(operation))
|
|
if operation == "QUOTE":
|
|
return expression[1:][0]
|
|
if operation != "DEFUN":
|
|
arguments = [self.evaluate(x) for x in expression[1:]]
|
|
else:
|
|
arguments = expression[1:]
|
|
match operation:
|
|
case "+":
|
|
return sum(arguments)
|
|
case "-":
|
|
return arguments[0] - sum(arguments[1:])
|
|
case "*":
|
|
return reduce(lambda x,y: x*y, arguments)
|
|
case "/":
|
|
return reduce(lambda x,y: x/y, arguments)
|
|
case "CAR":
|
|
if len(arguments) != 1:
|
|
raise ValueError("Expected 1 argument")
|
|
return arguments[0][0]
|
|
case "CDR":
|
|
if len(arguments) != 1:
|
|
raise ValueError("Expected 1 argument")
|
|
return arguments[0][1:]
|
|
case "CONS":
|
|
if len(arguments) != 2:
|
|
raise ValueError("Expected 2 arguments")
|
|
if type(arguments[0]) == list:
|
|
return [arguments[0]]+arguments[1]
|
|
else:
|
|
return [arguments[0]]+arguments[1]
|
|
case "SQRT":
|
|
if len(arguments) != 1:
|
|
raise ValueError("Expected 1 argument")
|
|
return math.sqrt(arguments[0])
|
|
case "POW":
|
|
if len(arguments) != 2:
|
|
raise ValueError("Expected 2 arguments")
|
|
return pow(arguments[0], arguments[1])
|
|
case "IF":
|
|
if len(arguments) != 3:
|
|
raise ValueError("Expected 3 arguments")
|
|
if arguments[0]:
|
|
return arguments[1]
|
|
else:
|
|
return arguments[2]
|
|
case ">":
|
|
if len(arguments) != 2:
|
|
raise ValueError("Expected 2 arguments")
|
|
return arguments[0] > arguments[1]
|
|
case "<":
|
|
if len(arguments) != 2:
|
|
raise ValueError("Expected 2 arguments")
|
|
return arguments[0] < arguments[1]
|
|
case "=":
|
|
if len(arguments) != 2:
|
|
raise ValueError("Expected 2 arguments")
|
|
return arguments[0] == arguments[1]
|
|
case "!=":
|
|
if len(arguments) != 2:
|
|
raise ValueError("Expected 2 arguments")
|
|
return arguments[0] != arguments[1]
|
|
case "AND":
|
|
if len(arguments) != 2:
|
|
raise ValueError("Expected 2 arguments")
|
|
return arguments[0] and arguments[1]
|
|
case "OR":
|
|
if len(arguments) != 2:
|
|
raise ValueError("Expected 2 arguments")
|
|
return arguments[0] or arguments[1]
|
|
case "NOT":
|
|
if len(arguments) != 1:
|
|
raise ValueError("Expected 1 argument")
|
|
return not arguments[0]
|
|
case "QUIT":
|
|
print(">> bye")
|
|
raise SystemExit
|
|
case "DEFINE":
|
|
if len(arguments) != 2:
|
|
raise ValueError("Expected 2 arguments")
|
|
self.env[arguments[0]] = arguments[1]
|
|
return arguments[0]
|
|
case "DEFUN":
|
|
if len(arguments) != 3:
|
|
raise ValueError("Expected 3 arguments")
|
|
self.env[arguments[0]] = Function(arguments[1], arguments[2])
|
|
return arguments[0]
|
|
case "SET!":
|
|
if len(arguments) != 2:
|
|
raise ValueError("Expected 2 arguments")
|
|
if arguments[0] in self.env:
|
|
self.env[arguments[0]] = arguments[1]
|
|
else:
|
|
raise ValueError("Undefined variable: " + str(arguments[0]))
|
|
return arguments[0]
|
|
case "MAPCAR":
|
|
if len(arguments) != 3:
|
|
raise ValueError("Expected 3 arguments")
|
|
result = []
|
|
for i in range(0, min(len(arguments[1]), len(arguments[2]))):
|
|
result.append(self.evaluate([arguments[0], arguments[1][i], arguments[2][i]]))
|
|
return result
|
|
case _:
|
|
if operation in self.env.keys():
|
|
if type(self.env[operation]) == Function:
|
|
func = self.env[operation]
|
|
functionrunner = Lisp(self.env)
|
|
if len(arguments) != len(func.parameters):
|
|
raise ValueError("Expected " + str(len(func.parameters)) + " arguments")
|
|
for i in range(0, len(arguments)):
|
|
functionrunner.env[func.parameters[i]] = arguments[i]
|
|
return functionrunner.evaluate(self.env[operation].expression)
|
|
else:
|
|
raise TypeError("This value is not a valid function: " + operation)
|
|
else:
|
|
raise ValueError("Undefined operation: " + operation) |