Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/python-wasm
Path: blob/main/python/pylang/src/baselib/builtins.py
1398 views
1
# globals: exports, console, ρσ_iterator_symbol, ρσ_kwargs_symbol, ρσ_arraylike, ρσ_list_contains
2
3
def abs(a):
4
return r"%js (typeof a === 'object' && a.__abs__ !== undefined) ? a.__abs__() : Math.abs(a)"
5
6
def ρσ_operator_add(a, b):
7
return r"""%js (
8
typeof a !== 'object' ? a + b :
9
((a.__add__ !== undefined ? a.__add__(b) :
10
a.concat !== undefined ? a.concat(b) :
11
a + b)
12
)
13
)
14
"""
15
16
def ρσ_operator_neg(a):
17
return v"(typeof a === 'object' && a.__neg__ !== undefined) ? a.__neg__() : (-a)"
18
19
def ρσ_operator_sub(a, b):
20
return v"(typeof a === 'object' && a.__sub__ !== undefined) ? a.__sub__(b) : a - b"
21
22
def ρσ_operator_mul(a, b):
23
return v"(typeof a === 'object' && a.__mul__ !== undefined) ? a.__mul__(b) : a * b"
24
25
def ρσ_operator_div(a, b):
26
return v"(typeof a === 'object' && a.__div__ !== undefined) ? a.__div__(b) : a / b"
27
28
def ρσ_operator_pow(a, b):
29
return v"(typeof a === 'object' && a.__pow__ !== undefined) ? a.__pow__(b) : a ** b"
30
31
32
def ρσ_operator_iadd(a, b):
33
return v"(typeof a === 'object' && a.__iadd__ !== undefined) ? a.__iadd__(b) : ρσ_operator_add(a,b)"
34
35
def ρσ_operator_isub(a, b):
36
return v"(typeof a === 'object' && a.__isub__ !== undefined) ? a.__isub__(b) : ρσ_operator_sub(a,b)"
37
38
def ρσ_operator_imul(a, b):
39
return v"(typeof a === 'object' && a.__imul__ !== undefined) ? a.__imul__(b) : ρσ_operator_mul(a,b)"
40
41
def ρσ_operator_idiv(a, b):
42
return v"(typeof a === 'object' && a.__idiv__ !== undefined) ? a.__idiv__(b) : ρσ_operator_div(a,b)"
43
44
def ρσ_operator_ipow(a, b):
45
return v"(typeof a === 'object' && a.__ipow__ !== undefined) ? a.__ipow__(b) : ρσ_operator_pow(a,b)"
46
47
48
def ρσ_operator_truediv(a, b):
49
return v"(typeof a === 'object' && a.__truediv__ !== undefined) ? a.__truediv__(b) : a / b"
50
51
def ρσ_operator_floordiv(a, b):
52
return v"(typeof a === 'object' && a.__floordiv__ !== undefined) ? a.__floordiv__(b) : Math.floor(a / b)"
53
54
def ρσ_bool(val):
55
return v'!!val'
56
57
def ρσ_round(val):
58
# no attempt at Python semantics yet
59
return v"Math.round(val)"
60
61
def ρσ_print():
62
if v'typeof console' is 'object':
63
parts = v'[]'
64
for v'var i = 0; i < arguments.length; i++':
65
parts.push(ρσ_str(arguments[i])) # noqa: undef
66
console.log(parts.join(' '))
67
68
def ρσ_int(val, base):
69
if jstype(val) is "number":
70
ans = val | 0
71
else:
72
ans = parseInt(val, base or 10)
73
if isNaN(ans):
74
raise ValueError('Invalid literal for int with base ' + (base or 10) + ': ' + val)
75
return ans
76
77
def ρσ_float(val):
78
if jstype(val) is "number":
79
ans = val
80
else:
81
ans = parseFloat(val)
82
if isNaN(ans):
83
raise ValueError('Could not convert string to float: ' + arguments[0])
84
return ans
85
86
def ρσ_arraylike_creator():
87
names = 'Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array'.split(' ')
88
if jstype(HTMLCollection) is 'function':
89
names = names.concat('HTMLCollection NodeList NamedNodeMap TouchList'.split(' '))
90
return def(x):
91
if Array.isArray(x) or v'typeof x' is 'string' or names.indexOf(Object.prototype.toString.call(x).slice(8, -1)) > -1:
92
return True
93
return False
94
95
def options_object(f):
96
return def():
97
if v'typeof arguments[arguments.length - 1] === "object"':
98
arguments[arguments.length - 1][ρσ_kwargs_symbol] = True
99
return f.apply(this, arguments)
100
101
def ρσ_id(x):
102
return x.ρσ_object_id
103
104
def ρσ_dir(item):
105
# TODO: this isn't really representative of real Python's dir(), nor is it
106
# an intuitive replacement for "for ... in" loop, need to update this logic
107
# and introduce a different way of achieving "for ... in"
108
arr = []
109
for v'var i in item': arr.push(i) # noqa:undef
110
return arr
111
112
def ρσ_ord(x):
113
ans = x.charCodeAt(0)
114
if 0xD800 <= ans <= 0xDBFF:
115
second = x.charCodeAt(1)
116
if 0xDC00 <= second <= 0xDFFF:
117
return (ans - 0xD800) * 0x400 + second - 0xDC00 + 0x10000
118
raise TypeError('string is missing the low surrogate char')
119
return ans
120
121
def ρσ_chr(code):
122
if code <= 0xFFFF:
123
return String.fromCharCode(code)
124
code -= 0x10000
125
return String.fromCharCode(0xD800+(code>>10), 0xDC00+(code&0x3FF))
126
127
def ρσ_callable(x):
128
return v'typeof x === "function"'
129
130
def ρσ_bin(x):
131
if jstype(x) is not 'number' or x % 1 is not 0:
132
raise TypeError('integer required')
133
ans = x.toString(2)
134
if ans[0] is '-':
135
ans = '-' + '0b' + ans[1:]
136
else:
137
ans = '0b' + ans
138
return ans
139
140
def ρσ_hex(x):
141
if jstype(x) is not 'number' or x % 1 is not 0:
142
raise TypeError('integer required')
143
ans = x.toString(16)
144
if ans[0] is '-':
145
ans = '-' + '0x' + ans[1:]
146
else:
147
ans = '0x' + ans
148
return ans
149
150
def ρσ_enumerate(iterable):
151
ans = v'{"_i":-1}'
152
ans[ρσ_iterator_symbol] = def():
153
return this
154
if ρσ_arraylike(iterable):
155
ans['next'] = def():
156
this._i += 1
157
if this._i < iterable.length:
158
return v"{'done':false, 'value':[this._i, iterable[this._i]]}"
159
return v"{'done':true}"
160
return ans
161
if jstype(iterable[ρσ_iterator_symbol]) is 'function':
162
iterator = iterable.keys() if jstype(Map) is 'function' and v'iterable instanceof Map' else iterable[ρσ_iterator_symbol]()
163
ans['_iterator'] = iterator
164
ans['next'] = def():
165
r = this._iterator.next()
166
if r.done:
167
return v"{'done':true}"
168
this._i += 1
169
return v"{'done':false, 'value':[this._i, r.value]}"
170
return ans
171
return ρσ_enumerate(Object.keys(iterable))
172
173
def ρσ_reversed(iterable):
174
if ρσ_arraylike(iterable):
175
ans = v'{"_i": iterable.length}'
176
ans['next'] = def():
177
this._i -= 1
178
if this._i > -1:
179
return v"{'done':false, 'value':iterable[this._i]}"
180
return v"{'done':true}"
181
ans[ρσ_iterator_symbol] = def():
182
return this
183
return ans
184
raise TypeError('reversed() can only be called on arrays or strings')
185
186
def ρσ_iter(iterable):
187
# Generate a JavaScript iterator object from iterable
188
if jstype(iterable[ρσ_iterator_symbol]) is 'function':
189
return iterable.keys() if jstype(Map) is 'function' and v'iterable instanceof Map' else iterable[ρσ_iterator_symbol]()
190
if ρσ_arraylike(iterable):
191
ans = v'{"_i":-1}'
192
ans[ρσ_iterator_symbol] = def():
193
return this
194
ans['next'] = def():
195
this._i += 1
196
if this._i < iterable.length:
197
return v"{'done':false, 'value':iterable[this._i]}"
198
return v"{'done':true}"
199
return ans
200
return ρσ_iter(Object.keys(iterable))
201
202
def ρσ_range_next(step, length):
203
this._i += step
204
this._idx += 1
205
if this._idx >= length:
206
this._i, this._idx = this.__i, -1
207
return v"{'done':true}"
208
return v"{'done':false, 'value':this._i}"
209
210
def ρσ_range(start, stop, step):
211
if arguments.length <= 1:
212
stop = start or 0
213
start = 0
214
step = arguments[2] or 1
215
length = Math.max(Math.ceil((stop - start) / step), 0)
216
ans = v'{start:start, step:step, stop:stop}'
217
ans[ρσ_iterator_symbol] = def():
218
it = v'{"_i": start - step, "_idx": -1}'
219
it.next = ρσ_range_next.bind(it, step, length)
220
it[ρσ_iterator_symbol] = def():
221
return this
222
return it
223
ans.count = def(val):
224
if not this._cached:
225
this._cached = list(this)
226
return this._cached.count(val)
227
ans.index = def(val):
228
if not this._cached:
229
this._cached = list(this)
230
return this._cached.index(val)
231
232
def slice(new_start=undefined, new_stop=undefined):
233
if step < 0:
234
if new_start is undefined and new_stop is undefined:
235
return ans
236
# I'm too lazy to do this directly, so just fallback for now.
237
return list(ans)[new_start:new_stop]
238
239
if new_start is undefined:
240
if new_stop is undefined:
241
return ans
242
else:
243
if new_stop < 0:
244
new_stop = (length + new_stop);
245
return ρσ_range(start, Math.max(start, Math.min(new_stop*step+start, stop)), step)
246
if new_stop is undefined:
247
if new_start < 0:
248
new_start = (length + new_start);
249
return ρσ_range(Math.min(stop, Math.max(new_start*step+start, start)), stop, step)
250
else:
251
if new_stop < 0:
252
new_stop = (length + new_stop);
253
if new_start < 0:
254
new_start = (length + new_start);
255
return ρσ_range(Math.min(new_stop*step, Math.max(new_start*step+start, start)), Math.max(new_start*step+start, Math.min(new_stop*step+start, stop)), step)
256
ans.slice = slice;
257
258
# ans.__getitem__
259
260
ans.__len__ = def():
261
return length
262
ans.__repr__ = def():
263
if step == 1:
264
return f'range({start}, {stop})'
265
else:
266
return f'range({start}, {stop}, {step})'
267
ans.__str__ = ans.toString = ans.__repr__
268
if jstype(Proxy) is 'function':
269
ans = new Proxy(ans, {
270
'get': def(obj, prop):
271
if jstype(prop) is 'string':
272
iprop = parseInt(prop)
273
if not isNaN(iprop):
274
prop = iprop
275
if jstype(prop) is 'number':
276
if not obj._cached:
277
obj._cached = list(obj)
278
return obj._cached[prop]
279
return obj[prop]
280
})
281
return ans
282
283
def ρσ_getattr(obj, name, defval):
284
try:
285
ret = obj[name]
286
except TypeError:
287
if defval is undefined:
288
raise AttributeError('The attribute ' + name + ' is not present')
289
return defval
290
if ret is undefined and not v'(name in obj)':
291
if defval is undefined:
292
raise AttributeError('The attribute ' + name + ' is not present')
293
ret = defval
294
return ret
295
296
def ρσ_setattr(obj, name, value):
297
obj[name] = value
298
299
def ρσ_hasattr(obj, name):
300
return v'name in obj'
301
302
ρσ_len = (def ():
303
304
def len(obj):
305
if ρσ_arraylike(obj): return obj.length
306
if jstype(obj.__len__) is 'function': return obj.__len__()
307
if v'obj instanceof Set' or v'obj instanceof Map': return obj.size
308
return Object.keys(obj).length
309
310
def len5(obj):
311
if ρσ_arraylike(obj): return obj.length
312
if jstype(obj.__len__) is 'function': return obj.__len__()
313
return Object.keys(obj).length
314
315
return len if v'typeof Set' is 'function' and v'typeof Map' is 'function' else len5
316
)()
317
318
def ρσ_get_module(name):
319
return ρσ_modules[name]
320
321
def ρσ_pow(x, y, z):
322
ans = Math.pow(x, y)
323
if z is not undefined:
324
ans %= z
325
return ans
326
327
def ρσ_type(x):
328
return x.constructor
329
330
331
def ρσ_divmod(x, y):
332
if y is 0:
333
raise ZeroDivisionError('integer division or modulo by zero')
334
d = Math.floor(x / y)
335
return d, x - d * y
336
337
338
def ρσ_max(*args, **kwargs):
339
if args.length is 0:
340
if kwargs.defval is not undefined:
341
return kwargs.defval
342
raise TypeError('expected at least one argument')
343
if args.length is 1:
344
args = args[0]
345
if kwargs.key:
346
args = [kwargs.key(x) for x in args]
347
if not Array.isArray(args):
348
args = list(args)
349
if args.length:
350
return this.apply(None, args)
351
if kwargs.defval is not undefined:
352
return kwargs.defval
353
raise TypeError('expected at least one argument')
354
355
v'var round = ρσ_round; var max = ρσ_max.bind(Math.max), min = ρσ_max.bind(Math.min), bool = ρσ_bool, type = ρσ_type'
356
v'var float = ρσ_float, int = ρσ_int, arraylike = ρσ_arraylike_creator(), ρσ_arraylike = arraylike'
357
v'var print = ρσ_print, id = ρσ_id, get_module = ρσ_get_module, pow = ρσ_pow, divmod = ρσ_divmod'
358
v'var dir = ρσ_dir, ord = ρσ_ord, chr = ρσ_chr, bin = ρσ_bin, hex = ρσ_hex, callable = ρσ_callable'
359
v'var enumerate = ρσ_enumerate, iter = ρσ_iter, reversed = ρσ_reversed, len = ρσ_len'
360
v'var range = ρσ_range, getattr = ρσ_getattr, setattr = ρσ_setattr, hasattr = ρσ_hasattr'
361
362