src/evaluator.py
import datatypes
import environment
import dynamic
import copy
class Evaluator():
def __init__(self):
pass
def apply_function(self, function, args, env):
if datatypes.isLambda(function):
local_env = environment.Environment(
{},
outer=function.env,
bindings=function.args,
args=args)
return self.eval(function.body, local_env)
return function(*args)
def eval(self, expr, env):
if not datatypes.isFuthonObj(expr):
if isinstance(expr, list):
return self.eval_list(expr, env)
return expr
elif datatypes.isSymbol(expr):
return env.get(expr)
elif datatypes.isKeyword(expr):
return expr
elif datatypes.isVector(expr):
return datatypes.Vector([self.eval(e, env) for e in expr])
elif datatypes.isSet(expr):
return datatypes.Set([self.eval(e, env) for e in expr])
raise Exception("evaluation not yet implemented for type " +
str(type(expr)))
def eval_list(self, expr, env):
if len(expr) == 0:
return expr
head = expr[0]
if datatypes.isSymbol(head):
if head.name == 'def':
env.set(expr[1], self.eval(expr[2], env))
return None
elif head.name == 'set-attribute!':
e = self.eval(expr[1], env)
setattr(e, self.eval(expr[2], env), self.eval(expr[3], env))
return None
elif head.name == 'new':
v = self.eval(expr[1], env)
args = [self.eval(arg, env) for arg in expr[2:]]
return dynamic.make_instance(v, args)
elif head.name == 'quote':
return expr[1]
elif head.name == 'fn':
return datatypes.Lambda(expr[1], expr[2], copy.copy(env))
elif head.name == 'do':
v = None
for e in expr[1:]:
v = self.eval(e, env)
return v
elif head.name == 'if':
test = self.eval(expr[1], env)
if test:
return self.eval(expr[2], env)
elif len(expr) == 4:
return self.eval(expr[3], env)
else:
return None
elif head.name == 'and':
v = True
for e in expr[1:]:
v = self.eval(e, env)
if not v:
return v
return v
elif head.name == 'or':
v = None
for e in expr[1:]:
v = self.eval(e, env)
if v:
return v
return v
elif head.name == 'import':
return dynamic.import_module(expr[1].name)
elif head.name == 'count':
return len(expr[1])
elif head.name == 'type':
return type(self.eval(expr[1], env))
elif '.' in head.name:
if head.name == '.':
instance = self.eval(expr[1], env)
method_name = expr[2].name
args = [self.eval(arg, env) for arg in expr[3:]]
return dynamic.attribute_or_call(instance, method_name, args)
elif head.name[0] == '.':
instance = self.eval(expr[1], env)
method_name = head.name[1:]
args = [self.eval(arg, env) for arg in expr[2:]]
return dynamic.attribute_or_call(instance, method_name, args)
else:
f = self.eval(head, env)
args = [self.eval(arg, env) for arg in expr[1:]]
return f(*args)
else:
args = [self.eval(v, env) for v in expr[1:]]
return self.apply_function(env.get(head), args, env)
elif datatypes.isKeyword(head):
arg = self.eval(expr[1], env)
if datatypes.isHashMap(arg) or isinstance(arg, dict):
return arg.get(head)
elif datatypes.isSet(arg):
if head in arg:
return head
return None
raise Exception("applying Keyword to type " +
str(type(arg)) + "is not implemented")
elif datatypes.isLambda(head):
args = [self.eval(v, env) for v in expr[1:]]
return self.apply_function(head, args, env)
elif datatypes.isHashMap(head):
return head.get(self.eval(expr[1], env))
elif datatypes.isSet(head):
v = self.eval(expr[1], env)
if v in head:
return v
else:
return None
elif isinstance(head, list):
head = self.eval(head, env)
return self.eval([head] + expr[1:], env)
raise Exception("evaluation not yet implemented for head of type " +
str(type(head)))