diff options
| author | Joel Martin <github@martintribe.org> | 2014-04-27 18:28:56 -0500 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2014-04-27 18:28:56 -0500 |
| commit | 72599899e3d3ae1face46a81f01979b040d19c61 (patch) | |
| tree | 95e163ffacaa7061a1ac90ccd8a1418656ebc5e3 /python | |
| parent | d574187895c8519bffd5a0f8b4c1817e00103d91 (diff) | |
| parent | cc021efe10380039a13da5300990639203450634 (diff) | |
| download | mal-72599899e3d3ae1face46a81f01979b040d19c61.tar.gz mal-72599899e3d3ae1face46a81f01979b040d19c61.zip | |
Merge branch 'master' into gh-pages
Diffstat (limited to 'python')
| -rw-r--r-- | python/Makefile | 8 | ||||
| -rw-r--r-- | python/core.py | 19 | ||||
| -rw-r--r-- | python/mal_readline.py | 10 | ||||
| -rw-r--r-- | python/mal_types.py | 35 | ||||
| -rw-r--r-- | python/printer.py | 2 | ||||
| -rw-r--r-- | python/reader.py | 2 | ||||
| -rw-r--r-- | python/step0_repl.py | 3 | ||||
| -rw-r--r-- | python/step1_read_print.py | 5 | ||||
| -rw-r--r-- | python/step2_eval.py | 7 | ||||
| -rw-r--r-- | python/step3_env.py | 14 | ||||
| -rw-r--r-- | python/step4_if_fn_do.py | 12 | ||||
| -rw-r--r-- | python/step5_tco.py | 23 | ||||
| -rw-r--r-- | python/step6_file.py | 48 | ||||
| -rw-r--r-- | python/step7_quote.py | 51 | ||||
| -rw-r--r-- | python/step8_macros.py | 53 | ||||
| -rw-r--r-- | python/step9_interop.py | 58 | ||||
| -rw-r--r-- | python/stepA_more.py | 63 |
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()))) |
