RPython: self-hosting
[jackhill/mal.git] / rpython / mal_types.py
1 import sys, copy, types as pytypes
2
3 # General functions
4
5 def _equal_Q(a, b):
6 assert isinstance(a, MalType) and isinstance(b, MalType)
7 ota, otb = a.__class__, b.__class__
8 if not (ota is otb or (_sequential_Q(a) and _sequential_Q(b))):
9 return False
10 if _symbol_Q(a):
11 assert isinstance(a, MalSym) and isinstance(b, MalSym)
12 return a.value == b.value
13 elif _string_Q(a):
14 assert isinstance(a, MalStr) and isinstance(b, MalStr)
15 return a.value == b.value
16 elif _int_Q(a):
17 assert isinstance(a, MalInt) and isinstance(b, MalInt)
18 return a.value == b.value
19 elif _list_Q(a) or _vector_Q(a):
20 ## elif _list_Q(a):
21 if len(a) != len(b): return False
22 for i in range(len(a)):
23 if not _equal_Q(a[i], b[i]): return False
24 return True
25 ## elif _hash_map_Q(a):
26 ## akeys = a.keys()
27 ## akeys.sort()
28 ## bkeys = b.keys()
29 ## bkeys.sort()
30 ## if len(akeys) != len(bkeys): return False
31 ## for i in range(len(akeys)):
32 ## if akeys[i] != bkeys[i]: return False
33 ## if not equal_Q(a[akeys[i]], b[bkeys[i]]): return False
34 ## return True
35 elif a is b:
36 #elif ((a is nil and a is nil) or (a is true and b is true) or (a
37 # is false and b is false)):
38 return True
39 else:
40 throw_str("no = op defined for %s" % a.__class__.__name__)
41
42 def _sequential_Q(seq): return _list_Q(seq) or _vector_Q(seq)
43 ##def _sequential_Q(seq): return _list_Q(seq)
44
45 def _clone(obj):
46 ## #if type(obj) == type(lambda x:x):
47 if isinstance(obj, MalFunc):
48 return MalFunc(obj.fn, obj.ast, obj.env, obj.params,
49 obj.EvalFunc, obj.ismacro)
50 elif isinstance(obj, MalList):
51 raise Exception("_clone on invalid type")
52 ## if obj.__code__:
53 ## return pytypes.FunctionType(
54 ## obj.__code__, obj.__globals__, name = obj.__name__,
55 ## argdefs = obj.__defaults__, closure = obj.__closure__)
56 ## else:
57 ## return pytypes.FunctionType(
58 ## obj.func_code, obj.func_globals, name = obj.func_name,
59 ## argdefs = obj.func_defaults, closure = obj.func_closure)
60 ## else:
61 ## return copy.copy(obj)
62
63 def _replace(match, sub, old_str):
64 new_str = u""
65 idx = 0
66 while idx < len(old_str):
67 midx = old_str.find(match, idx)
68 if midx < 0: break
69 assert midx >= 0 and midx < len(old_str)
70 new_str = new_str + old_str[idx:midx]
71 new_str = new_str + sub
72 idx = midx + len(match)
73 new_str = new_str + old_str[idx:]
74 return new_str
75
76 #
77 # Mal Types
78 #
79
80 class MalException(Exception):
81 def __init__(self, object):
82 self.object = object
83
84 def throw_str(s):
85 raise MalException(MalStr(unicode(s)))
86
87
88 ### Parent types
89 class MalType(): pass
90
91 ### Scalars
92 class MalNil(MalType): pass
93 nil = MalNil()
94 def _nil_Q(exp):
95 assert isinstance(exp, MalType)
96 return exp is nil
97
98 class MalTrue(MalType): pass
99 true = MalTrue()
100 def _true_Q(exp):
101 assert isinstance(exp, MalType)
102 return exp is true
103
104 class MalFalse(MalType): pass
105 false = MalFalse()
106 def _false_Q(exp):
107 assert isinstance(exp, MalType)
108 return exp is false
109
110 # Numbers
111 class MalInt(MalType):
112 def __init__(self, value):
113 assert isinstance(value, int)
114 self.value = value
115 def _int_Q(exp):
116 assert isinstance(exp, MalType)
117 return exp.__class__ is MalInt
118
119 # String
120 class MalStr(MalType):
121 def __init__(self, value):
122 assert isinstance(value, unicode)
123 self.value = value
124 def __len__(self):
125 return len(self.value)
126 def _string_Q(exp):
127 assert isinstance(exp, MalType)
128 return exp.__class__ is MalStr
129
130 # Symbols
131 class MalSym(MalType):
132 def __init__(self, value):
133 assert isinstance(value, unicode)
134 self.value = value
135 def _symbol(strn):
136 assert isinstance(strn, unicode)
137 return MalSym(strn)
138 def _symbol_Q(exp):
139 assert isinstance(exp, MalType)
140 return exp.__class__ is MalSym
141
142 # Keywords
143 # A specially prefixed string
144 def _keyword(mstr):
145 assert isinstance(mstr, MalType)
146 if isinstance(mstr, MalStr):
147 val = mstr.value
148 if val[0] == u"\u029e": return mstr
149 else: return MalStr(u"\u029e" + val)
150 else:
151 throw_str("_keyword called on non-string")
152 # Create keyword from unicode string
153 def _keywordu(strn):
154 assert isinstance(strn, unicode)
155 return MalStr(u"\u029e" + strn)
156 def _keyword_Q(exp):
157 if isinstance(exp, MalStr):
158 return exp.value[0] == u"\u029e"
159 else:
160 return False
161
162 # lists
163 class MalList(MalType):
164 def __init__(self, vals):
165 assert isinstance(vals, list)
166 self.values = vals
167 def append(self, val):
168 self.values.append(val)
169 def rest(self):
170 return MalList(self.values[1:])
171 def __len__(self):
172 return len(self.values)
173 def __getitem__(self, i):
174 assert isinstance(i, int)
175 return self.values[i]
176 def slice(self, start):
177 return MalList(self.values[start:len(self.values)])
178 def slice2(self, start, end):
179 assert end >= 0
180 return MalList(self.values[start:end])
181 ## def __add__(self, rhs): return List(list.__add__(self, rhs))
182 ## def __getitem__(self, i):
183 ## if type(i) == slice: return List(list.__getitem__(self, i))
184 ## elif i >= len(self): return None
185 ## else: return list.__getitem__(self, i)
186 def _list(*vals): return MalList(list(vals))
187 def _listl(lst): return MalList(lst)
188 def _list_Q(exp):
189 assert isinstance(exp, MalType)
190 return exp.__class__ is MalList
191
192 ### vectors
193 class MalVector(MalList):
194 pass
195 def _vector(*vals): return MalVector(list(vals))
196 def _vectorl(lst): return MalVector(lst)
197 def _vector_Q(exp):
198 assert isinstance(exp, MalType)
199 return exp.__class__ is MalVector
200
201 ### hash maps
202 class MalHashMap(MalType):
203 def __init__(self, dct):
204 #assert isinstance(dct, {}.__class__)
205 self.dct = dct
206 def append(self, val):
207 self.dct.append(val)
208 def __getitem__(self, k):
209 assert isinstance(k, unicode)
210 return self.dct[k]
211 def __setitem__(self, k, v):
212 assert isinstance(k, unicode)
213 assert isinstance(v, MalType)
214 self.dct[k] = v
215 return v
216 def _hash_mapl(kvs):
217 dct = {}
218 for i in range(0, len(kvs), 2):
219 k = kvs[i]
220 assert isinstance(k, MalStr)
221 v = kvs[i+1]
222 dct[k.value] = v
223 return MalHashMap(dct)
224 #def _hash_maph(l): return MalHashMap(l.values)
225 def _hash_map_Q(exp):
226 assert isinstance(exp, MalType)
227 return exp.__class__ is MalHashMap
228
229 # Functions
230 # env import must happen after MalSym and MalList definitions to allow
231 # circular dependency
232 from env import Env
233 class MalFunc(MalType):
234 def __init__(self, fn, ast=None, env=None, params=None,
235 EvalFunc=None, ismacro=False):
236 if fn is None and EvalFunc is None:
237 throw_str("MalFunc requires either fn or EvalFunc")
238 self.fn = fn
239 #assert isinstance(ast, MalType) or ast is None
240 self.ast = ast
241 self.env = env
242 self.params = params
243 self.EvalFunc = EvalFunc
244 self.ismacro = ismacro
245 self.meta = nil
246 def apply(self, args):
247 if self.EvalFunc:
248 return self.EvalFunc(self.ast, self.gen_env(args))
249 else:
250 return self.fn(args)
251 def gen_env(self, args):
252 return Env(self.env, self.params, args)
253 def _function_Q(exp):
254 assert isinstance(exp, MalType)
255 return exp.__class__ is MalFunc
256
257
258 # atoms
259 class MalAtom(MalType):
260 def __init__(self, val):
261 self.val = val
262 def _atom(val): return MalAtom(val)
263 def _atom_Q(exp): return exp.__class__ is MalAtom