def evaluate(ast, env): if is_list(ast): first_exp = ast[0] if first_exp == "atom": return is_atom(evaluate(ast[1],env)) elif first_exp == "define": return eval_define(ast[1:], env) elif first_exp == "if": return eval_if_statement(ast[1:], env) elif first_exp == "lambda": return eval_lambda(ast[1:], env) elif first_exp == "quote": return ast[1]; elif first_exp == "eq": return eval_equation(ast[1:], env) elif first_exp == "cons": return eval_list_cons(ast[1:], env) elif first_exp == "head": return eval_list_head(ast[1:], env) elif first_exp == "tail": return eval_list_tail(ast[1:], env) elif first_exp == "empty": return eval_list_empty(ast[1:], env) elif first_exp in math_operands: return eval_math_operation(first_exp, ast[1:], env) elif first_exp == "<": return evaluate(ast[1], env) < evaluate(ast[2], env) elif first_exp == "<=": return evaluate(ast[1], env) <= evaluate(ast[2], env) elif first_exp == ">": return evaluate(ast[1], env) > evaluate(ast[2], env) elif first_exp == ">=": return evaluate(ast[1], env) >= evaluate(ast[2], env) elif is_list(first_exp) or is_symbol(first_exp): eval_first = evaluate(first_exp, env) return evaluate([eval_first]+ast[1:], env) elif is_closure(first_exp): arguments = ast[1:] return evaluate(first_exp.body, first_exp.env.extend(evaluate_function_arguments(first_exp, arguments, env))) else: raise LispError('{0} not a function'.format(first_exp)) elif is_symbol(ast): return env.lookup(ast) elif is_atom(ast): return ast
def __init__(self, variables=None): from ast import is_boolean, is_atom, is_symbol, is_list, is_closure, is_integer self.variables = variables if variables else {} arithmetic = { '+': operator.add, '-': operator.sub, '*': operator.mul, '/': operator.div, 'mod': operator.mod, '<': operator.lt, '<=': operator.le, '>': operator.gt, '>=': operator.ge, } for op, fun in arithmetic.iteritems(): self.variables[op] = partial(_arithmetic_function, fun) self.variables['eq'] = lambda x, y: is_atom(x) and is_atom(y) and x == y self.variables['cons'] = lambda x, y: [x] + y self.variables['head'] = partial(_require_nonempty_list, lambda x: x[0]) self.variables['tail'] = lambda x: x[1:] self.variables['empty'] = lambda x: len(x) == 0
def evaluate(ast, env): """Evaluate an Abstract Syntax Tree in the specified environment.""" math_operators = ["+", "-", "*", "/", "mod", ">"] exprs = { "quote" : lambda ast: ast[1], "atom" : lambda ast: is_atom(evaluate(ast[1], env)), "eq" : lambda ast: (evaluate(["atom", ast[1]], env) and evaluate(["atom", ast[2]], env) and evaluate(ast[1], env) == evaluate(ast[2], env)), "if" : lambda ast: eval_if_statement(ast, env), "define" : lambda ast: eval_define(ast, env), "lambda" : lambda ast: eval_lambda(ast, env), "cons" : lambda ast: eval_cons(ast, env), "head" : lambda ast: eval_head(ast, env), "tail" : lambda ast: eval_tail(ast, env), "empty" : lambda ast: eval_empty(ast, env), "env" : lambda ast: eval_in_env(ast, env) } exprs.update(exprs.fromkeys(math_operators, lambda ast: eval_math_operators(ast, env))) if is_symbol(ast): return env.lookup(ast) elif is_atom(ast): return ast elif is_list(ast): expr = ast[0] if not(is_list(ast[0])) else "env" return exprs.get(expr, exprs["env"])(ast)
def evaluate(ast, env): """Evaluate an Abstract Syntax Tree in the specified environment.""" if is_list(ast): if ast[0] == "quote": return ast[1] if ast[0] == "define": if not len(ast) == 3: raise LispError("Wrong number of arguments") if not is_symbol(ast[1]): raise LispError("non-symbol") env.set(ast[1], evaluate(ast[2], env)) return if ast[0] == "if": if evaluate(ast[1], env): return evaluate(ast[2], env) else: return evaluate(ast[3], env) if ast[0] == "atom": return is_atom(evaluate(ast[1], env)) if ast[0] == "eq": if not is_atom(evaluate(ast[1], env)) or not is_atom(evaluate(ast[2], env)): return False return evaluate(ast[1], env) == evaluate(ast[2], env) try: if ast[0] == "+": return evaluate(ast[1], env) + evaluate(ast[2], env) if ast[0] == "-": return evaluate(ast[1], env) - evaluate(ast[2], env) if ast[0] == "/": return evaluate(ast[1], env) / evaluate(ast[2], env) if ast[0] == "*": return evaluate(ast[1], env) * evaluate(ast[2], env) if ast[0] == "mod": return evaluate(ast[1], env) % evaluate(ast[2], env) if ast[0] == "<": return evaluate(ast[1], env) < evaluate(ast[2], env) if ast[0] == ">": return evaluate(ast[1], env) > evaluate(ast[2], env) except TypeError: raise LispError("TypeError") if is_symbol(ast): return env.lookup(ast) else: return ast
def eq(ast, env): assert_exp_length(ast, 2) a = evaluate(ast[0], env) if not is_atom(a): return False b = evaluate(ast[1], env) if not is_atom(b): return False return a == b
def evaluate(ast, env): """Evaluate an Abstract Syntax Tree in the specified environment.""" if is_boolean(ast) or is_integer(ast): return ast elif is_symbol(ast): return env.lookup(ast) if not is_atom(ast[0]): ast[0] = evaluate(ast[0], env) elif is_symbol(ast[0]): if ast[0] in keywords: return keywords[ast[0]](ast, env) elif ast[0] in math_operators: return eval_math(ast, env) else: ast[0] = env.lookup(ast[0]) if is_closure(ast[0]): args = [evaluate(x, env) for x in ast[1:]] num_args = len(args) num_params = len(ast[0].params) if num_args != num_params: raise LispError('wrong number of arguments, expected %d got %d' % (num_params, num_args)) bindings = dict(zip(ast[0].params, args)) return evaluate(ast[0].body, ast[0].env.extend(bindings)) raise LispError('not a function: %s' % unparse(ast[0]))
def evaluate(ast, env): """Evaluate an Abstract Syntax Tree in the specified environment. """ print ast if is_atom(ast) or ast == []: if is_symbol(ast): return evaluate(env.lookup(ast), env) else: return ast if is_list(ast[0]): ast[0] = evaluate(ast[0], env) if ast[0] in MATH_EXP.keys(): return _evaluate_math(ast, env) for _map in (CONTROL_EXP, EVAL_EXP, VAR_EXP, CLOSURE_EXP, LIST_EXP): if ast[0] in _map.keys(): func = _map[ast[0]] return evaluate(func(ast[1:], env), env) if is_symbol(ast[0]): ast[0] = env.lookup(ast[0]) if is_closure(ast[0]): if len(ast[1:]) != len(ast[0].params): raise LispError('wrong number of arguments, expected %s got %s' % (len(ast[0].params), len(ast[1:]))) arguments = [evaluate(arg, env) for arg in ast[1:]] parameters = dict(zip(ast[0].params, arguments)) env = ast[0].env.extend(parameters) return evaluate(ast[0].body, env) return [evaluate(a, env) for a in ast]
def evaluate(ast, env): """Evaluate an Abstract Syntax Tree in the specified environment.""" if is_symbol(ast): if ast[0] == '"': return ast return env.lookup(ast) elif is_atom(ast): return ast elif is_list(ast): return eval_list(ast, env) else: raise LispError('Syntax error: %s' % unparse(ast))
def evaluate(ast, env): """Evaluate an Abstract Syntax Tree in the specified environment.""" if is_boolean(ast): return ast elif is_integer(ast): return ast elif ast[0] in ['+', '-', '*', '/']: return eval_math(ast, env) elif is_list(ast): if ast[0] == "atom": return is_atom(evaluate(ast[1], env)) #return is_atom(ast[1]) elif ast[0] == "quote": return ast[1] elif ast[0] == "eq": assert_exp_length(ast, 3) v1 = evaluate(ast[1], env) v2 = evaluate(ast[2], env) if not is_atom(v1) or not is_atom(v2): return False else: return (v1 == v2)
def evaluate(ast, env): """Evaluate an Abstract Syntax Tree in the specified environment.""" if is_atom(ast): if is_symbol(ast): return forms[ast] if ast in forms else env.lookup(ast) else: return ast else: if (len(ast) == 0): return [] fn = evaluate(ast[0], env) args = ast[1:] if len(ast) > 1 else [] if callable(fn): return fn(args, env) if is_closure(fn): return apply(fn, args, env) elif is_list(fn): return evaluate([evaluate(fn, env)] + args, env) else: raise LispError("%s is not a function." % unparse(fn))
def evaluate(ast, env): """Evaluate an Abstract Syntax Tree in the specified environment. """ if is_boolean(ast) or is_integer(ast): # evaluate booleans and integers return ast elif is_symbol(ast): # evaluate symbols return env.lookup(ast) elif is_list(ast): # evaluate lists if is_closure(ast[0]): # evaluate closure return eval_closure(ast, env) elif ast[0] == 'quote': # evaluate quotes return ast[1] elif ast[0] == 'atom': # evaluate atoms return is_atom(evaluate(ast[1], env)) elif ast[0] == 'eq': # evaluate equality return eval_eq(ast, env) # evaluate basic math operators: elif ast[0] in ['+', '-', '/', '*', 'mod', '>', '<', '=']: return eval_math(ast, env) elif ast[0] == 'if': # evaluate if expression return eval_if(ast, env) elif ast[0] == 'define': # evaluate define statement eval_define(ast, env) elif ast[0] == 'lambda': # evaluate lambda statement return eval_lambda(ast, env) elif ast[0] == 'cons': # evaluate cons statement return eval_cons(ast, env) elif ast[0] == 'head': # evaluate head statement return eval_head(ast, env) elif ast[0] == 'tail': # evaluate tail statement return eval_tail(ast, env) elif ast[0] == 'empty': # evaluate empty statement return eval_empty(ast, env) elif is_symbol(ast[0]) or is_list(ast[0]): # evaluate closure from env return eval_closure_env(ast, env) else: raise LispError('Argument is not a function!')
def evaluate(ast, env): """Evaluate an Abstract Syntax Tree in the specified environment.""" # Simple types if is_symbol(ast): splitast = ast.split(' ') if splitast[0] == 'define': return Environment.extend(env, dict(zip(splitast[1:2], splitast[2::]))) else: return Environment.lookup(env, ast) if is_boolean(ast) or is_integer(ast): return ast if is_list(ast): # Basic arithmetic if ast[0] == '+': if is_integer(evaluate(ast[1], env)) and is_integer(evaluate(ast[2], env)): return evaluate(ast[1], env) + evaluate(ast[2], env) if ast[0] == '-': if is_integer(evaluate(ast[1], env)) and is_integer(evaluate(ast[2], env)): return evaluate(ast[1], env) - evaluate(ast[2], env) if ast[0] == '/': if is_integer(evaluate(ast[1], env)) and is_integer(evaluate(ast[2], env)): return evaluate(ast[1], env) / evaluate(ast[2], env) if ast[0] == '*': if is_integer(evaluate(ast[1], env)) and is_integer(evaluate(ast[2], env)): return evaluate(ast[1], env) * evaluate(ast[2], env) if ast[0] == 'mod': if is_integer(evaluate(ast[1], env)) and is_integer(evaluate(ast[2], env)): return evaluate(ast[1], env) % evaluate(ast[2], env) if ast[0] == '>': if is_integer(evaluate(ast[1], env)) and is_integer(evaluate(ast[2], env)): return evaluate(ast[1], env) > evaluate(ast[2], env) if ast[0] == '<': if is_integer(evaluate(ast[1], env)) and is_integer(evaluate(ast[2], env)): return evaluate(ast[1], env) < evaluate(ast[2], env) # Atoms, quotes and equal if ast[0] == 'atom': return is_atom(evaluate(ast[1], env)) if ast[0] == 'quote': return ast[1] if ast[0] == 'eq': return ( is_atom(evaluate(ast[1], env)) and is_atom(evaluate(ast[2], env)) and evaluate(ast[1], env) == evaluate(ast[2], env) ) # If statement if ast[0] == 'if': if evaluate(ast[1], env) == True: return evaluate(ast[2], env) if evaluate(ast[1], env) == False: return evaluate(ast[3], env) # Lists if ast[0] == 'cons': head = evaluate(ast[1], env) tail = evaluate(ast[2], env) return [head] + tail if ast[0] == 'head': eval_new_ast = evaluate(ast[1], env) if eval_new_ast == []: raise LispError else: return eval_new_ast[0] if ast[0] == 'tail': eval_new_ast = evaluate(ast[1], env) if eval_new_ast == []: raise LispError else: return eval_new_ast[1:] if ast[0] == 'empty': if evaluate(ast[1], env) == []: return True else: return False # Functions if ast[0] == 'define': assert_valid_definition(ast[1:]) symbol = ast[1] value = evaluate(ast[2], env) env.set(symbol, value) return symbol if ast[0] == 'lambda': if len(ast) != 3: raise LispError("Wrong number of arguments") if not is_list(ast[1]): raise LispError("Parameters are not in list-form") else: return Closure(env, ast[1], ast[2]) if is_closure(ast[0]): closure = ast[0] arguments = ast[1:] if len(arguments) != len(closure.params): errormessage = "wrong number of arguments, expected " + str(len(closure.params)) + " got " + str(len(arguments)) raise LispError(errormessage) arguments = [evaluate(a, env) for a in arguments] bindings = dict(zip(closure.params, arguments)) new_env = closure.env.extend(bindings) return evaluate(closure.body, new_env) if is_list(ast[0]) or is_symbol(ast[0]): closure = evaluate(ast[0], env) return evaluate([closure] + ast[1:], env) else: raise LispError("not a function") else: raise LispError
def eval_equation(args, env): eval1 = evaluate(args[0],env) eval2 = evaluate(args[1],env) if not (is_atom(eval1) and is_atom(eval2)): return False return eval1 == eval2
def evaluate(ast, env): """Evaluate an Abstract Syntax Tree in the specified environment.""" if ast == "#t": return True if ast == "#f": return False if is_symbol(ast): symbol_value = env.lookup(ast) # if is_closure(symbol_value): # return evaluate(symbol_value, env) return symbol_value if is_integer(ast): return ast first_element = ast[0] if first_element == "quote": if len(ast) == 2: return ast[1] else: return [] if first_element == "atom": return is_atom(evaluate(ast[1], env)) if first_element == "if": if evaluate(ast[1], env): return evaluate(ast[2], env) else: return evaluate(ast[3], env) if first_element == "define": if len(ast) != 3: raise LispError("Wrong number of arguments") symbol_name = ast[1] if not is_symbol(symbol_name): raise LispError("non-symbol") value = evaluate(ast[2], env) env.set(symbol_name, value) return value if first_element == "eq": evaluated_items = [evaluate(item, env) for item in ast[1:]] for i in range(len(evaluated_items) - 1): return is_atom(evaluated_items[i]) and evaluated_items[i] == evaluated_items[i + 1] else: return True if first_element in ["+", "-", "*", "/", "mod", "<", ">"] and not (is_integer(evaluate(ast[1], env)) and is_integer( evaluate(ast[2], env))): error_message = "Math functions only take integer args but you tried to do (%s, %s, %s)" % ( first_element, (evaluate(ast[1], env)), (evaluate(ast[2], env))) raise LispError(error_message) if first_element == "+": return evaluate(ast[1], env) + evaluate(ast[2], env) if first_element == "-": return evaluate(ast[1], env) - evaluate(ast[2], env) if first_element == "*": return evaluate(ast[1], env) * evaluate(ast[2], env) if first_element == "/": return evaluate(ast[1], env) / evaluate(ast[2], env) if first_element == "mod": return evaluate(ast[1], env) % evaluate(ast[2], env) if first_element == ">": return evaluate(ast[1], env) > evaluate(ast[2], env) if first_element == "<": return evaluate(ast[1], env) < evaluate(ast[2], env) # List functions if first_element == "cons": if len(ast) != 3: raise LispError("cons requires 2 arguments") element = evaluate(ast[1], env) list = evaluate(ast[2], env) if not is_list(list): raise LispError("cons requires second arg to be list but got %s" % unparse(ast[2])) list.insert(0, element) return list if first_element == "head": if len(ast) != 2: raise LispError("head requires 1 argument") list_expression = evaluate(ast[1], env) if not is_list(list_expression) or len(list_expression) < 1: raise LispError("head requires a list of at least length 1") return list_expression[0] if first_element == "tail": if len(ast) != 2: raise LispError("tail requires 1 argument") list_expression = evaluate(ast[1], env) if not is_list(list_expression) or len(list_expression) < 1: raise LispError("tail requires a list argument") return list_expression[1:] if first_element == "empty": if len(ast) != 2: raise LispError("empty requires 1 argument") list_expression = evaluate(ast[1], env) if not is_list(list_expression): raise LispError("empty requires a list argument") return len(list_expression) == 0 # Function functions if first_element == "lambda": if len(ast) != 3: raise LispError("number of arguments") params = ast[1] if not is_list(params): raise LispError("params must be a list") body = ast[2] return Closure(env, params, body) if first_element == "quit": raise QuitError("Bye!") if first_element == "print": print "".join((str(evaluate(i, env)) for i in ast[1:])) return [] if first_element == "pp": print " ".join((str(evaluate(i, env)) for i in ast[1:])) return [] if first_element == "do": for i in ast[1:-1]: evaluate(i, env) return evaluate(ast[-1], env) if is_list(ast): if len(ast) == 0: return [] if is_symbol(first_element) and env.has_symbol(first_element): closure = env.lookup(first_element) elif is_closure(first_element): closure = first_element else: closure = evaluate(first_element, env) if not is_closure(closure): raise LispError("not a function") argument_bindings = {} if len(ast) > 1: param_values = ast[1:] closure_params = closure.params if len(closure_params) != len(param_values): raise LispError("wrong number of arguments, expected %i got %i" % (len(closure_params), len(param_values))) for i in range(len(closure_params)): param_name = closure_params[i] argument_bindings[param_name] = evaluate(param_values[i], env) result = evaluate(closure.body, closure.env.extend(argument_bindings)) if is_closure(result): return evaluate(result.body, result.env) return result
def _eval_eq(ast, env): ast = evaluate(ast, env) if not is_atom(ast[0]) or not is_atom(ast[1]): return False return ast[0] == ast[1]
assert_symbol(symbol) if symbol in forms: return "<form/%s>" % symbol else: val = env.lookup(symbol) if is_closure(val): return "(lambda %s %s)" % (unparse(val.params), unparse(val.body)) else: return val forms = { "+" : math(lambda a, b: a + b) , "-" : math(lambda a, b: a - b) , "/" : math(lambda a, b: a / b) , "*" : math(lambda a, b: a * b) , ">" : math(lambda a, b: a > b) , "mod" : math(lambda a, b: a % b) , "if" : cond , "eq" : eq , "cons" : cons , "head" : head , "tail" : tail , "empty" : empty , "atom" : lambda ast, env: is_atom(evaluate(ast[0], env)) , "quote" : lambda ast, env: ast[0] , "source" : source , "lambda" : fn , "define" : defn }
def evaluate(ast, env): """Evaluate an Abstract Syntax Tree in the specified environment.""" # evaluating booleans, integers, symbols and quotes if is_boolean(ast): return ast elif is_integer(ast): return ast elif is_symbol(ast): return env.lookup(ast) elif ast[0] == "quote": return ast[1] # everything else is of list form elif is_list(ast): # evaluating atom and eq functions if ast[0] == "atom": return is_atom(evaluate(ast[1], env)) elif ast[0] == "eq": aste = [evaluate(s, env) for s in ast[1:]] return is_atom(aste[0]) and aste[0] == aste[1] # evaluating basic math operators elif ast[0] == "+": if is_integer(evaluate(ast[1], env)) and is_integer(evaluate(ast[2], env)): return evaluate(ast[1], env) + evaluate(ast[2], env) else: raise LispError('Arguments must be integers') elif ast[0] == "-": if is_integer(evaluate(ast[1], env)) and is_integer(evaluate(ast[2], env)): return evaluate(ast[1], env) - evaluate(ast[2], env) else: raise LispError('Arguments must be integers') elif ast[0] == "*": if is_integer(evaluate(ast[1], env)) and is_integer(evaluate(ast[2], env)): return evaluate(ast[1], env) * evaluate(ast[2], env) else: raise LispError('Arguments must be integers') elif ast[0] == "mod": if is_integer(evaluate(ast[1], env)) and is_integer(evaluate(ast[2], env)): return evaluate(ast[1], env) % evaluate(ast[2], env) else: raise LispError('Arguments must be integers') elif ast[0] == "/": if is_integer(evaluate(ast[1], env)) and is_integer(evaluate(ast[2], env)): return evaluate(ast[1], env) / evaluate(ast[2], env) else: raise LispError('Arguments must be integers') elif ast[0] == ">": return evaluate(ast[1], env) > evaluate(ast[2], env) elif ast[0] == "<": return evaluate(ast[1], env) < evaluate(ast[2], env) # Evaluating complex expressions # basic if statement elif ast[0] == 'if': if (evaluate(ast[1], env)) is True: return evaluate(ast[2], env) else: return evaluate(ast[3], env) # definitions of variables elif ast[0] == "define": if is_symbol(ast[1]): if len(ast) == 3: return env.set(ast[1], evaluate(ast[2], env)) else: raise LispError("Wrong number of arguments") else: raise LispError("non-symbol") # evaluating a list in which the first element is a closure elif is_closure(ast[0]): closure = ast[0] arguments = ast[1:] parameters = closure.params if len(arguments) != len(parameters): raise LispError('wrong number of arguments, expected 2 got 3') bindings = {} for x in range(len(ast[1:])): arg1 = evaluate(arguments[x], env) param1 = parameters[x] bindings.update({param1: arg1}) return evaluate(closure.body, closure.env.extend(bindings)) elif ast[0] == 'lambda': if not is_list(ast[1]): raise LispError('not a list') if len(ast) == 3: return Closure(env, ast[1], ast[2]) else: raise LispError('number of arguments') # new forms such as cons, head, tail and empty elif ast[0] == "cons": if len(ast) != 3: raise LispError("expected 2 arguments") else: list = [evaluate(x, env) for x in ast[1:]] return [list[0]] + list[1] elif ast[0] == "head": list = [evaluate(x, env) for x in ast[1:]] if list[0] == []: raise LispError('empty list') return list[0][0] elif ast[0] == "tail": list = evaluate(ast[1], env) if list == []: raise LispError('empty list') else: return list[1:] elif ast[0] == "empty": list = evaluate(ast[1], env) return (list == []) elif is_symbol(ast[0]) or is_list(ast[0]): closure = evaluate(ast[0], env) return evaluate([closure] + ast[1:], env) else: raise LispError("not a function")
def eval_eq(ast, env): assert_exp_length(ast, 3) args = [evaluate(x, env) for x in ast[1:]] return is_atom(args[0]) and args[0] == args[1]
def _eval_atom(ast, env): return is_atom(evaluate(ast[0], env))
def evalAtomCommand(args, env): if len(args) != 1: raise LispError("atom command expects exactly one argument") return is_atom(args[0])
def evaluate(self, env): return is_atom(evaluate(self.ast[1], env))
def eval_eq(ast, env): """Evaluate an eq statement in the specified environment. """ a1 = evaluate(ast[1], env) a2 = evaluate(ast[2], env) return is_atom(a1) and is_atom(a2) and a1 == a2
def evaluate(ast, env): """Evaluate an Abstract Syntax Tree in the specified environment.""" print ast, env.variables # otherwise, it will be a function op = ast[0] args = ast[1:] # Simple Evaluation # quote evaluation if op == "quote": assert_exp_length(args, 1) return evaluate(args[0], env) # atom function if op == "atom": assert_exp_length(args, 1) return is_atom(evaluate(args[0], env)) # arithematic evaluation if op in ['+', '-', '*', '/', 'mod', '>']: assert_exp_length(args, 2) arg1 = evaluate(args[0], env) arg2 = evaluate(args[1], env) if not (is_integer(arg1) and is_integer(arg2)): raise LispError("Arguments of arithmetic operator should be numbers") return eval_arithmetic(op, arg1, arg2) # define evaluation if op == "define": try: assert_exp_length(args, 2) except LispError: raise LispError("Wrong number of arguments") var_name = args[0] var_value = evaluate(args[1], env) if not is_symbol(var_name): raise LispError("non-symbol: %s" % var_name) env.set(var_name, var_value) return var_name # equal evaluation if op == "eq": eval_arg1 = evaluate(args[0], env) eval_arg2 = evaluate(args[1], env) return is_atom(eval_arg1) and is_atom(eval_arg2) and eval_arg1 == eval_arg2 # Complex Evaluation # if evaluation if op == "if": assert_exp_length(args, 3) eval_predicate = evaluate(args[0], env) if eval_predicate: return evaluate(args[1], env) else: return evaluate(args[2], env) if op == 'lambda': try: assert_exp_length(args, 2) except LispError: raise LispError("number of arguments") print len(args) lambda_params = args[0] lambda_body = args[1] return Closure(env, lambda_params, lambda_body) if is_closure(op): closure = op assert_exp_length(args, len(closure.params)) new_env = Environment(closure.env.variables.copy()) for n, param in enumerate(closure.params): new_env.set(param, evaluate(args[n], new_env)) return evaluate(closure.body, new_env) # fundamental if is_symbol(ast): print 'is_symbol' try: return evaluate(env.lookup(ast), env) except: if len(ast) == 1: raise LispError("undefined: %s" % ast[0]) else: raise LispError("not a function: %s" % ast[0]) if is_atom(ast): print 'is_atom' return ast if is_list(ast): print 'is_list' return evaluate(map(lambda inner_ast: evaluate(inner_ast, env), ast), env)
def evaluate(self, env): if not is_atom(evaluate(self.ast[1], env)) or not is_atom(evaluate(self.ast[2], env)): return False return evaluate(self.ast[1], env) ==evaluate(self.ast[2], env)
def evaluate(ast, env): """Evaluate an Abstract Syntax Tree in the specified environment.""" if is_boolean(ast) or is_integer(ast): return ast elif is_symbol(ast): return env.lookup(ast) elif is_list(ast): f = ast[0] params = ast[1:] if is_list(f): c = evaluate(f, env) return evaluate([c] + params, env) elif f == 'quote': return params[0] elif f == 'atom': return is_atom(evaluate(params[0], env)) elif f == 'if': test = evaluate(params[0], env) if not is_boolean(test): raise LispError("First argument to if must be boolean") if test: return evaluate(params[1], env) else: return evaluate(params[2], env) elif f == 'define': if len(params) != 2: raise LispError("Wrong number of arguments") elif not is_symbol(params[0]): raise LispError("First argument to define is a non-symbol") env.set(params[0], evaluate(params[1], env)) elif f == 'lambda': if len(params) != 2: raise LispError("Wrong number of arguments") return Closure(env, params[0], params[1]) elif is_closure(f): evaled_params = {} for i, symbol in enumerate(f.params): evaled_params[symbol] = evaluate(params[i], env) return evaluate(f.body, f.env.extend(evaled_params)) elif is_symbol(f): evaled = evaluate(f, env) if callable(evaled): # python function evaled_params = [] for p in params: evaled_params.append(evaluate(p, env)) return evaled(*evaled_params) elif is_closure(evaled): expected_arg_length = len(evaled.params) actual_arg_length = len(params) if expected_arg_length != actual_arg_length: raise LispError("wrong number of arguments, expected " + str(expected_arg_length) + " got " + str(actual_arg_length)) return evaluate([evaled] + params, env) else: raise LispError() else: raise LispError(str(ast) + "is not a function") else: raise LispError("xxx")
def evaluate(ast, env): """Evaluate an Abstract Syntax Tree in the specified environment.""" # evaluating atoms if is_symbol(ast): return env.lookup(ast) if is_boolean(ast): return ast if is_integer(ast): return ast if is_list(ast): # lists if ast[0] == "cons": if len(ast) != 3: raise LispError("expected 2 arguments") else: value = evaluate(ast[1], env) list = evaluate(ast[2], env) new_list = [value] for i in list: new_list.append(i) return new_list if ast[0] == "head": list = evaluate(ast[1], env) if list == []: raise LispError else: return list[0] if ast[0] == "tail": list = evaluate(ast[1], env) if list == []: raise LispError else: return list[1:] if ast[0] == "empty": list = evaluate(ast[1], env) if list == []: return True else: return False if ast[0] == "quote": return ast[1] # functions if is_closure(ast[0]): closure = ast[0] arguments = ast[1:] params = closure.params number_of_arguments = len(arguments) number_of_params = len(params) if number_of_arguments != number_of_params: raise LispError("wrong number of arguments, expected %(param)d got %(arg)d" % {"arg": number_of_arguments, "param": number_of_params}) variables = {} for i in range(number_of_arguments): arg = evaluate(arguments[i], env) param = params[i] variables.update({param: arg}) environment = closure.env.extend(variables) return evaluate(closure.body, environment) if ast[0] == "lambda": if not is_list(ast[1]): raise LispError if len(ast) == 3: return Closure(env, ast[1], ast[2]) else: raise LispError("number of arguments") # defining variables if ast[0] == "define": if is_symbol(ast[1]): if len(ast) == 3: return env.set(ast[1], evaluate(ast[2], env)) else: raise LispError("Wrong number of arguments") else: raise LispError("non-symbol") #typechecks if ast[0] == "atom": return is_atom(evaluate(ast[1], env)) if ast[0] == "eq": return evaluate(ast[1], env) == evaluate(ast[2], env) and \ is_atom(evaluate(ast[1], env)) and is_atom(evaluate(ast[2], env)) #arithmetic: # elif is_arith_op(ast[0]): # try: # return arith_ops[ast[0]](evaluate(ast[1], env), evaluate(ast[2], env)) # make dicitonary of these operators if ast[0] == "+": if is_integer(evaluate(ast[1], env)) and is_integer(evaluate(ast[2], env)): return evaluate(ast[1], env) + evaluate(ast[2], env) else: raise LispError if ast[0] == "-": if is_integer(evaluate(ast[1], env)) and is_integer(evaluate(ast[2], env)): return evaluate(ast[1], env) - evaluate(ast[2], env) else: raise LispError if ast[0] == "*": if is_integer(evaluate(ast[1], env)) and is_integer(evaluate(ast[2], env)): return evaluate(ast[1], env) * evaluate(ast[2], env) else: raise LispError if ast[0] == "/": if is_integer(evaluate(ast[1], env)) and is_integer(evaluate(ast[2], env)): return evaluate(ast[1], env) / evaluate(ast[2], env) else: raise LispError if ast[0] == "mod": if is_integer(evaluate(ast[1], env)) and is_integer(evaluate(ast[2], env)): return evaluate(ast[1], env) % evaluate(ast[2], env) else: raise LispError # boolean operators if ast[0] == ">": return evaluate(ast[1], env) > evaluate(ast[2], env) if ast[0] == "<": return evaluate(ast[1], env) < evaluate(ast[2], env) # control-flow if ast[0] == 'if': pred = ast[1] then = ast[2] elsee = ast[3] if evaluate(pred, env): return evaluate(then, env) else: return evaluate(elsee, env) if is_symbol(ast[0]) or is_list(ast[0]): closure = evaluate(ast[0], env) return evaluate([closure] + ast[1:], env) else: raise LispError("not a function")
def eval_atom(ast, env): assert_exp_length(ast, 2) return is_atom(evaluate(ast[1], env))