aboutsummaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2015-03-02 21:33:10 -0600
committerJoel Martin <github@martintribe.org>2015-03-02 21:33:10 -0600
commit835fb7d8b06e2b44792a97ac89994658bf6d00af (patch)
tree578f67726ab9e3ce5fcbc50220e9761a66c5ddf1 /python
parent6b72e6078a7d505ecf9d711eb4a16fc4dfac36b6 (diff)
parent8a98ef9a3f3a6b6d05d02dc305a0c886c907e0f3 (diff)
downloadmal-835fb7d8b06e2b44792a97ac89994658bf6d00af.tar.gz
mal-835fb7d8b06e2b44792a97ac89994658bf6d00af.zip
Merge branch 'master' into gh-pages
Conflicts: .gitignore
Diffstat (limited to 'python')
-rw-r--r--python/Makefile2
-rw-r--r--python/core.py10
-rw-r--r--python/mal_types.py19
-rw-r--r--python/printer.py4
-rw-r--r--python/reader.py3
-rw-r--r--python/step3_env.py8
-rw-r--r--python/step4_if_fn_do.py2
-rw-r--r--python/step5_tco.py2
-rw-r--r--python/step6_file.py6
-rw-r--r--python/step7_quote.py6
-rw-r--r--python/step8_macros.py6
-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\")")