Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/python-wasm
Path: blob/main/python/pylang/src/output/operators.py
1398 views
1
# vim:fileencoding=utf-8
2
# License: BSD Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
3
from __python__ import hash_literals
4
from ast_types import (AST_Array, AST_Assign, AST_BaseCall, AST_Binary,
5
AST_Conditional, AST_ItemAccess, AST_Number, AST_Object,
6
AST_Return, AST_Seq, AST_Set, AST_SimpleStatement,
7
AST_Statement, AST_String, AST_Sub, AST_Symbol,
8
AST_SymbolRef, AST_Unary, is_node_type)
9
from output.loops import unpack_tuple
10
11
12
def print_getattr(self, output, skip_expression): # AST_Dot
13
if not skip_expression:
14
expr = self.expression
15
expr.print(output)
16
if is_node_type(expr, AST_Number) and expr.value >= 0:
17
if not RegExp("[xa-f.]", "i").test(output.last()):
18
output.print(".")
19
output.print(".")
20
# the name after dot would be mapped about here.
21
output.print_name(self.property)
22
23
24
def print_getitem(self, output): # AST_Sub
25
expr = self.expression
26
prop = self.property
27
if (is_node_type(prop, AST_Number) or is_node_type(prop, AST_String)) or (
28
is_node_type(prop, AST_SymbolRef) and prop.name
29
and prop.name.startsWith('ρσ_')):
30
expr.print(output)
31
output.print('['), prop.print(output), output.print(']')
32
return
33
is_negative_number = is_node_type(
34
prop, AST_Unary) and prop.operator is "-" and is_node_type(
35
prop.expression, AST_Number)
36
is_repeatable = is_node_type(expr, AST_SymbolRef)
37
if is_repeatable:
38
expr.print(output)
39
else:
40
output.spaced('(ρσ_expr_temp', '=', expr), output.print(')')
41
expr = {'print': lambda: output.print('ρσ_expr_temp')}
42
43
if is_negative_number:
44
output.print('['), expr.print(output), output.print(
45
'.length'), prop.print(output), output.print(']')
46
return
47
is_repeatable = is_node_type(prop, AST_SymbolRef)
48
# We have to check the type of the property because if it is a Symbol, it
49
# will raise a TypeError with the < operator.
50
if is_repeatable:
51
output.spaced('[(typeof', prop, '===', '"number"', '&&', prop)
52
output.spaced('', '<', '0)', '?',
53
expr), output.spaced('.length', '+', prop, ':', prop)
54
output.print("]")
55
else:
56
output.print('[ρσ_bound_index('), prop.print(
57
output), output.comma(), expr.print(output), output.print(')]')
58
59
60
def print_rich_getitem(self, output): # AST_ItemAccess
61
func = 'ρσ_' + ('setitem' if self.assignment else 'getitem')
62
output.print(func + '(')
63
self.expression.print(output), output.comma(), self.property.print(output)
64
if self.assignment:
65
output.comma(), self.assignment.print(output)
66
output.print(')')
67
68
69
def print_splice_assignment(self, output): # AST_Splice
70
# splice assignment via pythonic array[start:end]
71
output.print('ρσ_splice(')
72
self.expression.print(output), output.comma(), self.assignment.print(
73
output), output.comma()
74
self.property.print(output) if self.property else output.print('0')
75
if self.property2:
76
output.comma()
77
self.property2.print(output)
78
output.print(')')
79
80
81
def print_delete(self, output):
82
if is_node_type(self, AST_Symbol):
83
output.assign(self), output.print('undefined')
84
elif is_node_type(self, AST_Sub) or is_node_type(self, AST_ItemAccess):
85
output.print('ρσ_delitem('), self.expression.print(
86
output), output.comma(), self.property.print(output), output.print(
87
')')
88
else:
89
output.spaced('delete', self)
90
91
92
# def print_unary_prefix(self, output):
93
# op = self.operator
94
# if op is 'delete':
95
# return print_delete(self.expression, output)
96
# if op is '-':
97
# output.print("ρσ_operator_neg(")
98
# else:
99
# output.print(op)
100
# if RegExp("^[a-z]", "i").test(op):
101
# output.space()
102
# if self.parenthesized:
103
# output.with_parens(lambda: self.expression.print(output))
104
# else:
105
# self.expression.print(output)
106
# if op is '-':
107
# output.print(")")
108
109
def print_unary_prefix(self, output):
110
op = self.operator
111
if op is 'delete':
112
return print_delete(self.expression, output)
113
output.print(op)
114
if RegExp("^[a-z]", "i").test(op):
115
output.space()
116
if self.parenthesized:
117
output.with_parens(lambda: self.expression.print(output))
118
else:
119
self.expression.print(output)
120
121
def write_instanceof(left, right, output):
122
def do_many(vals):
123
output.print('ρσ_instanceof.apply(null,'), output.space()
124
output.print('['), left.print(output), output.comma()
125
for i in range(len(vals)):
126
vals[i].print(output)
127
if i is not vals.length - 1:
128
output.comma()
129
output.print('])')
130
131
if is_node_type(right, AST_Seq):
132
do_many(right.to_array())
133
elif is_node_type(right, AST_Array):
134
do_many(right.elements)
135
else:
136
output.print('ρσ_instanceof(')
137
left.print(output), output.comma(), right.print(output), output.print(
138
')')
139
140
141
def write_smart_equality(self, output):
142
def is_ok(x):
143
return not (
144
is_node_type(x, AST_Array) or is_node_type(x, AST_Set)
145
or is_node_type(x, AST_Object) or is_node_type(x, AST_Statement)
146
or is_node_type(x, AST_Binary) or is_node_type(x, AST_Conditional)
147
or is_node_type(x, AST_BaseCall) or is_node_type(x, AST_SymbolRef))
148
149
if is_ok(self.left) and is_ok(self.right):
150
if self.operator is '==':
151
output.print('(')
152
output.spaced(self.left, '===', self.right, '||', 'typeof',
153
self.left, '===', '"object"', '&&', 'ρσ_equals(')
154
self.left.print(output), output.print(','), output.space(
155
), self.right.print(output), output.print('))')
156
else:
157
output.print('(')
158
output.spaced(self.left, '!==', self.right, '&&', '(typeof',
159
self.left, '!==', '"object"', '||', 'ρσ_not_equals(')
160
self.left.print(output), output.print(','), output.space(
161
), self.right.print(output), output.print(')))')
162
else:
163
output.print('ρσ_' +
164
('equals(' if self.operator is '==' else 'not_equals('))
165
self.left.print(output), output.print(
166
','), output.space(), self.right.print(output), output.print(')')
167
168
169
comparators = {
170
"<": True,
171
">": True,
172
"<=": True,
173
">=": True,
174
}
175
176
function_ops = {
177
"in": "ρσ_in",
178
'nin': '!ρσ_in',
179
}
180
181
182
def print_binary_op(self, output):
183
if function_ops[self.operator]:
184
output.print(function_ops[self.operator])
185
186
def f_comma():
187
self.left.print(output)
188
output.comma()
189
self.right.print(output)
190
191
output.with_parens(f_comma)
192
elif comparators[self.operator] and is_node_type(
193
self.left, AST_Binary) and comparators[self.left.operator]:
194
# A chained comparison such as a < b < c
195
if is_node_type(self.left.right, AST_Symbol):
196
# left side compares against a regular variable,
197
# no caching needed
198
self.left.print(output)
199
leftvar = self.left.right.name
200
else:
201
# some logic is being performed, let's cache it
202
self.left.left.print(output)
203
output.space()
204
output.print(self.left.operator)
205
output.space()
206
207
def f_cond_temp():
208
nonlocal leftvar
209
output.assign("ρσ_cond_temp")
210
self.left.right.print(output)
211
leftvar = "ρσ_cond_temp"
212
213
output.with_parens(f_cond_temp)
214
215
output.space()
216
output.print("&&")
217
output.space()
218
output.print(leftvar)
219
output.space()
220
output.print(self.operator)
221
output.space()
222
self.right.print(output)
223
elif self.operator is '**':
224
left = self.left
225
if is_node_type(self.left, AST_Unary) and not self.left.parenthesized:
226
left = self.left.expression
227
output.print(self.left.operator)
228
output.print("ρσ_operator_pow(")
229
left.print(output)
230
output.comma()
231
self.right.print(output)
232
output.print(')')
233
elif self.operator is '==' or self.operator is '!=':
234
write_smart_equality(self, output)
235
elif self.operator is 'instanceof':
236
write_instanceof(self.left, self.right, output)
237
elif self.operator is '*' and is_node_type(self.left, AST_String):
238
self.left.print(output), output.print('.repeat('), self.right.print(
239
output), output.print(')')
240
elif self.operator is '===' or self.operator is '!==':
241
nan_check = None
242
if is_node_type(self.right, AST_Symbol) and self.right.name is 'NaN':
243
nan_check = self.left
244
if is_node_type(self.left, AST_Symbol) and self.left.name is 'NaN':
245
nan_check = self.right
246
if nan_check is not None:
247
# We use the fact that NaN is the only object that is not equal to
248
# itself
249
output.spaced(nan_check,
250
'!==' if self.operator is '===' else '===',
251
nan_check)
252
else:
253
output.spaced(self.left, self.operator, self.right)
254
elif self.operator is '+':
255
output.print('ρσ_operator_add('), self.left.print(
256
output), output.comma(), self.right.print(output), output.print(
257
')')
258
elif self.operator is '-':
259
output.print('ρσ_operator_sub('), self.left.print(
260
output), output.comma(), self.right.print(output), output.print(
261
')')
262
elif self.operator is '*':
263
output.print('ρσ_operator_mul('), self.left.print(
264
output), output.comma(), self.right.print(output), output.print(
265
')')
266
elif self.operator is '/':
267
output.print('ρσ_operator_truediv('), self.left.print(
268
output), output.comma(), self.right.print(output), output.print(
269
')')
270
elif self.operator is '//':
271
output.print('ρσ_operator_floordiv('), self.left.print(
272
output), output.comma(), self.right.print(output), output.print(
273
')')
274
else:
275
output.spaced(self.left, self.operator, self.right)
276
277
278
after_map = {'.': 'd', '(': 'c', '[': 'd', 'g': 'g', 'null': 'n'}
279
280
281
def print_existential(self, output):
282
key = after_map[self.after] if self.after is None or jstype(
283
self.after) is 'string' else 'e'
284
if is_node_type(self.expression, AST_SymbolRef):
285
if key is 'n':
286
output.spaced('(typeof', self.expression, '!==', '"undefined"',
287
'&&', self.expression, '!==', 'null)')
288
return
289
if key is 'c':
290
output.spaced('(typeof', self.expression, '===', '"function"', '?',
291
self.expression, ':',
292
'(function(){return undefined;}))')
293
return
294
after = self.after
295
if key is 'd':
296
after = 'Object.create(null)'
297
elif key is 'g':
298
after = '{__getitem__:function(){return undefined;}}'
299
output.spaced('(typeof', self.expression, '!==', '"undefined"', '&&',
300
self.expression, '!==', 'null', '?', self.expression,
301
':', after)
302
output.print(')')
303
return
304
output.print('ρσ_exists.' + key + '(')
305
self.expression.print(output)
306
if key is 'e':
307
output.comma(), self.after.print(output)
308
output.print(')')
309
310
311
def print_assignment(self, output):
312
flattened = False
313
left = self.left
314
if is_node_type(left, AST_Seq):
315
left = AST_Array({'elements': [left.car, left.cdr]})
316
if is_node_type(left, AST_Array):
317
flat = left.flatten()
318
flattened = flat.length > left.elements.length
319
output.print("ρσ_unpack")
320
else:
321
left.print(output)
322
output.space()
323
output.print(self.operator)
324
output.space()
325
if flattened:
326
output.print('ρσ_flatten')
327
output.with_parens(lambda: self.right.print(output))
328
else:
329
self.right.print(output)
330
if is_node_type(left, AST_Array):
331
output.end_statement()
332
if not is_node_type(self.right, AST_Seq) and not is_node_type(
333
self.right, AST_Array):
334
output.assign('ρσ_unpack')
335
output.print('ρσ_unpack_asarray(' +
336
flat.length), output.comma(), output.print(
337
'ρσ_unpack)')
338
output.end_statement()
339
unpack_tuple(flat, output, True)
340
341
342
def print_assign(self, output):
343
if self.operator is '//=':
344
output.assign(self.left)
345
output.print('Math.floor')
346
347
def f_slash():
348
self.left.print(output)
349
output.space()
350
output.print('/')
351
output.space()
352
self.right.print(output)
353
354
output.with_parens(f_slash)
355
return
356
if self.operator is '+=':
357
output.assign(self.left)
358
output.print('ρσ_operator_iadd('), self.left.print(
359
output), output.comma(), self.right.print(output), output.print(
360
')')
361
return
362
if self.operator is '-=':
363
output.assign(self.left)
364
output.print('ρσ_operator_isub('), self.left.print(
365
output), output.comma(), self.right.print(output), output.print(
366
')')
367
return
368
if self.operator is '*=':
369
output.assign(self.left)
370
output.print('ρσ_operator_imul('), self.left.print(
371
output), output.comma(), self.right.print(output), output.print(
372
')')
373
return
374
if self.operator is '/=':
375
output.assign(self.left)
376
output.print('ρσ_operator_idiv('), self.left.print(
377
output), output.comma(), self.right.print(output), output.print(
378
')')
379
return
380
if self.operator is '=' and self.is_chained():
381
left_hand_sides, rhs = self.traverse_chain()
382
is_compound_assign = False
383
for lhs in left_hand_sides:
384
if is_node_type(lhs, AST_Seq) or is_node_type(lhs, AST_Array):
385
is_compound_assign = True
386
break
387
if is_compound_assign:
388
temp_rhs = AST_SymbolRef({'name': 'ρσ_chain_assign_temp'})
389
print_assignment(
390
AST_Assign({
391
'left': temp_rhs,
392
'operator': '=',
393
'right': rhs
394
}), output)
395
for lhs in left_hand_sides:
396
output.end_statement(), output.indent()
397
print_assignment(
398
AST_Assign({
399
'left': lhs,
400
'right': temp_rhs,
401
'operator': self.operator
402
}), output)
403
else:
404
for lhs in left_hand_sides:
405
output.spaced(lhs, '=', '')
406
rhs.print(output)
407
else:
408
print_assignment(self, output)
409
410
411
def print_conditional(self, output, condition, consequent, alternative):
412
condition, consequent, alternative = self.condition, self.consequent, self.alternative
413
output.with_parens(lambda: condition.print(output))
414
output.space()
415
output.print("?")
416
output.space()
417
consequent.print(output)
418
output.space()
419
output.colon()
420
alternative.print(output)
421
422
423
def print_seq(output):
424
self = this
425
p = output.parent()
426
427
def print_seq0():
428
self.car.print(output)
429
if self.cdr:
430
output.comma()
431
if output.should_break():
432
output.newline()
433
output.indent()
434
self.cdr.print(output)
435
436
# this will effectively convert tuples to arrays
437
if (is_node_type(p, AST_Binary) or is_node_type(p, AST_Return)
438
or is_node_type(p, AST_Array) or is_node_type(p, AST_BaseCall)
439
or is_node_type(p, AST_SimpleStatement)):
440
output.with_square(print_seq0)
441
else:
442
print_seq0()
443
444