DISABLE FDs (REMOVE ME).
[jackhill/mal.git] / python / mal_types.py
1 import sys, copy, types as pytypes
2
3 # python 3.0 differences
4 if sys.hexversion > 0x3000000:
5 _u = lambda x: x
6 _s2u = lambda x: x
7 else:
8 import codecs
9 _u = lambda x: codecs.unicode_escape_decode(x)[0]
10 _s2u = lambda x: unicode(x)
11
12 if sys.version_info[0] >= 3:
13 str_types = [str]
14 else:
15 str_types = [str, unicode]
16
17 # General functions
18
19 def _equal_Q(a, b):
20 ota, otb = type(a), type(b)
21 if _string_Q(a) and _string_Q(b):
22 return a == b
23 if not (ota == otb or (_sequential_Q(a) and _sequential_Q(b))):
24 return False;
25 if _symbol_Q(a):
26 return a == b
27 elif _list_Q(a) or _vector_Q(a):
28 if len(a) != len(b): return False
29 for i in range(len(a)):
30 if not _equal_Q(a[i], b[i]): return False
31 return True
32 elif _hash_map_Q(a):
33 akeys = sorted(a.keys())
34 bkeys = sorted(b.keys())
35 if len(akeys) != len(bkeys): return False
36 for i in range(len(akeys)):
37 if akeys[i] != bkeys[i]: return False
38 if not _equal_Q(a[akeys[i]], b[bkeys[i]]): return False
39 return True
40 else:
41 return a == b
42
43 def _sequential_Q(seq): return _list_Q(seq) or _vector_Q(seq)
44
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
59 #
60 # Exception type
61 #
62
63 class MalException(Exception):
64 def __init__(self, object):
65 self.object = object
66
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
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
76 def _number_Q(exp): return type(exp) == int
77
78 # Symbols
79 class Symbol(str): pass
80 def _symbol(str): return Symbol(str)
81 def _symbol_Q(exp): return type(exp) == Symbol
82
83 # Keywords
84 # A specially prefixed string
85 def _keyword(str):
86 if str[0] == _u("\u029e"): return str
87 else: return _u("\u029e") + str
88 def _keyword_Q(exp):
89 if type(exp) in str_types:
90 return len(exp) != 0 and exp[0] == _u("\u029e")
91 else:
92 return False
93
94 # Functions
95 def _function(Eval, Env, ast, env, params):
96 def fn(*args):
97 return Eval(ast, Env(env, params, List(args)))
98 fn.__meta__ = None
99 fn.__ast__ = ast
100 fn.__gen_env__ = lambda args: Env(env, params, args)
101 return fn
102 def _function_Q(f):
103 return callable(f)
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))
113 def _list(*vals): return List(vals)
114 def _list_Q(exp): return type(exp) == List
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))
125 def _vector(*vals): return Vector(vals)
126 def _vector_Q(exp): return type(exp) == Vector
127
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
135
136 # atoms
137 class Atom(object):
138 def __init__(self, val):
139 self.val = val
140 def _atom(val): return Atom(val)
141 def _atom_Q(exp): return type(exp) == Atom
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