DISABLE FDs (REMOVE ME).
[jackhill/mal.git] / python / mal_types.py
CommitLineData
a05f7822 1import sys, copy, types as pytypes
d706ed50
JM
2
3# python 3.0 differences
4if sys.hexversion > 0x3000000:
672618d8
JM
5 _u = lambda x: x
6 _s2u = lambda x: x
d706ed50
JM
7else:
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
12if sys.version_info[0] >= 3:
13 str_types = [str]
14else:
15 str_types = [str, unicode]
16
31690700
JM
17# General functions
18
ea81a808 19def _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 43def _sequential_Q(seq): return _list_Q(seq) or _vector_Q(seq)
31690700 44
a05f7822
JM
45def _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
63class MalException(Exception):
64 def __init__(self, object):
65 self.object = object
a05f7822 66
ea81a808
JM
67# Scalars
68def _nil_Q(exp): return exp is None
69def _true_Q(exp): return exp is True
70def _false_Q(exp): return exp is False
185d4f0c
JM
71def _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 76def _number_Q(exp): return type(exp) == int
31690700 77
ea81a808 78# Symbols
31690700 79class Symbol(str): pass
ea81a808
JM
80def _symbol(str): return Symbol(str)
81def _symbol_Q(exp): return type(exp) == Symbol
31690700 82
b8ee29b2
JM
83# Keywords
84# A specially prefixed string
85def _keyword(str):
672618d8 86 if str[0] == _u("\u029e"): return str
185d4f0c 87 else: return _u("\u029e") + str
d706ed50 88def _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 95def _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
102def _function_Q(f):
103 return callable(f)
31690700
JM
104
105# lists
106class 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
113def _list(*vals): return List(vals)
114def _list_Q(exp): return type(exp) == List
31690700
JM
115
116
117# vectors
118class 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
125def _vector(*vals): return Vector(vals)
126def _vector_Q(exp): return type(exp) == Vector
31690700 127
ea81a808
JM
128# Hash maps
129class Hash_Map(dict): pass
130def _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
134def _hash_map_Q(exp): return type(exp) == Hash_Map
31690700
JM
135
136# atoms
137class Atom(object):
138 def __init__(self, val):
139 self.val = val
ea81a808
JM
140def _atom(val): return Atom(val)
141def _atom_Q(exp): return type(exp) == Atom
a5bdda6d
DM
142
143def 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