From 01c9731649a7ed97fad0bdeac9cb75b7323c0ad6 Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Thu, 9 Oct 2014 23:48:47 -0500 Subject: All: swap step9,A. Fixes for bash, C, perl. step9_interop -> stepA_interop stepA_more -> step9_try C: fix glib headers bash: behavior change of declare -A and pattern replacement. perl: squelch new 5.18 warnings related to switch/given statement. Also, include some in-progress interop related files. --- python/Makefile | 2 +- python/step9_interop.py | 164 -------------------------------------------- python/step9_try.py | 171 ++++++++++++++++++++++++++++++++++++++++++++++ python/stepA_interop.py | 177 ++++++++++++++++++++++++++++++++++++++++++++++++ python/stepA_more.py | 177 ------------------------------------------------ 5 files changed, 349 insertions(+), 342 deletions(-) delete mode 100644 python/step9_interop.py create mode 100644 python/step9_try.py create mode 100644 python/stepA_interop.py delete mode 100644 python/stepA_more.py (limited to 'python') diff --git a/python/Makefile b/python/Makefile index b461db3..6e51430 100644 --- a/python/Makefile +++ b/python/Makefile @@ -3,7 +3,7 @@ TESTS = SOURCES_BASE = mal_readline.py mal_types.py reader.py printer.py -SOURCES_LISP = env.py core.py stepA_more.py +SOURCES_LISP = env.py core.py stepA_interop.py SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) diff --git a/python/step9_interop.py b/python/step9_interop.py deleted file mode 100644 index 7cacf1f..0000000 --- a/python/step9_interop.py +++ /dev/null @@ -1,164 +0,0 @@ -import sys, traceback -import mal_readline -import mal_types as types -import reader, printer -from env import Env -import core - -# read -def READ(str): - return reader.read_str(str) - -# eval -def is_pair(x): - return types._sequential_Q(x) and len(x) > 0 - -def quasiquote(ast): - if not is_pair(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 types._list(types._symbol("concat"), - ast[0][1], - quasiquote(ast[1:])) - else: - return types._list(types._symbol("cons"), - quasiquote(ast[0]), - quasiquote(ast[1:])) - -def is_macro_call(ast, env): - return (types._list_Q(ast) and - types._symbol_Q(ast[0]) and - env.find(ast[0]) and - hasattr(env.get(ast[0]), '_ismacro_')) - -def macroexpand(ast, env): - while is_macro_call(ast, env): - mac = env.get(ast[0]) - ast = macroexpand(mac(*ast[1:]), env) - return ast - -def eval_ast(ast, env): - if types._symbol_Q(ast): - return env.get(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 types._hash_map(*keyvals) - else: - return ast # primitive value, return unchanged - -def EVAL(ast, env): - while True: - #print("EVAL %s" % printer._pr_str(ast)) - if not types._list_Q(ast): - return eval_ast(ast, env) - - # apply list - ast = macroexpand(ast, env) - if not types._list_Q(ast): return ast - 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)) - ast = a2 - env = let_env - # Continue loop (TCO) - elif "quote" == a0: - return ast[1] - elif "quasiquote" == a0: - ast = quasiquote(ast[1]); - # Continue loop (TCO) - elif 'defmacro!' == a0: - func = EVAL(ast[2], env) - func._ismacro_ = True - return env.set(ast[1], func) - elif 'macroexpand' == a0: - return macroexpand(ast[1], env) - elif "py!*" == a0: - 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]) - elif "." == a0: - el = eval_ast(ast[2:], env) - f = eval(ast[1]) - return f(*el) - elif "do" == a0: - eval_ast(ast[1:-1], env) - ast = ast[-1] - # Continue loop (TCO) - 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: ast = ast[3] - else: ast = None - else: - ast = a2 - # Continue loop (TCO) - elif "fn*" == a0: - a1, a2 = ast[1], ast[2] - return types._function(EVAL, Env, a2, env, a1) - else: - el = eval_ast(ast, env) - f = el[0] - if hasattr(f, '__ast__'): - ast = f.__ast__ - env = f.__gen_env__(el[1:]) - else: - return f(*el[1:]) - -# print -def PRINT(exp): - return printer._pr_str(exp) - -# repl -repl_env = Env() -def REP(str): - return PRINT(EVAL(READ(str), repl_env)) - -# 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:])) - -# 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] + '")') - 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_try.py b/python/step9_try.py new file mode 100644 index 0000000..65da08c --- /dev/null +++ b/python/step9_try.py @@ -0,0 +1,171 @@ +import sys, traceback +import mal_readline +import mal_types as types +import reader, printer +from env import Env +import core + +# read +def READ(str): + return reader.read_str(str) + +# eval +def is_pair(x): + return types._sequential_Q(x) and len(x) > 0 + +def quasiquote(ast): + if not is_pair(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 types._list(types._symbol("concat"), + ast[0][1], + quasiquote(ast[1:])) + else: + return types._list(types._symbol("cons"), + quasiquote(ast[0]), + quasiquote(ast[1:])) + +def is_macro_call(ast, env): + return (types._list_Q(ast) and + types._symbol_Q(ast[0]) and + env.find(ast[0]) and + hasattr(env.get(ast[0]), '_ismacro_')) + +def macroexpand(ast, env): + while is_macro_call(ast, env): + mac = env.get(ast[0]) + ast = macroexpand(mac(*ast[1:]), env) + return ast + +def eval_ast(ast, env): + if types._symbol_Q(ast): + return env.get(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 types._hash_map(*keyvals) + else: + return ast # primitive value, return unchanged + +def EVAL(ast, env): + while True: + #print("EVAL %s" % printer._pr_str(ast)) + if not types._list_Q(ast): + return eval_ast(ast, env) + + # apply list + ast = macroexpand(ast, env) + if not types._list_Q(ast): return ast + 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)) + ast = a2 + env = let_env + # Continue loop (TCO) + elif "quote" == a0: + return ast[1] + elif "quasiquote" == a0: + ast = quasiquote(ast[1]); + # Continue loop (TCO) + elif 'defmacro!' == a0: + func = EVAL(ast[2], env) + func._ismacro_ = True + return env.set(ast[1], func) + elif 'macroexpand' == a0: + return macroexpand(ast[1], env) + elif "py!*" == a0: + if sys.version_info[0] >= 3: + exec(compile(ast[1], '', 'single'), globals()) + else: + exec(compile(ast[1], '', 'single') in globals()) + return None + elif "try*" == a0: + a1, a2 = ast[1], ast[2] + if a2[0] == "catch*": + try: + return EVAL(a1, env); + except Exception as exc: + exc = exc.args[0] + catch_env = Env(env, [a2[1]], [exc]) + return EVAL(a2[2], catch_env) + else: + return EVAL(a1, env); + elif "do" == a0: + eval_ast(ast[1:-1], env) + ast = ast[-1] + # Continue loop (TCO) + 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: ast = ast[3] + else: ast = None + else: + ast = a2 + # Continue loop (TCO) + elif "fn*" == a0: + a1, a2 = ast[1], ast[2] + return types._function(EVAL, Env, a2, env, a1) + else: + el = eval_ast(ast, env) + f = el[0] + if hasattr(f, '__ast__'): + ast = f.__ast__ + env = f.__gen_env__(el[1:]) + else: + return f(*el[1:]) + +# print +def PRINT(exp): + return printer._pr_str(exp) + +# repl +repl_env = Env() +def REP(str): + return PRINT(EVAL(READ(str), repl_env)) + +# 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:])) + +# 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))))))))") + +if len(sys.argv) >= 2: + REP('(load-file "' + sys.argv[1] + '")') + 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()))) diff --git a/python/stepA_interop.py b/python/stepA_interop.py new file mode 100644 index 0000000..723f0ed --- /dev/null +++ b/python/stepA_interop.py @@ -0,0 +1,177 @@ +import sys, traceback +import mal_readline +import mal_types as types +import reader, printer +from env import Env +import core + +# read +def READ(str): + return reader.read_str(str) + +# eval +def is_pair(x): + return types._sequential_Q(x) and len(x) > 0 + +def quasiquote(ast): + if not is_pair(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 types._list(types._symbol("concat"), + ast[0][1], + quasiquote(ast[1:])) + else: + return types._list(types._symbol("cons"), + quasiquote(ast[0]), + quasiquote(ast[1:])) + +def is_macro_call(ast, env): + return (types._list_Q(ast) and + types._symbol_Q(ast[0]) and + env.find(ast[0]) and + hasattr(env.get(ast[0]), '_ismacro_')) + +def macroexpand(ast, env): + while is_macro_call(ast, env): + mac = env.get(ast[0]) + ast = macroexpand(mac(*ast[1:]), env) + return ast + +def eval_ast(ast, env): + if types._symbol_Q(ast): + return env.get(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 types._hash_map(*keyvals) + else: + return ast # primitive value, return unchanged + +def EVAL(ast, env): + while True: + #print("EVAL %s" % printer._pr_str(ast)) + if not types._list_Q(ast): + return eval_ast(ast, env) + + # apply list + ast = macroexpand(ast, env) + if not types._list_Q(ast): return ast + 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)) + ast = a2 + env = let_env + # Continue loop (TCO) + elif "quote" == a0: + return ast[1] + elif "quasiquote" == a0: + ast = quasiquote(ast[1]); + # Continue loop (TCO) + elif 'defmacro!' == a0: + func = EVAL(ast[2], env) + func._ismacro_ = True + return env.set(ast[1], func) + elif 'macroexpand' == a0: + return macroexpand(ast[1], env) + elif "py!*" == a0: + 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]) + elif "." == a0: + el = eval_ast(ast[2:], env) + f = eval(ast[1]) + return f(*el) + elif "try*" == a0: + a1, a2 = ast[1], ast[2] + if a2[0] == "catch*": + try: + return EVAL(a1, env); + except Exception as exc: + exc = exc.args[0] + catch_env = Env(env, [a2[1]], [exc]) + return EVAL(a2[2], catch_env) + else: + return EVAL(a1, env); + elif "do" == a0: + eval_ast(ast[1:-1], env) + ast = ast[-1] + # Continue loop (TCO) + 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: ast = ast[3] + else: ast = None + else: + ast = a2 + # Continue loop (TCO) + elif "fn*" == a0: + a1, a2 = ast[1], ast[2] + return types._function(EVAL, Env, a2, env, a1) + else: + el = eval_ast(ast, env) + f = el[0] + if hasattr(f, '__ast__'): + ast = f.__ast__ + env = f.__gen_env__(el[1:]) + else: + return f(*el[1:]) + +# print +def PRINT(exp): + return printer._pr_str(exp) + +# repl +repl_env = Env() +def REP(str): + return PRINT(EVAL(READ(str), repl_env)) + +# 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:])) + +# 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))))))))") + +if len(sys.argv) >= 2: + REP('(load-file "' + sys.argv[1] + '")') + 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()))) diff --git a/python/stepA_more.py b/python/stepA_more.py deleted file mode 100644 index 723f0ed..0000000 --- a/python/stepA_more.py +++ /dev/null @@ -1,177 +0,0 @@ -import sys, traceback -import mal_readline -import mal_types as types -import reader, printer -from env import Env -import core - -# read -def READ(str): - return reader.read_str(str) - -# eval -def is_pair(x): - return types._sequential_Q(x) and len(x) > 0 - -def quasiquote(ast): - if not is_pair(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 types._list(types._symbol("concat"), - ast[0][1], - quasiquote(ast[1:])) - else: - return types._list(types._symbol("cons"), - quasiquote(ast[0]), - quasiquote(ast[1:])) - -def is_macro_call(ast, env): - return (types._list_Q(ast) and - types._symbol_Q(ast[0]) and - env.find(ast[0]) and - hasattr(env.get(ast[0]), '_ismacro_')) - -def macroexpand(ast, env): - while is_macro_call(ast, env): - mac = env.get(ast[0]) - ast = macroexpand(mac(*ast[1:]), env) - return ast - -def eval_ast(ast, env): - if types._symbol_Q(ast): - return env.get(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 types._hash_map(*keyvals) - else: - return ast # primitive value, return unchanged - -def EVAL(ast, env): - while True: - #print("EVAL %s" % printer._pr_str(ast)) - if not types._list_Q(ast): - return eval_ast(ast, env) - - # apply list - ast = macroexpand(ast, env) - if not types._list_Q(ast): return ast - 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)) - ast = a2 - env = let_env - # Continue loop (TCO) - elif "quote" == a0: - return ast[1] - elif "quasiquote" == a0: - ast = quasiquote(ast[1]); - # Continue loop (TCO) - elif 'defmacro!' == a0: - func = EVAL(ast[2], env) - func._ismacro_ = True - return env.set(ast[1], func) - elif 'macroexpand' == a0: - return macroexpand(ast[1], env) - elif "py!*" == a0: - 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]) - elif "." == a0: - el = eval_ast(ast[2:], env) - f = eval(ast[1]) - return f(*el) - elif "try*" == a0: - a1, a2 = ast[1], ast[2] - if a2[0] == "catch*": - try: - return EVAL(a1, env); - except Exception as exc: - exc = exc.args[0] - catch_env = Env(env, [a2[1]], [exc]) - return EVAL(a2[2], catch_env) - else: - return EVAL(a1, env); - elif "do" == a0: - eval_ast(ast[1:-1], env) - ast = ast[-1] - # Continue loop (TCO) - 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: ast = ast[3] - else: ast = None - else: - ast = a2 - # Continue loop (TCO) - elif "fn*" == a0: - a1, a2 = ast[1], ast[2] - return types._function(EVAL, Env, a2, env, a1) - else: - el = eval_ast(ast, env) - f = el[0] - if hasattr(f, '__ast__'): - ast = f.__ast__ - env = f.__gen_env__(el[1:]) - else: - return f(*el[1:]) - -# print -def PRINT(exp): - return printer._pr_str(exp) - -# repl -repl_env = Env() -def REP(str): - return PRINT(EVAL(READ(str), repl_env)) - -# 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:])) - -# 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))))))))") - -if len(sys.argv) >= 2: - REP('(load-file "' + sys.argv[1] + '")') - 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()))) -- cgit v1.2.3 From b8ee29b22fbaa7a01f2754b4d6dd9af52e02017c Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Thu, 18 Dec 2014 20:33:49 -0600 Subject: All: add keywords. Also, fix nth and count to match cloure. --- python/core.py | 10 ++++++++-- python/mal_types.py | 7 +++++++ python/printer.py | 4 +++- python/reader.py | 3 ++- python/step3_env.py | 8 ++++---- python/step4_if_fn_do.py | 2 +- python/step5_tco.py | 2 +- python/step6_file.py | 6 +++--- python/step7_quote.py | 6 +++--- python/step8_macros.py | 6 +++--- python/step9_try.py | 8 +++----- python/stepA_interop.py | 6 +++--- 12 files changed, 41 insertions(+), 27 deletions(-) (limited to 'python') diff --git a/python/core.py b/python/core.py index d10047d..4a64594 100644 --- a/python/core.py +++ b/python/core.py @@ -60,7 +60,9 @@ def cons(x, seq): return List([x]) + List(seq) def concat(*lsts): return List(chain(*lsts)) -def nth(lst, idx): return lst[idx] +def nth(lst, idx): + if idx < len(lst): return lst[idx] + else: throw("nth: index out of range") def first(lst): return lst[0] @@ -68,7 +70,9 @@ def rest(lst): return List(lst[1:]) def empty_Q(lst): return len(lst) == 0 -def count(lst): return len(lst) +def count(lst): + if types._nil_Q(lst): return 0 + else: return len(lst) # retains metadata def conj(lst, *args): @@ -114,6 +118,8 @@ ns = { 'false?': types._false_Q, 'symbol': types._symbol, 'symbol?': types._symbol_Q, + 'keyword': types._keyword, + 'keyword?': types._keyword_Q, 'pr-str': pr_str, 'str': do_str, diff --git a/python/mal_types.py b/python/mal_types.py index e6bd70d..5fb9bba 100644 --- a/python/mal_types.py +++ b/python/mal_types.py @@ -58,6 +58,13 @@ class Symbol(str): pass def _symbol(str): return Symbol(str) def _symbol_Q(exp): return type(exp) == Symbol +# Keywords +# A specially prefixed string +def _keyword(str): + if str[0] == u"\u029e": return str + else: return u"\u029e" + str +def _keyword_Q(exp): return _string_Q(exp) and exp[0] == u"\u029e" + # Functions def _function(Eval, Env, ast, env, params): def fn(*args): diff --git a/python/printer.py b/python/printer.py index 65bf256..78a2fcf 100644 --- a/python/printer.py +++ b/python/printer.py @@ -12,7 +12,9 @@ def _pr_str(obj, print_readably=True): ret.extend((_pr_str(k), _pr_str(obj[k],_r))) return "{" + " ".join(ret) + "}" elif types._string_Q(obj): - if print_readably: + if len(obj) > 0 and obj[0] == u'\u029e': + return ':' + obj[1:] + elif print_readably: return '"' + obj.encode('unicode_escape').decode('latin1').replace('"', '\\"') + '"' else: return obj diff --git a/python/reader.py b/python/reader.py index 13b1f7b..71ad3d6 100644 --- a/python/reader.py +++ b/python/reader.py @@ -1,5 +1,5 @@ import re -from mal_types import (_symbol, _list, _vector, _hash_map) +from mal_types import (_symbol, _keyword, _list, _vector, _hash_map) class Blank(Exception): pass @@ -29,6 +29,7 @@ def read_atom(reader): if re.match(int_re, token): return int(token) elif re.match(float_re, token): return int(token) elif token[0] == '"': return token[1:-1].replace('\\"', '"') + elif token[0] == ':': return _keyword(token[1:]) elif token == "nil": return None elif token == "true": return True elif token == "false": return False diff --git a/python/step3_env.py b/python/step3_env.py index 4565011..86dc176 100644 --- a/python/step3_env.py +++ b/python/step3_env.py @@ -58,10 +58,10 @@ repl_env = Env() def REP(str): return PRINT(EVAL(READ(str), repl_env)) -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_env.set(types._symbol('+'), lambda a,b: a+b) +repl_env.set(types._symbol('-'), lambda a,b: a-b) +repl_env.set(types._symbol('*'), lambda a,b: a*b) +repl_env.set(types._symbol('/'), lambda a,b: int(a/b)) # repl loop while True: diff --git a/python/step4_if_fn_do.py b/python/step4_if_fn_do.py index e99cfcf..39b9dd6 100644 --- a/python/step4_if_fn_do.py +++ b/python/step4_if_fn_do.py @@ -74,7 +74,7 @@ def REP(str): return PRINT(EVAL(READ(str), repl_env)) # core.py: defined using python -for k, v in core.ns.items(): repl_env.set(k, v) +for k, v in core.ns.items(): repl_env.set(types._symbol(k), v) # core.mal: defined using the language itself REP("(def! not (fn* (a) (if a false true)))") diff --git a/python/step5_tco.py b/python/step5_tco.py index cbb92c9..da338d4 100644 --- a/python/step5_tco.py +++ b/python/step5_tco.py @@ -83,7 +83,7 @@ def REP(str): return PRINT(EVAL(READ(str), repl_env)) # core.py: defined using python -for k, v in core.ns.items(): repl_env.set(k, v) +for k, v in core.ns.items(): repl_env.set(types._symbol(k), v) # core.mal: defined using the language itself REP("(def! not (fn* (a) (if a false true)))") diff --git a/python/step6_file.py b/python/step6_file.py index 9d84d1f..5d10b46 100644 --- a/python/step6_file.py +++ b/python/step6_file.py @@ -83,9 +83,9 @@ def REP(str): return PRINT(EVAL(READ(str), repl_env)) # 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:])) +for k, v in core.ns.items(): repl_env.set(types._symbol(k), v) +repl_env.set(types._symbol('eval'), lambda ast: EVAL(ast, repl_env)) +repl_env.set(types._symbol('*ARGV*'), types._list(*sys.argv[2:])) # core.mal: defined using the language itself REP("(def! not (fn* (a) (if a false true)))") diff --git a/python/step7_quote.py b/python/step7_quote.py index de19c6d..7c97c23 100644 --- a/python/step7_quote.py +++ b/python/step7_quote.py @@ -106,9 +106,9 @@ def REP(str): return PRINT(EVAL(READ(str), repl_env)) # 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:])) +for k, v in core.ns.items(): repl_env.set(types._symbol(k), v) +repl_env.set(types._symbol('eval'), lambda ast: EVAL(ast, repl_env)) +repl_env.set(types._symbol('*ARGV*'), types._list(*sys.argv[2:])) # core.mal: defined using the language itself REP("(def! not (fn* (a) (if a false true)))") diff --git a/python/step8_macros.py b/python/step8_macros.py index 80ca239..da863c1 100644 --- a/python/step8_macros.py +++ b/python/step8_macros.py @@ -126,9 +126,9 @@ def REP(str): return PRINT(EVAL(READ(str), repl_env)) # 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:])) +for k, v in core.ns.items(): repl_env.set(types._symbol(k), v) +repl_env.set(types._symbol('eval'), lambda ast: EVAL(ast, repl_env)) +repl_env.set(types._symbol('*ARGV*'), types._list(*sys.argv[2:])) # core.mal: defined using the language itself REP("(def! not (fn* (a) (if a false true)))") diff --git a/python/step9_try.py b/python/step9_try.py index 65da08c..e01f42c 100644 --- a/python/step9_try.py +++ b/python/step9_try.py @@ -143,12 +143,11 @@ def REP(str): return PRINT(EVAL(READ(str), repl_env)) # 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:])) +for k, v in core.ns.items(): repl_env.set(types._symbol(k), v) +repl_env.set(types._symbol('eval'), lambda ast: EVAL(ast, repl_env)) +repl_env.set(types._symbol('*ARGV*'), types._list(*sys.argv[2:])) # 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)))))))") @@ -159,7 +158,6 @@ if len(sys.argv) >= 2: sys.exit(0) # repl loop -REP("(println (str \"Mal [\" *host-language* \"]\"))") while True: try: line = mal_readline.readline("user> ") diff --git a/python/stepA_interop.py b/python/stepA_interop.py index 723f0ed..93cdb2e 100644 --- a/python/stepA_interop.py +++ b/python/stepA_interop.py @@ -149,9 +149,9 @@ def REP(str): return PRINT(EVAL(READ(str), repl_env)) # 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:])) +for k, v in core.ns.items(): repl_env.set(types._symbol(k), v) +repl_env.set(types._symbol('eval'), lambda ast: EVAL(ast, repl_env)) +repl_env.set(types._symbol('*ARGV*'), types._list(*sys.argv[2:])) # core.mal: defined using the language itself REP("(def! *host-language* \"python\")") -- cgit v1.2.3 From d706ed5041f3b8eb90692d72d5e8db1a67cc7200 Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Tue, 6 Jan 2015 20:58:33 -0600 Subject: Python: fix python3 support with keywords. --- python/mal_types.py | 18 +++++++++++++++--- python/printer.py | 2 +- 2 files changed, 16 insertions(+), 4 deletions(-) (limited to 'python') diff --git a/python/mal_types.py b/python/mal_types.py index 5fb9bba..b1b1b3b 100644 --- a/python/mal_types.py +++ b/python/mal_types.py @@ -1,4 +1,15 @@ import sys, copy, types as pytypes + +# python 3.0 differences +if sys.hexversion > 0x3000000: + def u(x): + return x +else: + import codecs + def u(x): + return codecs.unicode_escape_decode(x)[0] + + if sys.version_info[0] >= 3: str_types = [str] else: @@ -61,9 +72,10 @@ def _symbol_Q(exp): return type(exp) == Symbol # Keywords # A specially prefixed string def _keyword(str): - if str[0] == u"\u029e": return str - else: return u"\u029e" + str -def _keyword_Q(exp): return _string_Q(exp) and exp[0] == u"\u029e" + if str[0] == u("\u029e"): return str + else: return u("\u029e") + str +def _keyword_Q(exp): + return _string_Q(exp) and exp[0] == u("\u029e") # Functions def _function(Eval, Env, ast, env, params): diff --git a/python/printer.py b/python/printer.py index 78a2fcf..98e3e90 100644 --- a/python/printer.py +++ b/python/printer.py @@ -12,7 +12,7 @@ def _pr_str(obj, print_readably=True): ret.extend((_pr_str(k), _pr_str(obj[k],_r))) return "{" + " ".join(ret) + "}" elif types._string_Q(obj): - if len(obj) > 0 and obj[0] == u'\u029e': + if len(obj) > 0 and obj[0] == types.u('\u029e'): return ':' + obj[1:] elif print_readably: return '"' + obj.encode('unicode_escape').decode('latin1').replace('"', '\\"') + '"' -- cgit v1.2.3 From 90f618cbe7ac7740accf501a75be6972bd95be1a Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Sat, 28 Feb 2015 11:09:54 -0600 Subject: All: rename stepA_interop to stepA_mal Also, add missed postscript interop tests. --- python/Makefile | 2 +- python/stepA_interop.py | 177 ------------------------------------------------ python/stepA_mal.py | 177 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+), 178 deletions(-) delete mode 100644 python/stepA_interop.py create mode 100644 python/stepA_mal.py (limited to 'python') diff --git a/python/Makefile b/python/Makefile index 6e51430..7842eae 100644 --- a/python/Makefile +++ b/python/Makefile @@ -3,7 +3,7 @@ TESTS = SOURCES_BASE = mal_readline.py mal_types.py reader.py printer.py -SOURCES_LISP = env.py core.py stepA_interop.py +SOURCES_LISP = env.py core.py stepA_mal.py SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) diff --git a/python/stepA_interop.py b/python/stepA_interop.py deleted file mode 100644 index 93cdb2e..0000000 --- a/python/stepA_interop.py +++ /dev/null @@ -1,177 +0,0 @@ -import sys, traceback -import mal_readline -import mal_types as types -import reader, printer -from env import Env -import core - -# read -def READ(str): - return reader.read_str(str) - -# eval -def is_pair(x): - return types._sequential_Q(x) and len(x) > 0 - -def quasiquote(ast): - if not is_pair(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 types._list(types._symbol("concat"), - ast[0][1], - quasiquote(ast[1:])) - else: - return types._list(types._symbol("cons"), - quasiquote(ast[0]), - quasiquote(ast[1:])) - -def is_macro_call(ast, env): - return (types._list_Q(ast) and - types._symbol_Q(ast[0]) and - env.find(ast[0]) and - hasattr(env.get(ast[0]), '_ismacro_')) - -def macroexpand(ast, env): - while is_macro_call(ast, env): - mac = env.get(ast[0]) - ast = macroexpand(mac(*ast[1:]), env) - return ast - -def eval_ast(ast, env): - if types._symbol_Q(ast): - return env.get(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 types._hash_map(*keyvals) - else: - return ast # primitive value, return unchanged - -def EVAL(ast, env): - while True: - #print("EVAL %s" % printer._pr_str(ast)) - if not types._list_Q(ast): - return eval_ast(ast, env) - - # apply list - ast = macroexpand(ast, env) - if not types._list_Q(ast): return ast - 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)) - ast = a2 - env = let_env - # Continue loop (TCO) - elif "quote" == a0: - return ast[1] - elif "quasiquote" == a0: - ast = quasiquote(ast[1]); - # Continue loop (TCO) - elif 'defmacro!' == a0: - func = EVAL(ast[2], env) - func._ismacro_ = True - return env.set(ast[1], func) - elif 'macroexpand' == a0: - return macroexpand(ast[1], env) - elif "py!*" == a0: - 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]) - elif "." == a0: - el = eval_ast(ast[2:], env) - f = eval(ast[1]) - return f(*el) - elif "try*" == a0: - a1, a2 = ast[1], ast[2] - if a2[0] == "catch*": - try: - return EVAL(a1, env); - except Exception as exc: - exc = exc.args[0] - catch_env = Env(env, [a2[1]], [exc]) - return EVAL(a2[2], catch_env) - else: - return EVAL(a1, env); - elif "do" == a0: - eval_ast(ast[1:-1], env) - ast = ast[-1] - # Continue loop (TCO) - 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: ast = ast[3] - else: ast = None - else: - ast = a2 - # Continue loop (TCO) - elif "fn*" == a0: - a1, a2 = ast[1], ast[2] - return types._function(EVAL, Env, a2, env, a1) - else: - el = eval_ast(ast, env) - f = el[0] - if hasattr(f, '__ast__'): - ast = f.__ast__ - env = f.__gen_env__(el[1:]) - else: - return f(*el[1:]) - -# print -def PRINT(exp): - return printer._pr_str(exp) - -# repl -repl_env = Env() -def REP(str): - return PRINT(EVAL(READ(str), repl_env)) - -# core.py: defined using python -for k, v in core.ns.items(): repl_env.set(types._symbol(k), v) -repl_env.set(types._symbol('eval'), lambda ast: EVAL(ast, repl_env)) -repl_env.set(types._symbol('*ARGV*'), types._list(*sys.argv[2:])) - -# 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))))))))") - -if len(sys.argv) >= 2: - REP('(load-file "' + sys.argv[1] + '")') - 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()))) diff --git a/python/stepA_mal.py b/python/stepA_mal.py new file mode 100644 index 0000000..93cdb2e --- /dev/null +++ b/python/stepA_mal.py @@ -0,0 +1,177 @@ +import sys, traceback +import mal_readline +import mal_types as types +import reader, printer +from env import Env +import core + +# read +def READ(str): + return reader.read_str(str) + +# eval +def is_pair(x): + return types._sequential_Q(x) and len(x) > 0 + +def quasiquote(ast): + if not is_pair(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 types._list(types._symbol("concat"), + ast[0][1], + quasiquote(ast[1:])) + else: + return types._list(types._symbol("cons"), + quasiquote(ast[0]), + quasiquote(ast[1:])) + +def is_macro_call(ast, env): + return (types._list_Q(ast) and + types._symbol_Q(ast[0]) and + env.find(ast[0]) and + hasattr(env.get(ast[0]), '_ismacro_')) + +def macroexpand(ast, env): + while is_macro_call(ast, env): + mac = env.get(ast[0]) + ast = macroexpand(mac(*ast[1:]), env) + return ast + +def eval_ast(ast, env): + if types._symbol_Q(ast): + return env.get(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 types._hash_map(*keyvals) + else: + return ast # primitive value, return unchanged + +def EVAL(ast, env): + while True: + #print("EVAL %s" % printer._pr_str(ast)) + if not types._list_Q(ast): + return eval_ast(ast, env) + + # apply list + ast = macroexpand(ast, env) + if not types._list_Q(ast): return ast + 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)) + ast = a2 + env = let_env + # Continue loop (TCO) + elif "quote" == a0: + return ast[1] + elif "quasiquote" == a0: + ast = quasiquote(ast[1]); + # Continue loop (TCO) + elif 'defmacro!' == a0: + func = EVAL(ast[2], env) + func._ismacro_ = True + return env.set(ast[1], func) + elif 'macroexpand' == a0: + return macroexpand(ast[1], env) + elif "py!*" == a0: + 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]) + elif "." == a0: + el = eval_ast(ast[2:], env) + f = eval(ast[1]) + return f(*el) + elif "try*" == a0: + a1, a2 = ast[1], ast[2] + if a2[0] == "catch*": + try: + return EVAL(a1, env); + except Exception as exc: + exc = exc.args[0] + catch_env = Env(env, [a2[1]], [exc]) + return EVAL(a2[2], catch_env) + else: + return EVAL(a1, env); + elif "do" == a0: + eval_ast(ast[1:-1], env) + ast = ast[-1] + # Continue loop (TCO) + 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: ast = ast[3] + else: ast = None + else: + ast = a2 + # Continue loop (TCO) + elif "fn*" == a0: + a1, a2 = ast[1], ast[2] + return types._function(EVAL, Env, a2, env, a1) + else: + el = eval_ast(ast, env) + f = el[0] + if hasattr(f, '__ast__'): + ast = f.__ast__ + env = f.__gen_env__(el[1:]) + else: + return f(*el[1:]) + +# print +def PRINT(exp): + return printer._pr_str(exp) + +# repl +repl_env = Env() +def REP(str): + return PRINT(EVAL(READ(str), repl_env)) + +# core.py: defined using python +for k, v in core.ns.items(): repl_env.set(types._symbol(k), v) +repl_env.set(types._symbol('eval'), lambda ast: EVAL(ast, repl_env)) +repl_env.set(types._symbol('*ARGV*'), types._list(*sys.argv[2:])) + +# 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))))))))") + +if len(sys.argv) >= 2: + REP('(load-file "' + sys.argv[1] + '")') + 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()))) -- cgit v1.2.3