diff options
Diffstat (limited to 'python')
| -rw-r--r-- | python/Makefile | 3 | ||||
| -rw-r--r-- | python/core.py | 159 | ||||
| -rw-r--r-- | python/env.py | 28 | ||||
| -rw-r--r-- | python/mal_types.py | 251 | ||||
| -rw-r--r-- | python/printer.py | 29 | ||||
| -rw-r--r-- | python/reader.py | 22 | ||||
| -rw-r--r-- | python/step1_read_print.py | 16 | ||||
| -rw-r--r-- | python/step2_eval.py | 40 | ||||
| -rw-r--r-- | python/step3_env.py | 67 | ||||
| -rw-r--r-- | python/step4_if_fn_do.py | 96 | ||||
| -rw-r--r-- | python/step5_tco.py | 40 | ||||
| -rw-r--r-- | python/step6_file.py | 42 | ||||
| -rw-r--r-- | python/step7_quote.py | 55 | ||||
| -rw-r--r-- | python/step8_macros.py | 59 |
14 files changed, 471 insertions, 436 deletions
diff --git a/python/Makefile b/python/Makefile index 1c8e467..3985d14 100644 --- a/python/Makefile +++ b/python/Makefile @@ -2,7 +2,8 @@ TESTS = -SOURCES = mal_types.py mal_readline.py reader.py stepA_more.py +SOURCES = mal_readline.py mal_types.py reader.py printer.py \ + env.py core.py stepA_more.py #all: mal.sh # diff --git a/python/core.py b/python/core.py new file mode 100644 index 0000000..92ae3d9 --- /dev/null +++ b/python/core.py @@ -0,0 +1,159 @@ +import copy +from itertools import chain + +import mal_types as types +from mal_types import List, Vector +import printer + +# Errors/Exceptions +def throw(exc): raise Exception(exc) + + +# String functions +def pr_str(*args): + return " ".join(map(lambda exp: printer._pr_str(exp, True), args)) + +def do_str(*args): + return "".join(map(lambda exp: printer._pr_str(exp, False), args)) + +def prn(*args): + print " ".join(map(lambda exp: printer._pr_str(exp, True), args)) + return None + +def println(*args): + line = " ".join(map(lambda exp: printer._pr_str(exp, False), args)) + print line.replace('\\n', '\n') + return None + + +# Hash map functions +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 types._list(*hm.keys()) + +def vals(hm): return types._list(*hm.values()) + + +# Sequence functions +def coll_Q(coll): return sequential_Q(coll) or hash_map_Q(coll) + +def cons(x, seq): return List([x]) + List(seq) + +def concat(*lsts): return List(chain(*lsts)) + +def nth(lst, idx): return lst[idx] + +def first(lst): return lst[0] + +def rest(lst): return List(lst[1:]) + +def empty_Q(lst): return len(lst) == 0 + +def count(lst): return len(lst) + +# retains metadata +def conj(lst, *args): + if types._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 apply(f, *args): return f(*(list(args[0:-1])+args[-1])) + +def mapf(f, lst): return List(map(f, lst)) + + +# Metadata functions +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 + + +# Atoms functions +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 + + +ns = { + '=': types._equal_Q, + 'throw': throw, + 'nil?': types._nil_Q, + 'true?': types._true_Q, + 'false?': types._false_Q, + 'symbol': types._symbol, + 'symbol?': types._symbol_Q, + 'pr-str': pr_str, + 'str': do_str, + 'prn': prn, + 'println': println, + '<': lambda a,b: a<b, + '<=': lambda a,b: a<=b, + '>': lambda a,b: a>b, + '>=': lambda a,b: a>=b, + '+': lambda a,b: a+b, + '-': lambda a,b: a-b, + '*': lambda a,b: a*b, + '/': lambda a,b: a/b, + + 'list': types._list, + 'list?': types._list_Q, + 'vector': types._vector, + 'vector?': types._vector_Q, + 'hash-map': types._hash_map, + 'map?': types._hash_map_Q, + 'assoc': assoc, + 'dissoc': dissoc, + 'get': get, + 'contains?': contains_Q, + 'keys': keys, + 'vals': vals, + + 'sequential?': types._sequential_Q, + 'cons': cons, + 'concat': concat, + 'nth': nth, + 'first': first, + 'rest': rest, + 'empty?': empty_Q, + 'count': count, + 'conj': conj, + 'apply': apply, + 'map': mapf, + + 'with-meta': with_meta, + 'meta': meta, + 'atom': types._atom, + 'atom?': types._atom_Q, + 'deref': deref, + 'reset!': reset_BANG, + 'swap!': swap_BANG} + diff --git a/python/env.py b/python/env.py new file mode 100644 index 0000000..4cd8e05 --- /dev/null +++ b/python/env.py @@ -0,0 +1,28 @@ +# 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] 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 diff --git a/python/printer.py b/python/printer.py new file mode 100644 index 0000000..d501d60 --- /dev/null +++ b/python/printer.py @@ -0,0 +1,29 @@ +import mal_types as types + +def _pr_str(obj, print_readably=True): + _r = print_readably + if types._list_Q(obj): + return "(" + " ".join(map(lambda e: _pr_str(e,_r), obj)) + ")" + elif types._vector_Q(obj): + return "[" + " ".join(map(lambda e: _pr_str(e,_r), obj)) + "]" + elif types._hash_map_Q(obj): + ret = [] + for k in obj.keys(): + ret.extend((_pr_str(k), _pr_str(obj[k],_r))) + return "{" + " ".join(ret) + "}" + elif types._string_Q(obj): + if print_readably: + return '"' + obj.encode('unicode_escape').replace('"', '\\"') + '"' + else: + return obj + elif types._nil_Q(obj): + return "nil" + elif types._true_Q(obj): + return "true" + elif types._false_Q(obj): + return "false" + elif types._atom_Q(obj): + return "(atom " + _pr_str(obj.val,_r) + ")" + else: + return obj.__str__() + diff --git a/python/reader.py b/python/reader.py index ddd6a32..846e2a8 100644 --- a/python/reader.py +++ b/python/reader.py @@ -1,5 +1,5 @@ import re -from mal_types import (new_symbol, Symbol, new_hash_map, List, new_list, Vector) +from mal_types import (_symbol, _list, _vector, _hash_map) class Blank(Exception): pass @@ -32,7 +32,7 @@ def read_atom(reader): elif token == "nil": return None elif token == "true": return True elif token == "false": return False - else: return Symbol(token) + else: return _symbol(token) def read_sequence(reader, typ=list, start='(', end=')'): ast = typ() @@ -49,13 +49,13 @@ def read_sequence(reader, typ=list, start='(', end=')'): def read_hash_map(reader): lst = read_sequence(reader, list, '{', '}') - return new_hash_map(*lst) + return _hash_map(*lst) def read_list(reader): - return read_sequence(reader, List, '(', ')') + return read_sequence(reader, _list, '(', ')') def read_vector(reader): - return read_sequence(reader, Vector, '[', ']') + return read_sequence(reader, _vector, '[', ']') def read_form(reader): token = reader.peek() @@ -65,23 +65,23 @@ def read_form(reader): return None elif token == '\'': reader.next() - return new_list(Symbol('quote'), read_form(reader)) + return _list(_symbol('quote'), read_form(reader)) elif token == '`': reader.next() - return new_list(Symbol('quasiquote'), read_form(reader)) + return _list(_symbol('quasiquote'), read_form(reader)) elif token == '~': reader.next() - return new_list(Symbol('unquote'), read_form(reader)) + return _list(_symbol('unquote'), read_form(reader)) elif token == '~@': reader.next() - return new_list(Symbol('splice-unquote'), read_form(reader)) + return _list(_symbol('splice-unquote'), read_form(reader)) elif token == '^': reader.next() meta = read_form(reader) - return new_list(Symbol('with-meta'), read_form(reader), meta) + return _list(_symbol('with-meta'), read_form(reader), meta) elif token == '@': reader.next() - return new_list(Symbol('deref'), read_form(reader)) + return _list(_symbol('deref'), read_form(reader)) # list elif token == ')': raise Exception("unexpected ')'") diff --git a/python/step1_read_print.py b/python/step1_read_print.py index 165dfa3..0315cf0 100644 --- a/python/step1_read_print.py +++ b/python/step1_read_print.py @@ -1,21 +1,19 @@ import sys, traceback import mal_readline -from mal_types import (pr_str, sequential_Q, symbol_Q, coll_Q, list_Q, - vector_Q, hash_map_Q, new_symbol, new_function, - new_list, new_vector, new_hash_map, Env, types_ns) -from reader import (read_str, Blank) +import mal_types as types +import reader, printer # read def READ(str): - return read_str(str) + return reader.read_str(str) # eval def EVAL(ast, env): - #print("EVAL %s" % ast) - return ast + #print("EVAL %s" % ast) + return ast def PRINT(exp): - return pr_str(exp) + return printer._pr_str(exp) # repl def REP(str): @@ -27,6 +25,6 @@ while True: if line == None: break if line == "": continue print(REP(line)) - except Blank: continue + except reader.Blank: continue except Exception as e: print "".join(traceback.format_exception(*sys.exc_info())) diff --git a/python/step2_eval.py b/python/step2_eval.py index 65972a2..e50d231 100644 --- a/python/step2_eval.py +++ b/python/step2_eval.py @@ -1,46 +1,44 @@ import sys, traceback import mal_readline -from mal_types import (pr_str, sequential_Q, symbol_Q, coll_Q, list_Q, - vector_Q, hash_map_Q, new_symbol, new_function, - new_list, new_vector, new_hash_map, Env, types_ns) -from reader import (read_str, Blank) +import mal_types as types +import reader, printer # read def READ(str): - return read_str(str) + return reader.read_str(str) # eval def eval_ast(ast, env): - if symbol_Q(ast): + if types._symbol_Q(ast): try: return env[ast] except: raise Exception("'" + ast + "' not found") - elif list_Q(ast): - return new_list(*map(lambda a: EVAL(a, env), ast)) - elif vector_Q(ast): - return new_vector(*map(lambda a: EVAL(a, env), ast)) - elif hash_map_Q(ast): + elif types._list_Q(ast): + return types._list(*map(lambda a: EVAL(a, env), ast)) + elif types._vector_Q(ast): + return types._vector(*map(lambda a: EVAL(a, env), ast)) + elif types._hash_map_Q(ast): keyvals = [] for k in ast.keys(): keyvals.append(EVAL(k, env)) keyvals.append(EVAL(ast[k], env)) - return new_hash_map(*keyvals) + return types._hash_map(*keyvals) else: return ast # primitive value, return unchanged def EVAL(ast, env): - #print("EVAL %s" % ast) - if not list_Q(ast): - return eval_ast(ast, env) + #print("EVAL %s" % ast) + if not types._list_Q(ast): + return eval_ast(ast, env) - # apply list - el = eval_ast(ast, env) - f = el[0] - return f(*el[1:]) + # apply list + el = eval_ast(ast, env) + f = el[0] + return f(*el[1:]) def PRINT(exp): - return pr_str(exp) + return printer._pr_str(exp) # repl repl_env = {} @@ -58,6 +56,6 @@ while True: if line == None: break if line == "": continue print(REP(line)) - except Blank: continue + except reader.Blank: continue except Exception as e: print "".join(traceback.format_exception(*sys.exc_info())) diff --git a/python/step3_env.py b/python/step3_env.py index f95a978..21879d6 100644 --- a/python/step3_env.py +++ b/python/step3_env.py @@ -1,58 +1,57 @@ import sys, traceback import mal_readline -from mal_types import (pr_str, sequential_Q, symbol_Q, coll_Q, list_Q, - vector_Q, hash_map_Q, new_symbol, new_function, - new_list, new_vector, new_hash_map, Env, types_ns) -from reader import (read_str, Blank) +import mal_types as types +import reader, printer +from env import Env # read def READ(str): - return read_str(str) + return reader.read_str(str) # eval def eval_ast(ast, env): - if symbol_Q(ast): + if types._symbol_Q(ast): return env.get(ast) - elif list_Q(ast): - return new_list(*map(lambda a: EVAL(a, env), ast)) - elif vector_Q(ast): - return new_vector(*map(lambda a: EVAL(a, env), ast)) - elif hash_map_Q(ast): + elif types._list_Q(ast): + return types._list(*map(lambda a: EVAL(a, env), ast)) + elif types._vector_Q(ast): + return types._vector(*map(lambda a: EVAL(a, env), ast)) + elif types._hash_map_Q(ast): keyvals = [] for k in ast.keys(): keyvals.append(EVAL(k, env)) keyvals.append(EVAL(ast[k], env)) - return new_hash_map(*keyvals) + return types._hash_map(*keyvals) else: return ast # primitive value, return unchanged def EVAL(ast, env): - #print("EVAL %s" % ast) - if not list_Q(ast): - return eval_ast(ast, env) + #print("EVAL %s" % ast) + if not types._list_Q(ast): + return eval_ast(ast, env) - # apply list - if len(ast) == 0: return ast - a0 = ast[0] + # apply list + if len(ast) == 0: return ast + a0 = ast[0] - if "def!" == a0: - a1, a2 = ast[1], ast[2] - res = EVAL(a2, env) - return env.set(a1, res) - elif "let*" == a0: - a1, a2 = ast[1], ast[2] - let_env = Env(env) - for i in range(0, len(a1), 2): - let_env.set(a1[i], EVAL(a1[i+1], let_env)) - return EVAL(a2, let_env) - else: - el = eval_ast(ast, env) - f = el[0] - return f(*el[1:]) + if "def!" == a0: + a1, a2 = ast[1], ast[2] + res = EVAL(a2, env) + return env.set(a1, res) + elif "let*" == a0: + a1, a2 = ast[1], ast[2] + let_env = Env(env) + for i in range(0, len(a1), 2): + let_env.set(a1[i], EVAL(a1[i+1], let_env)) + return EVAL(a2, let_env) + else: + el = eval_ast(ast, env) + f = el[0] + return f(*el[1:]) # print def PRINT(exp): - return pr_str(exp) + return printer._pr_str(exp) # repl repl_env = Env() @@ -71,6 +70,6 @@ while True: if line == None: break if line == "": continue print(REP(line)) - except Blank: continue + except reader.Blank: continue except Exception as e: print "".join(traceback.format_exception(*sys.exc_info())) diff --git a/python/step4_if_fn_do.py b/python/step4_if_fn_do.py index 4b54d8f..d0a7fc3 100644 --- a/python/step4_if_fn_do.py +++ b/python/step4_if_fn_do.py @@ -1,72 +1,72 @@ import sys, traceback import mal_readline -from mal_types import (pr_str, sequential_Q, symbol_Q, coll_Q, list_Q, - vector_Q, hash_map_Q, new_symbol, new_function, - new_list, new_vector, new_hash_map, Env, types_ns) -from reader import (read_str, Blank) +import mal_types as types +import reader, printer +from env import Env +import core # read def READ(str): - return read_str(str) + return reader.read_str(str) # eval def eval_ast(ast, env): - if symbol_Q(ast): + if types._symbol_Q(ast): return env.get(ast) - elif list_Q(ast): - return new_list(*map(lambda a: EVAL(a, env), ast)) - elif vector_Q(ast): - return new_vector(*map(lambda a: EVAL(a, env), ast)) - elif hash_map_Q(ast): + elif types._list_Q(ast): + return types._list(*map(lambda a: EVAL(a, env), ast)) + elif types._vector_Q(ast): + return types._vector(*map(lambda a: EVAL(a, env), ast)) + elif types._hash_map_Q(ast): keyvals = [] for k in ast.keys(): keyvals.append(EVAL(k, env)) keyvals.append(EVAL(ast[k], env)) - return new_hash_map(*keyvals) + return types._hash_map(*keyvals) else: return ast # primitive value, return unchanged def EVAL(ast, env): - #print("EVAL %s" % ast) - if not list_Q(ast): - return eval_ast(ast, env) + #print("EVAL %s" % ast) + if not types._list_Q(ast): + return eval_ast(ast, env) - # apply list - if len(ast) == 0: return ast - a0 = ast[0] + # apply list + if len(ast) == 0: return ast + a0 = ast[0] - if "def!" == a0: - a1, a2 = ast[1], ast[2] - res = EVAL(a2, env) - return env.set(a1, res) - elif "let*" == a0: - a1, a2 = ast[1], ast[2] - let_env = Env(env) - for i in range(0, len(a1), 2): - let_env.set(a1[i], EVAL(a1[i+1], let_env)) - return EVAL(a2, let_env) - elif "do" == a0: - el = eval_ast(ast[1:], env) - return el[-1] - elif "if" == a0: - a1, a2 = ast[1], ast[2] - cond = EVAL(a1, env) - if cond is None or cond is False: - if len(ast) > 3: return EVAL(ast[3], env) - else: return None + if "def!" == a0: + a1, a2 = ast[1], ast[2] + res = EVAL(a2, env) + return env.set(a1, res) + elif "let*" == a0: + a1, a2 = ast[1], ast[2] + let_env = Env(env) + for i in range(0, len(a1), 2): + let_env.set(a1[i], EVAL(a1[i+1], let_env)) + return EVAL(a2, let_env) + elif "do" == a0: + el = eval_ast(ast[1:], env) + return el[-1] + elif "if" == a0: + a1, a2 = ast[1], ast[2] + cond = EVAL(a1, env) + if cond is None or cond is False: + if len(ast) > 3: return EVAL(ast[3], env) + else: return None + else: + return EVAL(a2, env) + elif "fn*" == a0: + a1, a2 = ast[1], ast[2] + return types._function(EVAL, Env, a2, env, a1) else: - return EVAL(a2, env) - elif "fn*" == a0: - a1, a2 = ast[1], ast[2] - return new_function(EVAL, a2, env, a1) - else: - el = eval_ast(ast, env) - f = el[0] - return f(*el[1:]) + el = eval_ast(ast, env) + f = el[0] + return f(*el[1:]) # print def PRINT(exp): - return pr_str(exp) + return printer._pr_str(exp) # repl repl_env = Env() @@ -75,7 +75,7 @@ def REP(str): def _ref(k,v): repl_env.set(k, v) # Import types functions -for name, val in types_ns.items(): _ref(name, val) +for name, val in core.ns.items(): _ref(name, val) # Defined using the language itself REP("(def! not (fn* (a) (if a false true)))") @@ -86,6 +86,6 @@ while True: if line == None: break if line == "": continue print(REP(line)) - except Blank: continue + except reader.Blank: continue except Exception as e: print "".join(traceback.format_exception(*sys.exc_info())) diff --git a/python/step5_tco.py b/python/step5_tco.py index ffde863..4335a96 100644 --- a/python/step5_tco.py +++ b/python/step5_tco.py @@ -1,41 +1,41 @@ import sys, traceback import mal_readline -from mal_types import (pr_str, sequential_Q, symbol_Q, coll_Q, list_Q, - vector_Q, hash_map_Q, new_symbol, new_function, - new_list, new_vector, new_hash_map, Env, types_ns) -from reader import (read_str, Blank) +import mal_types as types +import reader, printer +from env import Env +import core # read def READ(str): - return read_str(str) + return reader.read_str(str) # eval def eval_ast(ast, env): - if symbol_Q(ast): + if types._symbol_Q(ast): return env.get(ast) - elif list_Q(ast): - return new_list(*map(lambda a: EVAL(a, env), ast)) - elif vector_Q(ast): - return new_vector(*map(lambda a: EVAL(a, env), ast)) - elif hash_map_Q(ast): + elif types._list_Q(ast): + return types._list(*map(lambda a: EVAL(a, env), ast)) + elif types._vector_Q(ast): + return types._vector(*map(lambda a: EVAL(a, env), ast)) + elif types._hash_map_Q(ast): keyvals = [] for k in ast.keys(): keyvals.append(EVAL(k, env)) keyvals.append(EVAL(ast[k], env)) - return new_hash_map(*keyvals) + return types._hash_map(*keyvals) else: return ast # primitive value, return unchanged def EVAL(ast, env): while True: #print("EVAL %s" % ast) - if not list_Q(ast): + if not types._list_Q(ast): return eval_ast(ast, env) - + # apply list if len(ast) == 0: return ast - a0 = ast[0] - + a0 = ast[0] + if "def!" == a0: a1, a2 = ast[1], ast[2] res = EVAL(a2, env) @@ -61,7 +61,7 @@ def EVAL(ast, env): # Continue loop (TCO) elif "fn*" == a0: a1, a2 = ast[1], ast[2] - return new_function(EVAL, a2, env, a1) + return types._function(EVAL, Env, a2, env, a1) else: el = eval_ast(ast, env) f = el[0] @@ -74,7 +74,7 @@ def EVAL(ast, env): # print def PRINT(exp): - return pr_str(exp) + return printer._pr_str(exp) # repl repl_env = Env() @@ -83,7 +83,7 @@ def REP(str): def _ref(k,v): repl_env.set(k, v) # Import types functions -for name, val in types_ns.items(): _ref(name, val) +for name, val in core.ns.items(): _ref(name, val) # Defined using the language itself REP("(def! not (fn* (a) (if a false true)))") @@ -94,6 +94,6 @@ while True: if line == None: break if line == "": continue print(REP(line)) - except Blank: continue + except reader.Blank: continue except Exception as e: print "".join(traceback.format_exception(*sys.exc_info())) diff --git a/python/step6_file.py b/python/step6_file.py index 8a3432d..9e0b8cd 100644 --- a/python/step6_file.py +++ b/python/step6_file.py @@ -1,41 +1,41 @@ import sys, traceback import mal_readline -from mal_types import (pr_str, sequential_Q, symbol_Q, coll_Q, list_Q, - vector_Q, hash_map_Q, new_symbol, new_function, - new_list, new_vector, new_hash_map, Env, types_ns) -from reader import (read_str, Blank) +import mal_types as types +import reader, printer +from env import Env +import core # read def READ(str): - return read_str(str) + return reader.read_str(str) # eval def eval_ast(ast, env): - if symbol_Q(ast): + if types._symbol_Q(ast): return env.get(ast) - elif list_Q(ast): - return new_list(*map(lambda a: EVAL(a, env), ast)) - elif vector_Q(ast): - return new_vector(*map(lambda a: EVAL(a, env), ast)) - elif hash_map_Q(ast): + elif types._list_Q(ast): + return types._list(*map(lambda a: EVAL(a, env), ast)) + elif types._vector_Q(ast): + return types._vector(*map(lambda a: EVAL(a, env), ast)) + elif types._hash_map_Q(ast): keyvals = [] for k in ast.keys(): keyvals.append(EVAL(k, env)) keyvals.append(EVAL(ast[k], env)) - return new_hash_map(*keyvals) + return types._hash_map(*keyvals) else: return ast # primitive value, return unchanged def EVAL(ast, env): while True: #print("EVAL %s" % ast) - if not list_Q(ast): + if not types._list_Q(ast): return eval_ast(ast, env) - + # apply list if len(ast) == 0: return ast - a0 = ast[0] - + a0 = ast[0] + if "def!" == a0: a1, a2 = ast[1], ast[2] res = EVAL(a2, env) @@ -61,7 +61,7 @@ def EVAL(ast, env): # Continue loop (TCO) elif "fn*" == a0: a1, a2 = ast[1], ast[2] - return new_function(EVAL, a2, env, a1) + return types._function(EVAL, Env, a2, env, a1) else: el = eval_ast(ast, env) f = el[0] @@ -74,7 +74,7 @@ def EVAL(ast, env): # print def PRINT(exp): - return pr_str(exp) + return printer._pr_str(exp) # repl repl_env = Env() @@ -83,9 +83,9 @@ def REP(str): def _ref(k,v): repl_env.set(k, v) # Import types functions -for name, val in types_ns.items(): _ref(name, val) +for name, val in core.ns.items(): _ref(name, val) -_ref('read-string', read_str) +_ref('read-string', reader.read_str) _ref('eval', lambda ast: EVAL(ast, repl_env)) _ref('slurp', lambda file: open(file).read()) @@ -102,6 +102,6 @@ else: if line == None: break if line == "": continue print(REP(line)) - except Blank: continue + except reader.Blank: continue except Exception as e: print "".join(traceback.format_exception(*sys.exc_info())) diff --git a/python/step7_quote.py b/python/step7_quote.py index 7acc322..3ed6965 100644 --- a/python/step7_quote.py +++ b/python/step7_quote.py @@ -1,54 +1,59 @@ import sys, traceback import mal_readline -from mal_types import (pr_str, sequential_Q, symbol_Q, coll_Q, list_Q, - vector_Q, hash_map_Q, new_symbol, new_function, - new_list, new_vector, new_hash_map, Env, types_ns) -from reader import (read_str, Blank) +import mal_types as types +import reader, printer +from env import Env +import core # read def READ(str): - return read_str(str) + return reader.read_str(str) # eval def is_pair(x): - return sequential_Q(x) and len(x) > 0 + return types._sequential_Q(x) and len(x) > 0 def quasiquote(ast): if not is_pair(ast): - return new_list(new_symbol("quote"), ast) + return types._list(types._symbol("quote"), + ast) elif ast[0] == 'unquote': return ast[1] elif is_pair(ast[0]) and ast[0][0] == 'splice-unquote': - return new_list(new_symbol("concat"), ast[0][1], quasiquote(ast[1:])) + return types._list(types._symbol("concat"), + ast[0][1], + quasiquote(ast[1:])) else: - return new_list(new_symbol("cons"), quasiquote(ast[0]), quasiquote(ast[1:])) + return types._list(types._symbol("cons"), + quasiquote(ast[0]), + quasiquote(ast[1:])) def eval_ast(ast, env): - if symbol_Q(ast): + if types._symbol_Q(ast): return env.get(ast) - elif list_Q(ast): - return new_list(*map(lambda a: EVAL(a, env), ast)) - elif vector_Q(ast): - return new_vector(*map(lambda a: EVAL(a, env), ast)) - elif hash_map_Q(ast): + elif types._list_Q(ast): + return types._list(*map(lambda a: EVAL(a, env), ast)) + elif types._vector_Q(ast): + return types._vector(*map(lambda a: EVAL(a, env), ast)) + elif types._hash_map_Q(ast): keyvals = [] for k in ast.keys(): keyvals.append(EVAL(k, env)) keyvals.append(EVAL(ast[k], env)) - return new_hash_map(*keyvals) + return types._hash_map(*keyvals) else: return ast # primitive value, return unchanged def EVAL(ast, env): while True: #print("EVAL %s" % ast) - if not list_Q(ast): + if not types._list_Q(ast): return eval_ast(ast, env) - + # apply list if len(ast) == 0: return ast - a0 = ast[0] - + a0 = ast[0] + if "def!" == a0: a1, a2 = ast[1], ast[2] res = EVAL(a2, env) @@ -78,7 +83,7 @@ def EVAL(ast, env): # Continue loop (TCO) elif "fn*" == a0: a1, a2 = ast[1], ast[2] - return new_function(EVAL, a2, env, a1) + return types._function(EVAL, Env, a2, env, a1) else: el = eval_ast(ast, env) f = el[0] @@ -91,7 +96,7 @@ def EVAL(ast, env): # print def PRINT(exp): - return pr_str(exp) + return printer._pr_str(exp) # repl repl_env = Env() @@ -100,9 +105,9 @@ def REP(str): def _ref(k,v): repl_env.set(k, v) # Import types functions -for name, val in types_ns.items(): _ref(name, val) +for name, val in core.ns.items(): _ref(name, val) -_ref('read-string', read_str) +_ref('read-string', reader.read_str) _ref('eval', lambda ast: EVAL(ast, repl_env)) _ref('slurp', lambda file: open(file).read()) @@ -119,6 +124,6 @@ else: if line == None: break if line == "": continue print(REP(line)) - except Blank: continue + except reader.Blank: continue except Exception as e: print "".join(traceback.format_exception(*sys.exc_info())) diff --git a/python/step8_macros.py b/python/step8_macros.py index e09942c..6e2bd45 100644 --- a/python/step8_macros.py +++ b/python/step8_macros.py @@ -1,31 +1,36 @@ import sys, traceback import mal_readline -from mal_types import (pr_str, sequential_Q, symbol_Q, coll_Q, list_Q, - vector_Q, hash_map_Q, new_symbol, new_function, - new_list, new_vector, new_hash_map, Env, types_ns) -from reader import (read_str, Blank) +import mal_types as types +import reader, printer +from env import Env +import core # read def READ(str): - return read_str(str) + return reader.read_str(str) # eval def is_pair(x): - return sequential_Q(x) and len(x) > 0 + return types._sequential_Q(x) and len(x) > 0 def quasiquote(ast): if not is_pair(ast): - return new_list(new_symbol("quote"), ast) + return types._list(types._symbol("quote"), + ast) elif ast[0] == 'unquote': return ast[1] elif is_pair(ast[0]) and ast[0][0] == 'splice-unquote': - return new_list(new_symbol("concat"), ast[0][1], quasiquote(ast[1:])) + return types._list(types._symbol("concat"), + ast[0][1], + quasiquote(ast[1:])) else: - return new_list(new_symbol("cons"), quasiquote(ast[0]), quasiquote(ast[1:])) + return types._list(types._symbol("cons"), + quasiquote(ast[0]), + quasiquote(ast[1:])) def is_macro_call(ast, env): - return (list_Q(ast) and - symbol_Q(ast[0]) and + return (types._list_Q(ast) and + types._symbol_Q(ast[0]) and env.find(ast[0]) and hasattr(env.get(ast[0]), '_ismacro_')) @@ -36,33 +41,33 @@ def macroexpand(ast, env): return ast def eval_ast(ast, env): - if symbol_Q(ast): + if types._symbol_Q(ast): return env.get(ast) - elif list_Q(ast): - return new_list(*map(lambda a: EVAL(a, env), ast)) - elif vector_Q(ast): - return new_vector(*map(lambda a: EVAL(a, env), ast)) - elif hash_map_Q(ast): + elif types._list_Q(ast): + return types._list(*map(lambda a: EVAL(a, env), ast)) + elif types._vector_Q(ast): + return types._vector(*map(lambda a: EVAL(a, env), ast)) + elif types._hash_map_Q(ast): keyvals = [] for k in ast.keys(): keyvals.append(EVAL(k, env)) keyvals.append(EVAL(ast[k], env)) - return new_hash_map(*keyvals) + return types._hash_map(*keyvals) else: return ast # primitive value, return unchanged def EVAL(ast, env): while True: #print("EVAL %s" % ast) - if not list_Q(ast): + if not types._list_Q(ast): return eval_ast(ast, env) - + # apply list ast = macroexpand(ast, env) - if not list_Q(ast): return ast + if not types._list_Q(ast): return ast if len(ast) == 0: return ast + a0 = ast[0] - a0 = ast[0] if "def!" == a0: a1, a2 = ast[1], ast[2] res = EVAL(a2, env) @@ -98,7 +103,7 @@ def EVAL(ast, env): # Continue loop (TCO) elif "fn*" == a0: a1, a2 = ast[1], ast[2] - return new_function(EVAL, a2, env, a1) + return types._function(EVAL, Env, a2, env, a1) else: el = eval_ast(ast, env) f = el[0] @@ -111,7 +116,7 @@ def EVAL(ast, env): # print def PRINT(exp): - return pr_str(exp) + return printer._pr_str(exp) # repl repl_env = Env() @@ -120,9 +125,9 @@ def REP(str): def _ref(k,v): repl_env.set(k, v) # Import types functions -for name, val in types_ns.items(): _ref(name, val) +for name, val in core.ns.items(): _ref(name, val) -_ref('read-string', read_str) +_ref('read-string', reader.read_str) _ref('eval', lambda ast: EVAL(ast, repl_env)) _ref('slurp', lambda file: open(file).read()) @@ -139,6 +144,6 @@ else: if line == None: break if line == "": continue print(REP(line)) - except Blank: continue + except reader.Blank: continue except Exception as e: print "".join(traceback.format_exception(*sys.exc_info())) |
