Commit | Line | Data |
---|---|---|
a05f7822 | 1 | import sys, copy, types as pytypes |
d706ed50 JM |
2 | |
3 | # python 3.0 differences | |
4 | if sys.hexversion > 0x3000000: | |
672618d8 JM |
5 | _u = lambda x: x |
6 | _s2u = lambda x: x | |
d706ed50 JM |
7 | else: |
8 | import codecs | |
672618d8 JM |
9 | _u = lambda x: codecs.unicode_escape_decode(x)[0] |
10 | _s2u = lambda x: unicode(x) | |
d706ed50 | 11 | |
a05f7822 JM |
12 | if sys.version_info[0] >= 3: |
13 | str_types = [str] | |
14 | else: | |
15 | str_types = [str, unicode] | |
16 | ||
31690700 JM |
17 | # General functions |
18 | ||
ea81a808 | 19 | def _equal_Q(a, b): |
31690700 | 20 | ota, otb = type(a), type(b) |
a16bb08f DM |
21 | if _string_Q(a) and _string_Q(b): |
22 | return a == b | |
ea81a808 | 23 | if not (ota == otb or (_sequential_Q(a) and _sequential_Q(b))): |
31690700 | 24 | return False; |
ea81a808 | 25 | if _symbol_Q(a): |
31690700 | 26 | return a == b |
ea81a808 | 27 | elif _list_Q(a) or _vector_Q(a): |
31690700 JM |
28 | if len(a) != len(b): return False |
29 | for i in range(len(a)): | |
ea81a808 | 30 | if not _equal_Q(a[i], b[i]): return False |
31690700 | 31 | return True |
ea81a808 | 32 | elif _hash_map_Q(a): |
dd7a4f55 JM |
33 | akeys = sorted(a.keys()) |
34 | bkeys = sorted(b.keys()) | |
31690700 JM |
35 | if len(akeys) != len(bkeys): return False |
36 | for i in range(len(akeys)): | |
37 | if akeys[i] != bkeys[i]: return False | |
6d3fc1be | 38 | if not _equal_Q(a[akeys[i]], b[bkeys[i]]): return False |
31690700 JM |
39 | return True |
40 | else: | |
41 | return a == b | |
42 | ||
ea81a808 | 43 | def _sequential_Q(seq): return _list_Q(seq) or _vector_Q(seq) |
31690700 | 44 | |
a05f7822 JM |
45 | def _clone(obj): |
46 | #if type(obj) == type(lambda x:x): | |
47 | if type(obj) == pytypes.FunctionType: | |
48 | if obj.__code__: | |
49 | return pytypes.FunctionType( | |
50 | obj.__code__, obj.__globals__, name = obj.__name__, | |
51 | argdefs = obj.__defaults__, closure = obj.__closure__) | |
52 | else: | |
53 | return pytypes.FunctionType( | |
54 | obj.func_code, obj.func_globals, name = obj.func_name, | |
55 | argdefs = obj.func_defaults, closure = obj.func_closure) | |
56 | else: | |
57 | return copy.copy(obj) | |
58 | ||
dd7a4f55 JM |
59 | # |
60 | # Exception type | |
61 | # | |
62 | ||
63 | class MalException(Exception): | |
64 | def __init__(self, object): | |
65 | self.object = object | |
a05f7822 | 66 | |
ea81a808 JM |
67 | # Scalars |
68 | def _nil_Q(exp): return exp is None | |
69 | def _true_Q(exp): return exp is True | |
70 | def _false_Q(exp): return exp is False | |
185d4f0c JM |
71 | def _string_Q(exp): |
72 | if type(exp) in str_types: | |
73 | return len(exp) == 0 or exp[0] != _u("\u029e") | |
74 | else: | |
75 | return False | |
9e1b1752 | 76 | def _number_Q(exp): return type(exp) == int |
31690700 | 77 | |
ea81a808 | 78 | # Symbols |
31690700 | 79 | class Symbol(str): pass |
ea81a808 JM |
80 | def _symbol(str): return Symbol(str) |
81 | def _symbol_Q(exp): return type(exp) == Symbol | |
31690700 | 82 | |
b8ee29b2 JM |
83 | # Keywords |
84 | # A specially prefixed string | |
85 | def _keyword(str): | |
672618d8 | 86 | if str[0] == _u("\u029e"): return str |
185d4f0c | 87 | else: return _u("\u029e") + str |
d706ed50 | 88 | def _keyword_Q(exp): |
185d4f0c JM |
89 | if type(exp) in str_types: |
90 | return len(exp) != 0 and exp[0] == _u("\u029e") | |
91 | else: | |
92 | return False | |
b8ee29b2 | 93 | |
ea81a808 | 94 | # Functions |
a34b0200 | 95 | def _function(Eval, Env, ast, env, params): |
a05f7822 | 96 | def fn(*args): |
cbbbec92 | 97 | return Eval(ast, Env(env, params, List(args))) |
a05f7822 JM |
98 | fn.__meta__ = None |
99 | fn.__ast__ = ast | |
100 | fn.__gen_env__ = lambda args: Env(env, params, args) | |
101 | return fn | |
9e1b1752 VS |
102 | def _function_Q(f): |
103 | return callable(f) | |
31690700 JM |
104 | |
105 | # lists | |
106 | class List(list): | |
107 | def __add__(self, rhs): return List(list.__add__(self, rhs)) | |
108 | def __getitem__(self, i): | |
109 | if type(i) == slice: return List(list.__getitem__(self, i)) | |
110 | elif i >= len(self): return None | |
111 | else: return list.__getitem__(self, i) | |
112 | def __getslice__(self, *a): return List(list.__getslice__(self, *a)) | |
ea81a808 JM |
113 | def _list(*vals): return List(vals) |
114 | def _list_Q(exp): return type(exp) == List | |
31690700 JM |
115 | |
116 | ||
117 | # vectors | |
118 | class Vector(list): | |
119 | def __add__(self, rhs): return Vector(list.__add__(self, rhs)) | |
120 | def __getitem__(self, i): | |
121 | if type(i) == slice: return Vector(list.__getitem__(self, i)) | |
122 | elif i >= len(self): return None | |
123 | else: return list.__getitem__(self, i) | |
124 | def __getslice__(self, *a): return Vector(list.__getslice__(self, *a)) | |
ea81a808 JM |
125 | def _vector(*vals): return Vector(vals) |
126 | def _vector_Q(exp): return type(exp) == Vector | |
31690700 | 127 | |
ea81a808 JM |
128 | # Hash maps |
129 | class Hash_Map(dict): pass | |
130 | def _hash_map(*key_vals): | |
131 | hm = Hash_Map() | |
132 | for i in range(0,len(key_vals),2): hm[key_vals[i]] = key_vals[i+1] | |
133 | return hm | |
134 | def _hash_map_Q(exp): return type(exp) == Hash_Map | |
31690700 JM |
135 | |
136 | # atoms | |
137 | class Atom(object): | |
138 | def __init__(self, val): | |
139 | self.val = val | |
ea81a808 JM |
140 | def _atom(val): return Atom(val) |
141 | def _atom_Q(exp): return type(exp) == Atom | |
a5bdda6d DM |
142 | |
143 | def py_to_mal(obj): | |
144 | if type(obj) == list: return List(obj) | |
145 | if type(obj) == tuple: return List(obj) | |
146 | elif type(obj) == dict: return Hash_Map(obj) | |
147 | else: return obj |