diff options
Diffstat (limited to 'python')
| -rw-r--r-- | python/Makefile | 2 | ||||
| -rw-r--r-- | python/core.py | 10 | ||||
| -rw-r--r-- | python/mal_types.py | 19 | ||||
| -rw-r--r-- | python/printer.py | 4 | ||||
| -rw-r--r-- | python/reader.py | 3 | ||||
| -rw-r--r-- | python/step3_env.py | 8 | ||||
| -rw-r--r-- | python/step4_if_fn_do.py | 2 | ||||
| -rw-r--r-- | python/step5_tco.py | 2 | ||||
| -rw-r--r-- | python/step6_file.py | 6 | ||||
| -rw-r--r-- | python/step7_quote.py | 6 | ||||
| -rw-r--r-- | python/step8_macros.py | 6 | ||||
| -rw-r--r-- | python/step9_try.py (renamed from python/step9_interop.py) | 23 | ||||
| -rw-r--r-- | python/stepA_mal.py (renamed from python/stepA_more.py) | 6 |
13 files changed, 65 insertions, 32 deletions
diff --git a/python/Makefile b/python/Makefile index b461db3..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_more.py +SOURCES_LISP = env.py core.py stepA_mal.py SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) 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..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: @@ -58,6 +69,14 @@ 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..98e3e90 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] == types.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_interop.py b/python/step9_try.py index 7cacf1f..e01f42c 100644 --- a/python/step9_interop.py +++ b/python/step9_try.py @@ -97,12 +97,17 @@ def EVAL(ast, env): 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] @@ -138,9 +143,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/stepA_more.py b/python/stepA_mal.py index 723f0ed..93cdb2e 100644 --- a/python/stepA_more.py +++ b/python/stepA_mal.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\")") |
