# Evaluating Module from parse import * import math import operator as op # A user-defined Scheme procedure. class Procedure(object): def __init__(self, parms, body, env): self.parms, self.body, self.env = parms, body, env def __call__(self, *args): return eval(self.body, Env(self.parms, args, self.env)) # An environment: a dict with an outer Env. class Env(dict): def __init__(self, parms=(), args=(), outer=None): self.update(zip(parms, args)) self.outer = outer # Find the innermost Env where var appears. def find(self, var): return self if (var in self) else self.outer.find(var) # Manual definition of foldr def foldr(combine, base, lst): if len(lst) == 0: return base else: value = combine(lst[0], foldr(combine, base, lst[1:])) return value # Manual definition of foldl def foldl(combine, acc, lst): if len(lst) == 0: return acc else: return foldl( combine, combine(acc, lst[0]), lst[1:] ) # An environment with some Scheme standard procedures." def standard_env(): env = Env() env.update(vars(math)) env.update({ '+':op.add, '-':op.sub, '*':op.mul, '/':op.div, '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq, 'abs': abs, 'append': op.add, 'apply': apply, 'begin': lambda *x: x[-1], 'car': lambda x: x[0], 'cdr': lambda x: x[1:], 'cons': lambda x,y: [x] + y, 'eq?': op.is_, 'equal?': op.eq, 'length': len, 'list': lambda *x: list(x), 'list?': lambda x: isinstance(x,list), 'map': map, 'max': max, 'filter': filter, 'foldr': foldr, 'foldl': foldl, 'min': min, 'not': op.not_, 'null?': lambda x: x == [], 'number?': lambda x: isinstance(x, Number), 'procedure?': callable, 'round': round, 'symbol?': lambda x: isinstance(x, Symbol), }) return env global_env = standard_env() _quote = Sym('quote') _if = Sym('if') _set = Sym('set!') _define = Sym('define') _lambda = Sym('lambda') _begin = Sym('begin') _definemacro = Sym('define-macro') _quasiquote = Sym('quasiquote') _unquoto = Sym('unquote') _unquotesplicing = Sym('unquote-splicing') _checkexpect = Sym('check-expect') _checkwithin = Sym('check-within') _member = Sym('member?') _struct = Sym('struct') # Make predicates and field functions of a user defined struct def make_functions(name, param, env=global_env): create = 'make-' + name check = name + '?' index_array = [] key_array = [] i = 0 for par in param: index_array.append(i) i += 1 for par in param: key_array.append(name + '-' + par + '-pos') env.update(zip(key_array, index_array)) env[name + '-pos'] = lambda arr, index: arr[index] env[check] = lambda arr: len(arr) == eval(create) env[create] = len(param) # Evaluate an expression in an environment. def eval(x, env=global_env): if isinstance(x, Symbol): # variable reference return env.find(x)[x] elif not isinstance(x, list): # constant literal return x elif x[0] == _quote: # quotation (_, exp) = x return exp elif x[0] == _if: # conditional (_, test, conseq, alt) = x exp = (conseq if eval(test, env) else alt) return eval(exp, env) elif x[0] == _define: # definition (_, var, exp) = x env[var] = eval(exp, env) elif x[0] == _set: # assignment (_, var, exp) = x env.find(var)[var] = eval(exp, env) elif x[0] == _lambda: # procedure (_, parms, body) = x return Procedure(parms, body, env) elif x[0]== _checkexpect: # test exact (_, var, exp) = x return (eval(var, env) == eval(exp, env)) elif x[0] == _checkwithin: # test range (_, var, lower_bound, upper_bound) = x return ((eval(var, env) <= eval(upper_bound, env) and (eval(var, env) >= eval(lower_bound, env)))) elif x[0] == _member: # member? (_, var, lst) = x return (eval(var, env) in eval(lst, env)) elif x[0] == _struct: # struct definition (_, name, params) = x make_functions(name, params, env) else: # procedure call proc = eval(x[0], env) if ( isinstance(x[0], str) and x[0].startswith('make-')): args = [eval(arg, env) for arg in x[2:]] if len(args) != proc: print('TypeError: ' + x[0] + ' requires %d values, given %d' % (proc, len(args))) else: env[x[1]] = args return else: args = [eval(arg, env) for arg in x[1:]] return proc(*args)