Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/python-wasm
Path: blob/main/python/pylang/src/output/codegen.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
5
# globals:console,writefile
6
7
from utils import noop
8
from parse import PRECEDENCE
9
from ast_types import (
10
AST_Array, AST_Assign, AST_BaseCall, AST_Binary, AST_BlockStatement,
11
AST_Break, AST_Class, AST_Conditional, AST_Constant, AST_Continue,
12
AST_Debugger, AST_Definitions, AST_Directive, AST_Do, AST_Dot,
13
is_node_type, AST_EllipsesRange, AST_EmptyStatement, AST_Exit,
14
AST_ExpressiveObject, AST_ForIn, AST_ForJS, AST_Function, AST_Hole, AST_If,
15
AST_Imports, AST_Infinity, AST_Lambda, AST_ListComprehension,
16
AST_LoopControl, AST_NaN, AST_New, AST_Node, AST_Number, AST_Object,
17
AST_ObjectKeyVal, AST_ObjectProperty, AST_PropAccess, AST_RegExp,
18
AST_Return, AST_Set, AST_Seq, AST_SimpleStatement, AST_Splice,
19
AST_Statement, AST_StatementWithBody, AST_String, AST_Sub, AST_ItemAccess,
20
AST_Symbol, AST_This, AST_Throw, AST_Toplevel, AST_Try, AST_Unary,
21
AST_UnaryPrefix, AST_Undefined, AST_Var, AST_VarDef, AST_Assert,
22
AST_Verbatim, AST_While, AST_With, AST_Yield, TreeWalker, AST_Existential)
23
from output.exceptions import print_try
24
from output.classes import print_class
25
from output.literals import print_array, print_obj_literal, print_object, print_set, print_regexp
26
from output.loops import print_do_loop, print_while_loop, print_for_loop_body, print_for_in, print_list_comprehension, print_ellipses_range
27
from output.modules import print_top_level, print_imports
28
from output.comments import print_comments
29
from output.operators import (print_getattr, print_getitem, print_rich_getitem,
30
print_splice_assignment, print_unary_prefix,
31
print_binary_op, print_assign, print_conditional,
32
print_seq, print_existential)
33
from output.functions import print_function, print_function_call
34
from output.statements import print_bracketed, first_in_statement, force_statement, print_with, print_assert
35
from output.utils import make_block, make_num
36
37
38
# -----[ code generators ]-----
39
def generate_code():
40
# -----[ utils ]-----
41
def DEFPRINT(nodetype, generator):
42
nodetype.prototype._codegen = generator
43
44
def f_print_generate(stream, force_parens):
45
self = this
46
generator = self._codegen
47
stream.push_node(self)
48
if force_parens or self.needs_parens(stream):
49
stream.with_parens(f_comments_then_generator)
50
51
def f_comments_then_generator():
52
self.add_comments(stream)
53
generator(self, stream)
54
else:
55
self.add_comments(stream)
56
generator(self, stream)
57
58
stream.pop_node()
59
60
AST_Node.prototype.print = f_print_generate
61
62
# -----[ comments ]-----
63
def add_comments(output):
64
if not is_node_type(this, AST_Toplevel):
65
print_comments(this, output)
66
67
AST_Node.prototype.add_comments = add_comments
68
69
# -----[ PARENTHESES ]-----
70
def PARENS(nodetype, func):
71
nodetype.prototype.needs_parens = func
72
73
PARENS(AST_Node, lambda: False)
74
# a function expression needs parens around it when it's provably
75
# the first token to appear in a statement.
76
PARENS(AST_Function, first_in_statement)
77
# same goes for an object literal, because otherwise it would be
78
# interpreted as a block of code.
79
PARENS(AST_Object, first_in_statement)
80
81
def f_unary(output):
82
p = output.parent()
83
return is_node_type(p, AST_PropAccess) and p.expression is this
84
85
PARENS(AST_Unary, f_unary)
86
87
def f_seq(output):
88
p = output.parent()
89
return is_node_type(p, AST_Unary) or is_node_type(
90
p, AST_VarDef) or is_node_type(p, AST_Dot) or is_node_type(
91
p, AST_ObjectProperty) or is_node_type(p, AST_Conditional)
92
93
PARENS(AST_Seq, f_seq)
94
95
def f_binary(output):
96
p = output.parent()
97
# (foo && bar)()
98
if is_node_type(p, AST_BaseCall) and p.expression is this:
99
return True
100
101
# typeof (foo && bar)
102
if is_node_type(p, AST_Unary):
103
return True
104
105
# (foo && bar)["prop"], (foo && bar).prop
106
if is_node_type(p, AST_PropAccess) and p.expression is this:
107
return True
108
109
# this deals with precedence: 3 * (2 + 1)
110
if is_node_type(p, AST_Binary):
111
po = p.operator
112
pp = PRECEDENCE[po]
113
so = this.operator
114
sp = PRECEDENCE[so]
115
if pp > sp or pp is sp and this is p.right and not (
116
so is po and (so is "*" or so is "&&" or so is "||")):
117
return True
118
119
PARENS(AST_Binary, f_binary)
120
121
def f_prop_access(output):
122
p = output.parent()
123
if is_node_type(p, AST_New) and p.expression is this:
124
# i.e. new (foo.bar().baz)
125
#
126
# if there's one call into this subtree, then we need
127
# parens around it too, otherwise the call will be
128
# interpreted as passing the arguments to the upper New
129
# expression.
130
try:
131
132
def error_on_base_call(node):
133
if is_node_type(node, AST_BaseCall):
134
raise p
135
136
this.walk(TreeWalker(error_on_base_call))
137
except:
138
return True
139
140
PARENS(AST_PropAccess, f_prop_access)
141
142
def f_base_call(output):
143
p = output.parent()
144
return is_node_type(p, AST_New) and p.expression is this
145
146
PARENS(AST_BaseCall, f_base_call)
147
148
def f_new(output):
149
p = output.parent()
150
if this.args.length is 0 and (is_node_type(p, AST_PropAccess)
151
or is_node_type(p, AST_BaseCall)
152
and p.expression is this):
153
# (new foo)(bar)
154
return True
155
156
PARENS(AST_New, f_new)
157
158
def f_number(output):
159
p = output.parent()
160
if this.value < 0 and is_node_type(
161
p, AST_PropAccess) and p.expression is this:
162
return True
163
164
PARENS(AST_Number, f_number)
165
166
def f_nan(output):
167
p = output.parent()
168
if is_node_type(p, AST_PropAccess) and p.expression is this:
169
return True
170
171
PARENS(AST_NaN, f_nan)
172
173
def assign_and_conditional_paren_rules(output):
174
p = output.parent()
175
# !(a = false) → true
176
if is_node_type(p, AST_Unary):
177
return True
178
179
# 1 + (a = 2) + 3 → 6, side effect setting a = 2
180
if is_node_type(p, AST_Binary) and not (is_node_type(p, AST_Assign)):
181
return True
182
183
# (a = func)() —or— new (a = Object)()
184
if is_node_type(p, AST_BaseCall) and p.expression is this:
185
return True
186
187
# bar if a = foo else baz
188
if is_node_type(p, AST_Conditional) and p.condition is this:
189
return True
190
191
# (a = foo)["prop"] —or— (a = foo).prop
192
if is_node_type(p, AST_PropAccess) and p.expression is this:
193
return True
194
195
PARENS(AST_Assign, assign_and_conditional_paren_rules)
196
PARENS(AST_Conditional, assign_and_conditional_paren_rules)
197
198
# -----[ PRINTERS ]-----
199
def f_directive(self, output):
200
output.print_string(self.value)
201
output.semicolon()
202
203
DEFPRINT(AST_Directive, f_directive)
204
205
def f_debugger(self, output):
206
output.print("debugger")
207
output.semicolon()
208
209
DEFPRINT(AST_Debugger, f_debugger)
210
211
AST_StatementWithBody.prototype._do_print_body = lambda output: force_statement(
212
this.body, output)
213
214
def f_statement(self, output):
215
self.body.print(output)
216
output.semicolon()
217
218
DEFPRINT(AST_Statement, f_statement)
219
DEFPRINT(AST_Toplevel, print_top_level)
220
221
DEFPRINT(AST_Imports, print_imports)
222
223
def f_simple_statement(self, output):
224
if not (is_node_type(self.body, AST_EmptyStatement)):
225
self.body.print(output)
226
output.semicolon()
227
228
DEFPRINT(AST_SimpleStatement, f_simple_statement)
229
DEFPRINT(AST_BlockStatement,
230
lambda self, output: print_bracketed(self, output))
231
232
DEFPRINT(AST_EmptyStatement, lambda self, output: None)
233
234
DEFPRINT(AST_Do, print_do_loop)
235
236
DEFPRINT(AST_While, print_while_loop)
237
238
AST_ForIn.prototype._do_print_body = print_for_loop_body
239
240
DEFPRINT(AST_ForIn, print_for_in)
241
242
def f_do_print_body(output):
243
self = this
244
245
def f_print_stmt():
246
for stmt in self.body.body:
247
output.indent()
248
stmt.print(output)
249
output.newline()
250
251
output.with_block(f_print_stmt)
252
253
AST_ForJS.prototype._do_print_body = f_do_print_body
254
255
def f_for_js(self, output):
256
output.print("for")
257
output.space()
258
output.with_parens(lambda: self.condition.print(output))
259
output.space()
260
self._do_print_body(output)
261
262
DEFPRINT(AST_ForJS, f_for_js)
263
264
DEFPRINT(AST_ListComprehension, print_list_comprehension)
265
266
DEFPRINT(AST_EllipsesRange, print_ellipses_range)
267
268
DEFPRINT(AST_With, print_with)
269
270
DEFPRINT(AST_Assert, print_assert)
271
272
AST_Lambda.prototype._do_print = print_function
273
274
DEFPRINT(AST_Lambda, lambda self, output: self._do_print(output))
275
AST_Class.prototype._do_print = print_class
276
DEFPRINT(AST_Class, lambda self, output: self._do_print(output))
277
278
# -----[ exits ]-----
279
def f_do_print_exit(output, kind):
280
self = this
281
output.print(kind)
282
if self.value:
283
output.space()
284
self.value.print(output)
285
286
output.semicolon()
287
288
AST_Exit.prototype._do_print = f_do_print_exit
289
290
DEFPRINT(
291
AST_Yield, lambda self, output: self._do_print(
292
output, "yield" + ('*' if self.is_yield_from else '')))
293
DEFPRINT(AST_Return, lambda self, output: self._do_print(output, "return"))
294
DEFPRINT(AST_Throw, lambda self, output: self._do_print(output, "throw"))
295
296
# -----[ loop control ]-----
297
def f_do_print_loop(output, kind):
298
output.print(kind)
299
if this.label:
300
output.space()
301
this.label.print(output)
302
303
output.semicolon()
304
305
AST_LoopControl.prototype._do_print = f_do_print_loop
306
307
DEFPRINT(AST_Break, lambda self, output: self._do_print(output, "break"))
308
309
DEFPRINT(AST_Continue,
310
lambda self, output: self._do_print(output, "continue"))
311
312
# -----[ if ]-----
313
def make_then(self, output):
314
if output.options.bracketize:
315
make_block(self.body, output)
316
return
317
318
# The squeezer replaces "block"-s that contain only a single
319
# statement with the statement itself; technically, the AST
320
# is correct, but this can create problems when we output an
321
# IF having an ELSE clause where the THEN clause ends in an
322
# IF *without* an ELSE block (then the outer ELSE would refer
323
# to the inner IF). This function checks for this case and
324
# adds the block brackets if needed.
325
if not self.body:
326
return output.force_semicolon()
327
328
if is_node_type(self.body, AST_Do) and output.options.ie_proof:
329
# https://github.com/mishoo/RapydScript/issues/#issue/57 IE
330
# croaks with "syntax error" on code like this: if (foo)
331
# do ... while(cond); else ... we need block brackets
332
# around do/while
333
make_block(self.body, output)
334
return
335
336
b = self.body
337
while True:
338
if is_node_type(b, AST_If):
339
if not b.alternative:
340
make_block(self.body, output)
341
return
342
343
b = b.alternative
344
elif is_node_type(b, AST_StatementWithBody):
345
b = b.body
346
else:
347
break
348
349
force_statement(self.body, output)
350
351
def f_if(self, output):
352
output.print("if")
353
output.space()
354
output.with_parens(lambda: self.condition.print(output))
355
output.space()
356
if self.alternative:
357
make_then(self, output)
358
output.space()
359
output.print("else")
360
output.space()
361
force_statement(self.alternative, output)
362
else:
363
self._do_print_body(output)
364
365
DEFPRINT(AST_If, f_if)
366
367
# -----[ exceptions ]-----
368
DEFPRINT(AST_Try, print_try)
369
370
# -----[ var/const ]-----
371
def f_do_print_definition(output, kind):
372
output.print(kind)
373
output.space()
374
for i, def_ in enumerate(this.definitions):
375
if i:
376
output.comma()
377
def_.print(output)
378
p = output.parent()
379
in_for = is_node_type(p, AST_ForIn)
380
avoid_semicolon = in_for and p.init is this
381
if not avoid_semicolon:
382
output.semicolon()
383
384
AST_Definitions.prototype._do_print = f_do_print_definition
385
386
DEFPRINT(AST_Var, lambda self, output: self._do_print(output, "var"))
387
388
def parenthesize_for_noin(node, output, noin):
389
if not noin:
390
node.print(output)
391
else:
392
try:
393
# need to take some precautions here:
394
# https://github.com/mishoo/RapydScript2/issues/60
395
def f_for_noin(node):
396
if is_node_type(node,
397
AST_Binary) and node.operator is "in":
398
raise output
399
400
node.walk(TreeWalker(f_for_noin))
401
node.print(output)
402
except:
403
node.print(output, True)
404
405
def f_print_var_def(self, output):
406
self.name.print(output)
407
if self.value:
408
output.assign("")
409
# output.space()
410
# output.print("=")
411
# output.space()
412
p = output.parent(1)
413
noin = is_node_type(p, AST_ForIn)
414
parenthesize_for_noin(self.value, output, noin)
415
416
DEFPRINT(AST_VarDef, f_print_var_def)
417
418
# -----[ other expressions ]-----
419
DEFPRINT(AST_BaseCall, print_function_call)
420
421
AST_Seq.prototype._do_print = print_seq
422
423
DEFPRINT(AST_Seq, lambda self, output: self._do_print(output))
424
425
DEFPRINT(AST_Dot, print_getattr)
426
427
DEFPRINT(AST_Sub, print_getitem)
428
429
DEFPRINT(AST_ItemAccess, print_rich_getitem)
430
431
DEFPRINT(AST_Splice, print_splice_assignment)
432
433
DEFPRINT(AST_UnaryPrefix, print_unary_prefix)
434
435
DEFPRINT(AST_Binary, print_binary_op)
436
437
DEFPRINT(AST_Existential, print_existential)
438
439
DEFPRINT(AST_Assign, print_assign)
440
441
DEFPRINT(AST_Conditional, print_conditional)
442
443
# -----[ literals ]-----
444
DEFPRINT(AST_Array, print_array)
445
446
DEFPRINT(AST_ExpressiveObject, print_obj_literal)
447
448
DEFPRINT(AST_Object, print_object)
449
450
DEFPRINT(AST_ObjectKeyVal, f_print_obj_key_val)
451
452
def f_print_obj_key_val(self, output):
453
self.key.print(output)
454
output.colon()
455
self.value.print(output)
456
457
DEFPRINT(AST_Set, print_set)
458
459
AST_Symbol.prototype.definition = lambda: this.thedef
460
461
DEFPRINT(AST_Symbol, f_print_symbol)
462
463
def f_print_symbol(self, output):
464
def_ = self.definition()
465
output.print_name((
466
def_.mangled_name or def_.name) if def_ else self.name)
467
468
DEFPRINT(AST_Undefined, lambda self, output: output.print("void 0"))
469
DEFPRINT(AST_Hole, noop)
470
471
DEFPRINT(AST_Infinity, lambda self, output: output.print("1/0"))
472
DEFPRINT(AST_NaN, lambda self, output: output.print("0/0"))
473
DEFPRINT(AST_This, lambda self, output: output.print("this"))
474
DEFPRINT(AST_Constant, lambda self, output: output.print(self.value))
475
DEFPRINT(AST_String, lambda self, output: output.print_string(self.value))
476
DEFPRINT(AST_Verbatim, lambda self, output: output.print(self.value))
477
DEFPRINT(AST_Number,
478
lambda self, output: output.print(make_num(self.value)))
479
DEFPRINT(AST_RegExp, print_regexp)
480
481