aboutsummaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/Makefile3
-rw-r--r--python/core.py159
-rw-r--r--python/env.py28
-rw-r--r--python/mal_types.py251
-rw-r--r--python/printer.py29
-rw-r--r--python/reader.py22
-rw-r--r--python/step1_read_print.py16
-rw-r--r--python/step2_eval.py40
-rw-r--r--python/step3_env.py67
-rw-r--r--python/step4_if_fn_do.py96
-rw-r--r--python/step5_tco.py40
-rw-r--r--python/step6_file.py42
-rw-r--r--python/step7_quote.py55
-rw-r--r--python/step8_macros.py59
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()))