diff options
| author | Joel Martin <github@martintribe.org> | 2014-04-02 22:23:37 -0500 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2014-04-02 22:23:37 -0500 |
| commit | ea81a8087bcd7953b083a2be9db447f75e7ebf56 (patch) | |
| tree | 6cf47a2dbd55d42efc4a901eaabdec952f40ce89 /python/mal_types.py | |
| parent | 1617910ad342a55762f3ddabb975849d843cff85 (diff) | |
| download | mal-ea81a8087bcd7953b083a2be9db447f75e7ebf56.tar.gz mal-ea81a8087bcd7953b083a2be9db447f75e7ebf56.zip | |
All: split types into types, env, printer, core.
- types: low-level mapping to the implementation language.
- core: functions on types that are exposed directly to mal.
- printer: implementation called by pr-str, str, prn, println.
- env: the environment implementation
- Also, unindent all TCO while loops so that the diff of step4 and
step5 are minimized.
Diffstat (limited to 'python/mal_types.py')
| -rw-r--r-- | python/mal_types.py | 251 |
1 files changed, 32 insertions, 219 deletions
diff --git a/python/mal_types.py b/python/mal_types.py index 401a03b..15e4b6b 100644 --- a/python/mal_types.py +++ b/python/mal_types.py @@ -1,71 +1,17 @@ -import copy -from itertools import chain - # General functions -def _pr_str(obj, print_readably=True): - _r = print_readably - if list_Q(obj): - return "(" + " ".join(map(lambda e: _pr_str(e,_r), obj)) + ")" - elif vector_Q(obj): - return "[" + " ".join(map(lambda e: _pr_str(e,_r), obj)) + "]" - elif hash_map_Q(obj): - ret = [] - for k in obj.keys(): - ret.extend((_pr_str(k), _pr_str(obj[k],_r))) - return "{" + " ".join(ret) + "}" - elif string_Q(obj): - if print_readably: - return '"' + obj.encode('unicode_escape').replace('"', '\\"') + '"' - else: - return obj - elif nil_Q(obj): - return "nil" - elif true_Q(obj): - return "true" - elif false_Q(obj): - return "false" - elif atom_Q(obj): - return "(atom " + _pr_str(obj.val,_r) + ")" - else: - return obj.__str__() - -def pr_str(*args): - return " ".join(map(lambda exp: _pr_str(exp, True), args)) - -def do_str(*args): - return "".join(map(lambda exp: _pr_str(exp, False), args)) - -def prn(*args): - print " ".join(map(lambda exp: _pr_str(exp, True), args)) - return None - -def println(*args): - line = " ".join(map(lambda exp: _pr_str(exp, False), args)) - print line.replace('\\n', '\n') - return None - -def with_meta(obj, meta): - new_obj = copy.copy(obj) - new_obj.__meta__ = meta - return new_obj - -def meta(obj): - if hasattr(obj, "__meta__"): return obj.__meta__ - else: return None - -def equal_Q(a, b): +def _equal_Q(a, b): ota, otb = type(a), type(b) - if not (ota == otb or (sequential_Q(a) and sequential_Q(b))): + if not (ota == otb or (_sequential_Q(a) and _sequential_Q(b))): return False; - if symbol_Q(a): + if _symbol_Q(a): return a == b - elif list_Q(a) or vector_Q(a): + elif _list_Q(a) or _vector_Q(a): if len(a) != len(b): return False for i in range(len(a)): - if not equal_Q(a[i], b[i]): return False + if not _equal_Q(a[i], b[i]): return False return True - elif hash_map_Q(a): + elif _hash_map_Q(a): akeys = a.keys() akeys.sort() bkeys = b.keys() @@ -78,70 +24,26 @@ def equal_Q(a, b): else: return a == b -# nil, true, false -def nil_Q(exp): return exp is None -def true_Q(exp): return exp is True -def false_Q(exp): return exp is False -def string_Q(exp): return type(exp) in [str, unicode] +def _sequential_Q(seq): return _list_Q(seq) or _vector_Q(seq) -# numbers -int_plus = lambda a,b: a+b -int_minus = lambda a,b: a-b -int_multiply = lambda a,b: a*b -int_divide = lambda a,b: a/b -int_lt = lambda a,b: a<b -int_lte = lambda a,b: a<=b -int_gt = lambda a,b: a>b -int_gte = lambda a,b: a>=b +# Scalars +def _nil_Q(exp): return exp is None +def _true_Q(exp): return exp is True +def _false_Q(exp): return exp is False +def _string_Q(exp): return type(exp) in [str, unicode] -# symbols +# Symbols class Symbol(str): pass -def new_symbol(str): return Symbol(str) -def symbol_Q(exp): return type(exp) == Symbol +def _symbol(str): return Symbol(str) +def _symbol_Q(exp): return type(exp) == Symbol - -# functions -def new_function(func, exp, env, params): +# Functions +def _function(Eval, Env, exp, env, params): def f(*args): - return func(exp, Env(env, params, args)) + return Eval(exp, Env(env, params, args)) f.__meta__ = {"exp": exp, "env": env, "params": params} return f -def function_Q(f): return type(f) == type(function_Q) - -# hash maps -class Hash_Map(dict): pass -def new_hash_map(*key_vals): - hm = Hash_Map() - for i in range(0,len(key_vals),2): hm[key_vals[i]] = key_vals[i+1] - return hm -def hash_map_Q(exp): return type(exp) == Hash_Map - -def assoc(src_hm, *key_vals): - hm = copy.copy(src_hm) - for i in range(0,len(key_vals),2): hm[key_vals[i]] = key_vals[i+1] - return hm - -def dissoc(src_hm, *keys): - hm = copy.copy(src_hm) - for key in keys: del hm[key] - return hm - -def get(hm, key): - if key in hm: - return hm[key] - else: - return None - -def contains_Q(hm, key): return key in hm - -def keys(hm): return new_list(*hm.keys()) - -def vals(hm): return new_list(*hm.values()) - - -# errors/exceptions -def throw(exc): raise Exception(exc) - +def _function_Q(f): return type(f) == type(function_Q) # lists class List(list): @@ -151,8 +53,8 @@ class List(list): elif i >= len(self): return None else: return list.__getitem__(self, i) def __getslice__(self, *a): return List(list.__getslice__(self, *a)) -def new_list(*vals): return List(vals) -def list_Q(exp): return type(exp) == List +def _list(*vals): return List(vals) +def _list_Q(exp): return type(exp) == List # vectors @@ -163,109 +65,20 @@ class Vector(list): elif i >= len(self): return None else: return list.__getitem__(self, i) def __getslice__(self, *a): return Vector(list.__getslice__(self, *a)) -def new_vector(*vals): return Vector(vals) -def vector_Q(exp): return type(exp) == Vector +def _vector(*vals): return Vector(vals) +def _vector_Q(exp): return type(exp) == Vector +# Hash maps +class Hash_Map(dict): pass +def _hash_map(*key_vals): + hm = Hash_Map() + for i in range(0,len(key_vals),2): hm[key_vals[i]] = key_vals[i+1] + return hm +def _hash_map_Q(exp): return type(exp) == Hash_Map # atoms class Atom(object): def __init__(self, val): self.val = val -def new_atom(val): return Atom(val) -def atom_Q(exp): return type(exp) == Atom -def deref(atm): return atm.val -def reset_BANG(atm,val): - atm.val = val - return atm.val -def swap_BANG(atm,f,*args): - atm.val = f(atm.val,*args) - return atm.val - - - -# Sequence operations -def sequential_Q(seq): return list_Q(seq) or vector_Q(seq) - -def coll_Q(coll): return sequential_Q(coll) or hash_map_Q(coll) - -def cons(x, seq): return List([x]) + List(seq) - -def nth(lst, idx): return lst[idx] - -def count(lst): return len(lst) - -def empty_Q(lst): return len(lst) == 0 - -def concat(*lsts): return List(chain(*lsts)) - -# retains metadata -def conj(lst, *args): - if list_Q(lst): - new_lst = List(list(reversed(list(args))) + lst) - else: - new_lst = Vector(lst + list(args)) - if hasattr(lst, "__meta__"): - new_lst.__meta__ = lst.__meta__ - return new_lst - -def first(lst): return lst[0] - -def rest(lst): return List(lst[1:]) - -def apply(f, *args): - return f(*(list(args[0:-1])+args[-1])) - -def mapf(f, lst): - return List(map(f, lst)) - - -# Environment - -class Env(): - def __init__(self, outer=None, binds=None, exprs=None): - self.data = {} - self.outer = outer or None - - if binds: - for i in range(len(binds)): - if binds[i] == "&": - self.data[binds[i+1]] = exprs[i:] - break - else: - self.data[binds[i]] = exprs[i] - - def find(self, key): - if key in self.data: return self - elif self.outer: return self.outer.find(key) - else: return None - - def set(self, key, value): - self.data[key] = value - return value - - def get(self, key): - env = self.find(key) - if not env: raise Exception("'" + key + "' not found") - return env.data[key] - -types_ns = { - 'pr-str': pr_str, 'str': do_str, 'prn': prn, 'println': println, - 'with-meta': with_meta, 'meta': meta, - '=': equal_Q, - 'nil?': nil_Q, 'true?': true_Q, 'false?': false_Q, - 'symbol?': symbol_Q, - '<': int_lt, '<=': int_lte, '>': int_gt, '>=': int_gte, - '+': int_plus, '-': int_minus, '*': int_multiply, '/': int_divide, - 'hash-map': new_hash_map, 'map?': hash_map_Q, - 'assoc': assoc, 'dissoc': dissoc, 'get': get, - 'contains?': contains_Q, 'keys': keys, 'vals': vals, - 'throw': throw, - 'list': new_list, 'list?': list_Q, - 'vector': new_vector, 'vector?': vector_Q, - 'atom': new_atom, 'atom?': atom_Q, 'deref': deref, - 'reset!': reset_BANG, 'swap!': swap_BANG, - 'sequential?': sequential_Q, - 'cons': cons, 'nth': nth, 'count': count, 'empty?': empty_Q, - 'concat': concat, "conj": conj, "first": first, "rest": rest, - 'apply': apply, 'map': mapf} - +def _atom(val): return Atom(val) +def _atom_Q(exp): return type(exp) == Atom |
