aboutsummaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-04-27 18:28:56 -0500
committerJoel Martin <github@martintribe.org>2014-04-27 18:28:56 -0500
commit72599899e3d3ae1face46a81f01979b040d19c61 (patch)
tree95e163ffacaa7061a1ac90ccd8a1418656ebc5e3 /python
parentd574187895c8519bffd5a0f8b4c1817e00103d91 (diff)
parentcc021efe10380039a13da5300990639203450634 (diff)
downloadmal-72599899e3d3ae1face46a81f01979b040d19c61.tar.gz
mal-72599899e3d3ae1face46a81f01979b040d19c61.zip
Merge branch 'master' into gh-pages
Diffstat (limited to 'python')
-rw-r--r--python/Makefile8
-rw-r--r--python/core.py19
-rw-r--r--python/mal_readline.py10
-rw-r--r--python/mal_types.py35
-rw-r--r--python/printer.py2
-rw-r--r--python/reader.py2
-rw-r--r--python/step0_repl.py3
-rw-r--r--python/step1_read_print.py5
-rw-r--r--python/step2_eval.py7
-rw-r--r--python/step3_env.py14
-rw-r--r--python/step4_if_fn_do.py12
-rw-r--r--python/step5_tco.py23
-rw-r--r--python/step6_file.py48
-rw-r--r--python/step7_quote.py51
-rw-r--r--python/step8_macros.py53
-rw-r--r--python/step9_interop.py58
-rw-r--r--python/stepA_more.py63
17 files changed, 236 insertions, 177 deletions
diff --git a/python/Makefile b/python/Makefile
index 3985d14..b461db3 100644
--- a/python/Makefile
+++ b/python/Makefile
@@ -2,8 +2,10 @@
TESTS =
-SOURCES = mal_readline.py mal_types.py reader.py printer.py \
- env.py core.py stepA_more.py
+SOURCES_BASE = mal_readline.py mal_types.py reader.py printer.py
+SOURCES_LISP = env.py core.py stepA_more.py
+SOURCES = $(SOURCES_BASE) $(SOURCES_LISP)
+
#all: mal.sh
#
@@ -20,6 +22,8 @@ SOURCES = mal_readline.py mal_types.py reader.py printer.py \
stats: $(SOURCES)
@wc $^
+stats-lisp: $(SOURCES_LISP)
+ @wc $^
tests: $(TESTS)
diff --git a/python/core.py b/python/core.py
index 28d9c5e..d10047d 100644
--- a/python/core.py
+++ b/python/core.py
@@ -1,8 +1,10 @@
-import copy
+import copy, time
from itertools import chain
import mal_types as types
from mal_types import List, Vector
+import mal_readline
+import reader
import printer
# Errors/Exceptions
@@ -17,12 +19,12 @@ 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))
+ 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')
+ print(line.replace('\\n', '\n'))
return None
@@ -39,7 +41,7 @@ def dissoc(src_hm, *keys):
return hm
def get(hm, key):
- if key in hm:
+ if hm and key in hm:
return hm[key]
else:
return None
@@ -85,7 +87,7 @@ def mapf(f, lst): return List(map(f, lst))
# Metadata functions
def with_meta(obj, meta):
- new_obj = copy.copy(obj)
+ new_obj = types._clone(obj)
new_obj.__meta__ = meta
return new_obj
@@ -112,10 +114,14 @@ ns = {
'false?': types._false_Q,
'symbol': types._symbol,
'symbol?': types._symbol_Q,
+
'pr-str': pr_str,
'str': do_str,
'prn': prn,
'println': println,
+ 'readline': lambda prompt: mal_readline.readline(prompt),
+ 'read-string': reader.read_str,
+ 'slurp': lambda file: open(file).read(),
'<': lambda a,b: a<b,
'<=': lambda a,b: a<=b,
'>': lambda a,b: a>b,
@@ -123,7 +129,8 @@ ns = {
'+': lambda a,b: a+b,
'-': lambda a,b: a-b,
'*': lambda a,b: a*b,
- '/': lambda a,b: a/b,
+ '/': lambda a,b: int(a/b),
+ 'time-ms': lambda : int(time.time() * 1000),
'list': types._list,
'list?': types._list_Q,
diff --git a/python/mal_readline.py b/python/mal_readline.py
index e8cf957..fc22b58 100644
--- a/python/mal_readline.py
+++ b/python/mal_readline.py
@@ -1,10 +1,16 @@
-import os, readline as pyreadline
+import os, sys, readline as pyreadline
history_loaded = False
histfile = os.path.expanduser("~/.mal-history")
+if sys.version_info[0] >= 3:
+ rl = input
+else:
+ rl = raw_input
def readline(prompt="user> "):
+ global history_loaded
if not history_loaded:
+ history_loaded = True
try:
with open(histfile, "r") as hf:
for line in hf.readlines():
@@ -15,7 +21,7 @@ def readline(prompt="user> "):
pass
try:
- line = raw_input(prompt)
+ line = rl(prompt)
pyreadline.add_history(line)
with open(histfile, "a") as hf:
hf.write(line + "\n")
diff --git a/python/mal_types.py b/python/mal_types.py
index 15e4b6b..e6bd70d 100644
--- a/python/mal_types.py
+++ b/python/mal_types.py
@@ -1,3 +1,9 @@
+import sys, copy, types as pytypes
+if sys.version_info[0] >= 3:
+ str_types = [str]
+else:
+ str_types = [str, unicode]
+
# General functions
def _equal_Q(a, b):
@@ -26,11 +32,26 @@ def _equal_Q(a, b):
def _sequential_Q(seq): return _list_Q(seq) or _vector_Q(seq)
+def _clone(obj):
+ #if type(obj) == type(lambda x:x):
+ if type(obj) == pytypes.FunctionType:
+ if obj.__code__:
+ return pytypes.FunctionType(
+ obj.__code__, obj.__globals__, name = obj.__name__,
+ argdefs = obj.__defaults__, closure = obj.__closure__)
+ else:
+ return pytypes.FunctionType(
+ obj.func_code, obj.func_globals, name = obj.func_name,
+ argdefs = obj.func_defaults, closure = obj.func_closure)
+ else:
+ return copy.copy(obj)
+
+
# 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]
+def _string_Q(exp): return type(exp) in str_types
# Symbols
class Symbol(str): pass
@@ -38,11 +59,13 @@ def _symbol(str): return Symbol(str)
def _symbol_Q(exp): return type(exp) == Symbol
# Functions
-def _function(Eval, Env, exp, env, params):
- def f(*args):
- return Eval(exp, Env(env, params, args))
- f.__meta__ = {"exp": exp, "env": env, "params": params}
- return f
+def _function(Eval, Env, ast, env, params):
+ def fn(*args):
+ return Eval(ast, Env(env, params, args))
+ fn.__meta__ = None
+ fn.__ast__ = ast
+ fn.__gen_env__ = lambda args: Env(env, params, args)
+ return fn
def _function_Q(f): return type(f) == type(function_Q)
# lists
diff --git a/python/printer.py b/python/printer.py
index d501d60..65bf256 100644
--- a/python/printer.py
+++ b/python/printer.py
@@ -13,7 +13,7 @@ def _pr_str(obj, print_readably=True):
return "{" + " ".join(ret) + "}"
elif types._string_Q(obj):
if print_readably:
- return '"' + obj.encode('unicode_escape').replace('"', '\\"') + '"'
+ return '"' + obj.encode('unicode_escape').decode('latin1').replace('"', '\\"') + '"'
else:
return obj
elif types._nil_Q(obj):
diff --git a/python/reader.py b/python/reader.py
index 846e2a8..13b1f7b 100644
--- a/python/reader.py
+++ b/python/reader.py
@@ -100,5 +100,5 @@ def read_form(reader):
def read_str(str):
tokens = tokenize(str)
- if len(tokens) == 0: raise Blank
+ if len(tokens) == 0: raise Blank("Blank Line")
return read_form(Reader(tokens))
diff --git a/python/step0_repl.py b/python/step0_repl.py
index 8d42c33..bb4d6bf 100644
--- a/python/step0_repl.py
+++ b/python/step0_repl.py
@@ -22,6 +22,7 @@ def PRINT(exp):
def REP(str):
return PRINT(EVAL(READ(str), {}))
+# repl loop
while True:
try:
line = mal_readline.readline("user> ")
@@ -29,4 +30,4 @@ while True:
if line == "": continue
print(REP(line))
except Exception as e:
- print "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+ print("".join(traceback.format_exception(*sys.exc_info())))
diff --git a/python/step1_read_print.py b/python/step1_read_print.py
index 0315cf0..3c2e4ac 100644
--- a/python/step1_read_print.py
+++ b/python/step1_read_print.py
@@ -9,7 +9,7 @@ def READ(str):
# eval
def EVAL(ast, env):
- #print("EVAL %s" % ast)
+ #print("EVAL %s" % printer._pr_str(ast))
return ast
def PRINT(exp):
@@ -19,6 +19,7 @@ def PRINT(exp):
def REP(str):
return PRINT(EVAL(READ(str), {}))
+# repl loop
while True:
try:
line = mal_readline.readline("user> ")
@@ -27,4 +28,4 @@ while True:
print(REP(line))
except reader.Blank: continue
except Exception as e:
- print "".join(traceback.format_exception(*sys.exc_info()))
+ print("".join(traceback.format_exception(*sys.exc_info())))
diff --git a/python/step2_eval.py b/python/step2_eval.py
index e50d231..8af09b1 100644
--- a/python/step2_eval.py
+++ b/python/step2_eval.py
@@ -28,7 +28,7 @@ def eval_ast(ast, env):
return ast # primitive value, return unchanged
def EVAL(ast, env):
- #print("EVAL %s" % ast)
+ #print("EVAL %s" % printer._pr_str(ast))
if not types._list_Q(ast):
return eval_ast(ast, env)
@@ -48,8 +48,9 @@ def REP(str):
repl_env['+'] = lambda a,b: a+b
repl_env['-'] = lambda a,b: a-b
repl_env['*'] = lambda a,b: a*b
-repl_env['/'] = lambda a,b: a/b
+repl_env['/'] = lambda a,b: int(a/b)
+# repl loop
while True:
try:
line = mal_readline.readline("user> ")
@@ -58,4 +59,4 @@ while True:
print(REP(line))
except reader.Blank: continue
except Exception as e:
- print "".join(traceback.format_exception(*sys.exc_info()))
+ print("".join(traceback.format_exception(*sys.exc_info())))
diff --git a/python/step3_env.py b/python/step3_env.py
index 21879d6..4565011 100644
--- a/python/step3_env.py
+++ b/python/step3_env.py
@@ -26,7 +26,7 @@ def eval_ast(ast, env):
return ast # primitive value, return unchanged
def EVAL(ast, env):
- #print("EVAL %s" % ast)
+ #print("EVAL %s" % printer._pr_str(ast))
if not types._list_Q(ast):
return eval_ast(ast, env)
@@ -57,13 +57,13 @@ def PRINT(exp):
repl_env = Env()
def REP(str):
return PRINT(EVAL(READ(str), repl_env))
-def _ref(k,v): repl_env.set(k, v)
-_ref('+', lambda a,b: a+b)
-_ref('-', lambda a,b: a-b)
-_ref('*', lambda a,b: a*b)
-_ref('/', lambda a,b: a/b)
+repl_env.set('+', lambda a,b: a+b)
+repl_env.set('-', lambda a,b: a-b)
+repl_env.set('*', lambda a,b: a*b)
+repl_env.set('/', lambda a,b: int(a/b))
+# repl loop
while True:
try:
line = mal_readline.readline("user> ")
@@ -72,4 +72,4 @@ while True:
print(REP(line))
except reader.Blank: continue
except Exception as e:
- print "".join(traceback.format_exception(*sys.exc_info()))
+ 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 d0a7fc3..e99cfcf 100644
--- a/python/step4_if_fn_do.py
+++ b/python/step4_if_fn_do.py
@@ -27,7 +27,7 @@ def eval_ast(ast, env):
return ast # primitive value, return unchanged
def EVAL(ast, env):
- #print("EVAL %s" % ast)
+ #print("EVAL %s" % printer._pr_str(ast))
if not types._list_Q(ast):
return eval_ast(ast, env)
@@ -72,14 +72,14 @@ def PRINT(exp):
repl_env = Env()
def REP(str):
return PRINT(EVAL(READ(str), repl_env))
-def _ref(k,v): repl_env.set(k, v)
-# Import types functions
-for name, val in core.ns.items(): _ref(name, val)
+# core.py: defined using python
+for k, v in core.ns.items(): repl_env.set(k, v)
-# Defined using the language itself
+# core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))")
+# repl loop
while True:
try:
line = mal_readline.readline("user> ")
@@ -88,4 +88,4 @@ while True:
print(REP(line))
except reader.Blank: continue
except Exception as e:
- print "".join(traceback.format_exception(*sys.exc_info()))
+ print("".join(traceback.format_exception(*sys.exc_info())))
diff --git a/python/step5_tco.py b/python/step5_tco.py
index 4335a96..cbb92c9 100644
--- a/python/step5_tco.py
+++ b/python/step5_tco.py
@@ -28,7 +28,7 @@ def eval_ast(ast, env):
def EVAL(ast, env):
while True:
- #print("EVAL %s" % ast)
+ #print("EVAL %s" % printer._pr_str(ast))
if not types._list_Q(ast):
return eval_ast(ast, env)
@@ -45,7 +45,9 @@ def EVAL(ast, env):
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)
+ ast = a2
+ env = let_env
+ # Continue loop (TCO)
elif "do" == a0:
eval_ast(ast[1:-1], env)
ast = ast[-1]
@@ -65,10 +67,9 @@ def EVAL(ast, env):
else:
el = eval_ast(ast, env)
f = el[0]
- if hasattr(f, '__meta__') and f.__meta__.has_key("exp"):
- m = f.__meta__
- ast = m['exp']
- env = Env(m['env'], m['params'], el[1:])
+ if hasattr(f, '__ast__'):
+ ast = f.__ast__
+ env = f.__gen_env__(el[1:])
else:
return f(*el[1:])
@@ -80,14 +81,14 @@ def PRINT(exp):
repl_env = Env()
def REP(str):
return PRINT(EVAL(READ(str), repl_env))
-def _ref(k,v): repl_env.set(k, v)
-# Import types functions
-for name, val in core.ns.items(): _ref(name, val)
+# core.py: defined using python
+for k, v in core.ns.items(): repl_env.set(k, v)
-# Defined using the language itself
+# core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))")
+# repl loop
while True:
try:
line = mal_readline.readline("user> ")
@@ -96,4 +97,4 @@ while True:
print(REP(line))
except reader.Blank: continue
except Exception as e:
- print "".join(traceback.format_exception(*sys.exc_info()))
+ print("".join(traceback.format_exception(*sys.exc_info())))
diff --git a/python/step6_file.py b/python/step6_file.py
index 9e0b8cd..9d84d1f 100644
--- a/python/step6_file.py
+++ b/python/step6_file.py
@@ -28,7 +28,7 @@ def eval_ast(ast, env):
def EVAL(ast, env):
while True:
- #print("EVAL %s" % ast)
+ #print("EVAL %s" % printer._pr_str(ast))
if not types._list_Q(ast):
return eval_ast(ast, env)
@@ -45,7 +45,9 @@ def EVAL(ast, env):
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)
+ ast = a2
+ env = let_env
+ # Continue loop (TCO)
elif "do" == a0:
eval_ast(ast[1:-1], env)
ast = ast[-1]
@@ -65,10 +67,9 @@ def EVAL(ast, env):
else:
el = eval_ast(ast, env)
f = el[0]
- if hasattr(f, '__meta__') and f.__meta__.has_key("exp"):
- m = f.__meta__
- ast = m['exp']
- env = Env(m['env'], m['params'], el[1:])
+ if hasattr(f, '__ast__'):
+ ast = f.__ast__
+ env = f.__gen_env__(el[1:])
else:
return f(*el[1:])
@@ -80,28 +81,27 @@ def PRINT(exp):
repl_env = Env()
def REP(str):
return PRINT(EVAL(READ(str), repl_env))
-def _ref(k,v): repl_env.set(k, v)
-
-# Import types functions
-for name, val in core.ns.items(): _ref(name, val)
-_ref('read-string', reader.read_str)
-_ref('eval', lambda ast: EVAL(ast, repl_env))
-_ref('slurp', lambda file: open(file).read())
+# core.py: defined using python
+for k, v in core.ns.items(): repl_env.set(k, v)
+repl_env.set('eval', lambda ast: EVAL(ast, repl_env))
+repl_env.set('*ARGV*', types._list(*sys.argv[2:]))
-# Defined using the language itself
+# core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))")
REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
if len(sys.argv) >= 2:
REP('(load-file "' + sys.argv[1] + '")')
-else:
- while True:
- try:
- line = mal_readline.readline("user> ")
- if line == None: break
- if line == "": continue
- print(REP(line))
- except reader.Blank: continue
- except Exception as e:
- print "".join(traceback.format_exception(*sys.exc_info()))
+ sys.exit(0)
+
+# repl loop
+while True:
+ try:
+ line = mal_readline.readline("user> ")
+ if line == None: break
+ if line == "": continue
+ print(REP(line))
+ 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 3ed6965..de19c6d 100644
--- a/python/step7_quote.py
+++ b/python/step7_quote.py
@@ -46,7 +46,7 @@ def eval_ast(ast, env):
def EVAL(ast, env):
while True:
- #print("EVAL %s" % ast)
+ #print("EVAL %s" % printer._pr_str(ast))
if not types._list_Q(ast):
return eval_ast(ast, env)
@@ -63,11 +63,14 @@ def EVAL(ast, env):
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)
+ ast = a2
+ env = let_env
+ # Continue loop (TCO)
elif "quote" == a0:
return ast[1]
elif "quasiquote" == a0:
- return EVAL(quasiquote(ast[1]), env)
+ ast = quasiquote(ast[1]);
+ # Continue loop (TCO)
elif "do" == a0:
eval_ast(ast[1:-1], env)
ast = ast[-1]
@@ -87,10 +90,9 @@ def EVAL(ast, env):
else:
el = eval_ast(ast, env)
f = el[0]
- if hasattr(f, '__meta__') and f.__meta__.has_key("exp"):
- m = f.__meta__
- ast = m['exp']
- env = Env(m['env'], m['params'], el[1:])
+ if hasattr(f, '__ast__'):
+ ast = f.__ast__
+ env = f.__gen_env__(el[1:])
else:
return f(*el[1:])
@@ -102,28 +104,27 @@ def PRINT(exp):
repl_env = Env()
def REP(str):
return PRINT(EVAL(READ(str), repl_env))
-def _ref(k,v): repl_env.set(k, v)
-
-# Import types functions
-for name, val in core.ns.items(): _ref(name, val)
-_ref('read-string', reader.read_str)
-_ref('eval', lambda ast: EVAL(ast, repl_env))
-_ref('slurp', lambda file: open(file).read())
+# core.py: defined using python
+for k, v in core.ns.items(): repl_env.set(k, v)
+repl_env.set('eval', lambda ast: EVAL(ast, repl_env))
+repl_env.set('*ARGV*', types._list(*sys.argv[2:]))
-# Defined using the language itself
+# core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))")
REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
if len(sys.argv) >= 2:
REP('(load-file "' + sys.argv[1] + '")')
-else:
- while True:
- try:
- line = mal_readline.readline("user> ")
- if line == None: break
- if line == "": continue
- print(REP(line))
- except reader.Blank: continue
- except Exception as e:
- print "".join(traceback.format_exception(*sys.exc_info()))
+ sys.exit(0)
+
+# repl loop
+while True:
+ try:
+ line = mal_readline.readline("user> ")
+ if line == None: break
+ if line == "": continue
+ print(REP(line))
+ 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 6e2bd45..80ca239 100644
--- a/python/step8_macros.py
+++ b/python/step8_macros.py
@@ -58,7 +58,7 @@ def eval_ast(ast, env):
def EVAL(ast, env):
while True:
- #print("EVAL %s" % ast)
+ #print("EVAL %s" % printer._pr_str(ast))
if not types._list_Q(ast):
return eval_ast(ast, env)
@@ -77,11 +77,14 @@ def EVAL(ast, env):
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)
+ ast = a2
+ env = let_env
+ # Continue loop (TCO)
elif "quote" == a0:
return ast[1]
elif "quasiquote" == a0:
- return EVAL(quasiquote(ast[1]), env)
+ ast = quasiquote(ast[1]);
+ # Continue loop (TCO)
elif 'defmacro!' == a0:
func = EVAL(ast[2], env)
func._ismacro_ = True
@@ -107,10 +110,9 @@ def EVAL(ast, env):
else:
el = eval_ast(ast, env)
f = el[0]
- if hasattr(f, '__meta__') and f.__meta__.has_key("exp"):
- m = f.__meta__
- ast = m['exp']
- env = Env(m['env'], m['params'], el[1:])
+ if hasattr(f, '__ast__'):
+ ast = f.__ast__
+ env = f.__gen_env__(el[1:])
else:
return f(*el[1:])
@@ -122,28 +124,29 @@ def PRINT(exp):
repl_env = Env()
def REP(str):
return PRINT(EVAL(READ(str), repl_env))
-def _ref(k,v): repl_env.set(k, v)
-
-# Import types functions
-for name, val in core.ns.items(): _ref(name, val)
-_ref('read-string', reader.read_str)
-_ref('eval', lambda ast: EVAL(ast, repl_env))
-_ref('slurp', lambda file: open(file).read())
+# core.py: defined using python
+for k, v in core.ns.items(): repl_env.set(k, v)
+repl_env.set('eval', lambda ast: EVAL(ast, repl_env))
+repl_env.set('*ARGV*', types._list(*sys.argv[2:]))
-# Defined using the language itself
+# core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))")
REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
+REP("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))")
+REP("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))")
if len(sys.argv) >= 2:
REP('(load-file "' + sys.argv[1] + '")')
-else:
- while True:
- try:
- line = mal_readline.readline("user> ")
- if line == None: break
- if line == "": continue
- print(REP(line))
- except reader.Blank: continue
- except Exception as e:
- print "".join(traceback.format_exception(*sys.exc_info()))
+ sys.exit(0)
+
+# repl loop
+while True:
+ try:
+ line = mal_readline.readline("user> ")
+ if line == None: break
+ if line == "": continue
+ print(REP(line))
+ except reader.Blank: continue
+ except Exception as e:
+ print("".join(traceback.format_exception(*sys.exc_info())))
diff --git a/python/step9_interop.py b/python/step9_interop.py
index 66a8c50..7cacf1f 100644
--- a/python/step9_interop.py
+++ b/python/step9_interop.py
@@ -58,7 +58,7 @@ def eval_ast(ast, env):
def EVAL(ast, env):
while True:
- #print("EVAL %s" % ast)
+ #print("EVAL %s" % printer._pr_str(ast))
if not types._list_Q(ast):
return eval_ast(ast, env)
@@ -77,11 +77,14 @@ def EVAL(ast, env):
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)
+ ast = a2
+ env = let_env
+ # Continue loop (TCO)
elif "quote" == a0:
return ast[1]
elif "quasiquote" == a0:
- return EVAL(quasiquote(ast[1]), env)
+ ast = quasiquote(ast[1]);
+ # Continue loop (TCO)
elif 'defmacro!' == a0:
func = EVAL(ast[2], env)
func._ismacro_ = True
@@ -89,7 +92,10 @@ def EVAL(ast, env):
elif 'macroexpand' == a0:
return macroexpand(ast[1], env)
elif "py!*" == a0:
- exec compile(ast[1], '', 'single') in globals()
+ if sys.version_info[0] >= 3:
+ exec(compile(ast[1], '', 'single'), globals())
+ else:
+ exec(compile(ast[1], '', 'single') in globals())
return None
elif "py*" == a0:
return eval(ast[1])
@@ -116,10 +122,9 @@ def EVAL(ast, env):
else:
el = eval_ast(ast, env)
f = el[0]
- if hasattr(f, '__meta__') and f.__meta__.has_key("exp"):
- m = f.__meta__
- ast = m['exp']
- env = Env(m['env'], m['params'], el[1:])
+ if hasattr(f, '__ast__'):
+ ast = f.__ast__
+ env = f.__gen_env__(el[1:])
else:
return f(*el[1:])
@@ -131,28 +136,29 @@ def PRINT(exp):
repl_env = Env()
def REP(str):
return PRINT(EVAL(READ(str), repl_env))
-def _ref(k,v): repl_env.set(k, v)
-# Import types functions
-for name, val in core.ns.items(): _ref(name, val)
+# core.py: defined using python
+for k, v in core.ns.items(): repl_env.set(k, v)
+repl_env.set('eval', lambda ast: EVAL(ast, repl_env))
+repl_env.set('*ARGV*', types._list(*sys.argv[2:]))
-_ref('read-string', reader.read_str)
-_ref('eval', lambda ast: EVAL(ast, repl_env))
-_ref('slurp', lambda file: open(file).read())
-
-# Defined using the language itself
+# core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))")
REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
+REP("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))")
+REP("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))")
if len(sys.argv) >= 2:
REP('(load-file "' + sys.argv[1] + '")')
-else:
- while True:
- try:
- line = mal_readline.readline("user> ")
- if line == None: break
- if line == "": continue
- print(REP(line))
- except reader.Blank: continue
- except Exception as e:
- print "".join(traceback.format_exception(*sys.exc_info()))
+ sys.exit(0)
+
+# repl loop
+while True:
+ try:
+ line = mal_readline.readline("user> ")
+ if line == None: break
+ if line == "": continue
+ print(REP(line))
+ except reader.Blank: continue
+ except Exception as e:
+ print("".join(traceback.format_exception(*sys.exc_info())))
diff --git a/python/stepA_more.py b/python/stepA_more.py
index 7c6a5da..723f0ed 100644
--- a/python/stepA_more.py
+++ b/python/stepA_more.py
@@ -58,7 +58,7 @@ def eval_ast(ast, env):
def EVAL(ast, env):
while True:
- #print("EVAL %s" % ast)
+ #print("EVAL %s" % printer._pr_str(ast))
if not types._list_Q(ast):
return eval_ast(ast, env)
@@ -77,11 +77,14 @@ def EVAL(ast, env):
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)
+ ast = a2
+ env = let_env
+ # Continue loop (TCO)
elif "quote" == a0:
return ast[1]
elif "quasiquote" == a0:
- return EVAL(quasiquote(ast[1]), env)
+ ast = quasiquote(ast[1]);
+ # Continue loop (TCO)
elif 'defmacro!' == a0:
func = EVAL(ast[2], env)
func._ismacro_ = True
@@ -89,7 +92,10 @@ def EVAL(ast, env):
elif 'macroexpand' == a0:
return macroexpand(ast[1], env)
elif "py!*" == a0:
- exec compile(ast[1], '', 'single') in globals()
+ if sys.version_info[0] >= 3:
+ exec(compile(ast[1], '', 'single'), globals())
+ else:
+ exec(compile(ast[1], '', 'single') in globals())
return None
elif "py*" == a0:
return eval(ast[1])
@@ -103,7 +109,7 @@ def EVAL(ast, env):
try:
return EVAL(a1, env);
except Exception as exc:
- exc = exc.message
+ exc = exc.args[0]
catch_env = Env(env, [a2[1]], [exc])
return EVAL(a2[2], catch_env)
else:
@@ -127,10 +133,9 @@ def EVAL(ast, env):
else:
el = eval_ast(ast, env)
f = el[0]
- if hasattr(f, '__meta__') and f.__meta__.has_key("exp"):
- m = f.__meta__
- ast = m['exp']
- env = Env(m['env'], m['params'], el[1:])
+ if hasattr(f, '__ast__'):
+ ast = f.__ast__
+ env = f.__gen_env__(el[1:])
else:
return f(*el[1:])
@@ -142,31 +147,31 @@ def PRINT(exp):
repl_env = Env()
def REP(str):
return PRINT(EVAL(READ(str), repl_env))
-def _ref(k,v): repl_env.set(k, v)
-
-# Import types functions
-for name, val in core.ns.items(): _ref(name, val)
-_ref('readline', lambda prompt: mal_readline.readline(prompt))
-_ref('read-string', reader.read_str)
-_ref('eval', lambda ast: EVAL(ast, repl_env))
-_ref('slurp', lambda file: open(file).read())
+# core.py: defined using python
+for k, v in core.ns.items(): repl_env.set(k, v)
+repl_env.set('eval', lambda ast: EVAL(ast, repl_env))
+repl_env.set('*ARGV*', types._list(*sys.argv[2:]))
-# Defined using the language itself
+# core.mal: defined using the language itself
+REP("(def! *host-language* \"python\")")
REP("(def! not (fn* (a) (if a false true)))")
+REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
REP("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))")
REP("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))")
-REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
if len(sys.argv) >= 2:
REP('(load-file "' + sys.argv[1] + '")')
-else:
- while True:
- try:
- line = mal_readline.readline("user> ")
- if line == None: break
- if line == "": continue
- print(REP(line))
- except reader.Blank: continue
- except Exception as e:
- print "".join(traceback.format_exception(*sys.exc_info()))
+ sys.exit(0)
+
+# repl loop
+REP("(println (str \"Mal [\" *host-language* \"]\"))")
+while True:
+ try:
+ line = mal_readline.readline("user> ")
+ if line == None: break
+ if line == "": continue
+ print(REP(line))
+ except reader.Blank: continue
+ except Exception as e:
+ print("".join(traceback.format_exception(*sys.exc_info())))