Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/python-wasm
Path: blob/main/python/pylang/src/output/classes.py
1398 views
1
from __python__ import hash_literals
2
3
from ast_types import AST_Class, AST_Method, is_node_type
4
from output.functions import decorate, function_definition, function_annotation
5
from output.utils import create_doctring
6
from utils import has_prop
7
8
9
def print_class(output):
10
self = this
11
if self.external:
12
return
13
14
def class_def(method, is_var):
15
output.indent()
16
self.name.print(output)
17
if not is_var and method and has_prop(self.static, method):
18
output.assign("." + method)
19
else:
20
if is_var:
21
output.assign(".prototype[" + method + "]")
22
else:
23
output.assign(".prototype" +
24
(("." + method) if method else ""))
25
26
def define_method(stmt, is_property):
27
name = stmt.name.name
28
if not is_property:
29
class_def(name)
30
# only strip first argument if the method is static
31
is_static = has_prop(self.static, name)
32
strip_first = not is_static
33
34
# decorate the method
35
if stmt.decorators and stmt.decorators.length:
36
decorate(
37
stmt.decorators, output,
38
lambda: function_definition(stmt, output, strip_first, True))
39
output.end_statement()
40
else:
41
function_definition(stmt, output, strip_first)
42
if not is_property:
43
output.end_statement()
44
fname = self.name.name + ('.' if is_static else
45
'.prototype.') + name
46
function_annotation(stmt, output, strip_first, fname)
47
48
def define_default_method(name, body):
49
class_def(name)
50
output.spaced('function', name, '()', '')
51
output.with_block(lambda: [output.indent(), body()])
52
output.end_statement()
53
54
def add_hidden_property(name, proceed):
55
output.indent(), output.print('Object.defineProperty(')
56
self.name.print(
57
output), output.print('.prototype'), output.comma(), output.print(
58
JSON.stringify(name)), output.comma()
59
output.spaced(
60
'{value:',
61
''), proceed(), output.print('})'), output.end_statement()
62
63
# generate constructor
64
def write_constructor():
65
output.print("function")
66
output.space()
67
self.name.print(output)
68
output.print("()")
69
output.space()
70
71
def f_constructor():
72
output.indent()
73
output.spaced('if', '(this.ρσ_object_id', '===', 'undefined)',
74
'Object.defineProperty(this,', '"ρσ_object_id",',
75
'{"value":++ρσ_object_counter})')
76
output.end_statement()
77
if self.bound.length:
78
output.indent()
79
self.name.print(output), output.print(
80
".prototype.__bind_methods__.call(this)")
81
output.end_statement()
82
output.indent()
83
self.name.print(output)
84
output.print(".prototype.__init__.apply(this"), output.comma(
85
), output.print('arguments)')
86
output.end_statement()
87
88
output.with_block(f_constructor)
89
90
decorators = self.decorators or []
91
if decorators.length:
92
output.print('var ')
93
output.assign(self.name)
94
write_constructor()
95
output.semicolon()
96
else:
97
write_constructor()
98
output.newline()
99
if decorators.length:
100
output.indent()
101
self.name.print(output)
102
output.spaced('.ρσ_decorators', '=', '[')
103
num = decorators.length
104
for i in range(num):
105
decorators[i].expression.print(output)
106
output.spaced(',' if i < num - 1 else ']')
107
output.semicolon()
108
output.newline()
109
110
# inheritance
111
if self.parent:
112
output.indent()
113
output.print("ρσ_extends")
114
115
def f_extends():
116
self.name.print(output)
117
output.comma()
118
self.parent.print(output)
119
120
output.with_parens(f_extends)
121
output.end_statement()
122
123
# method binding
124
if self.bound.length:
125
seen_methods = Object.create(None)
126
127
def f_bind_methods():
128
output.spaced('function', '()', '')
129
130
def f_bases():
131
if self.bases.length:
132
for i in range(self.bases.length - 1, -1, -1):
133
base = self.bases[i]
134
output.indent(), base.print(output), output.spaced(
135
'.prototype.__bind_methods__', '&&', '')
136
base.print(output), output.print(
137
'.prototype.__bind_methods__.call(this)')
138
output.end_statement()
139
for bname in self.bound:
140
if seen_methods[bname] or self.dynamic_properties[bname]:
141
continue
142
seen_methods[bname] = True
143
output.indent(), output.assign('this.' + bname)
144
self.name.print(output), output.print('.prototype.' +
145
bname +
146
'.bind(this)')
147
output.end_statement()
148
149
output.with_block(f_bases)
150
151
add_hidden_property('__bind_methods__', f_bind_methods)
152
153
# dynamic properties
154
property_names = Object.keys(self.dynamic_properties)
155
if property_names.length:
156
output.indent()
157
output.print('Object.defineProperties')
158
159
def f_props():
160
self.name.print(output)
161
output.print('.prototype')
162
output.comma()
163
output.space()
164
165
def f_enum():
166
for name in property_names:
167
prop = self.dynamic_properties[name]
168
output.indent(), output.print(JSON.stringify(name) +
169
':'), output.space()
170
171
def f_enum2():
172
output.indent(), output.print(
173
'"enumerable":'), output.space(), output.print(
174
'true'), output.comma(), output.newline()
175
if prop.getter:
176
output.indent(), output.print(
177
'"get":'), output.space()
178
define_method(
179
prop.getter,
180
True), output.comma(), output.newline()
181
output.indent(), output.print('"set":'), output.space()
182
if prop.setter:
183
define_method(prop.setter, True), output.newline()
184
else:
185
output.spaced(
186
'function', '()', '{',
187
'''throw new AttributeError("can't set attribute")''',
188
'}'), output.newline()
189
190
output.with_block(f_enum2)
191
output.comma()
192
output.newline()
193
194
output.with_block(f_enum)
195
196
output.with_parens(f_props)
197
output.end_statement()
198
199
# actual methods
200
if not self.init:
201
# Create a default __init__ method
202
def f_default():
203
if self.parent:
204
self.parent.print(output)
205
output.spaced('.prototype.__init__', '&&')
206
output.space(), self.parent.print(output)
207
output.print(".prototype.__init__.apply")
208
209
def f_this_arguments():
210
output.print("this")
211
output.comma()
212
output.print("arguments")
213
214
output.with_parens(f_this_arguments)
215
output.end_statement()
216
217
define_default_method('__init__', f_default)
218
219
defined_methods = {}
220
221
for stmt in self.body:
222
if is_node_type(stmt, AST_Method):
223
if stmt.is_getter or stmt.is_setter:
224
continue
225
define_method(stmt)
226
defined_methods[stmt.name.name] = True
227
sname = stmt.name.name
228
if sname is '__init__':
229
# Copy argument handling data so that kwarg interpolation works when calling the constructor
230
for attr in [
231
'.__argnames__', '.__handles_kwarg_interpolation__'
232
]:
233
output.indent(), self.name.print(output), output.assign(
234
attr)
235
self.name.print(output), output.print(
236
'.prototype.__init__' + attr), output.end_statement()
237
if sname is '__iter__':
238
class_def('ρσ_iterator_symbol', True)
239
self.name.print(output)
240
output.print('.prototype.' + stmt.name.name)
241
output.end_statement()
242
243
elif is_node_type(stmt, AST_Class):
244
console.error('Nested classes aren\'t supported yet') # noqa:undef
245
246
if not defined_methods['__repr__']:
247
248
def f_repr():
249
if self.parent:
250
output.print('if('), self.parent.print(output), output.spaced(
251
'.prototype.__repr__)', 'return', self.parent)
252
output.print(
253
'.prototype.__repr__.call(this)'), output.end_statement()
254
output.indent(), output.spaced('return', '"<"', '+', '__name__',
255
'+', '"."', '+',
256
'this.constructor.name', '')
257
output.spaced('+', '" #"', '+', 'this.ρσ_object_id', '+', '">"')
258
output.end_statement()
259
260
define_default_method('__repr__', f_repr)
261
262
if not defined_methods['__str__']:
263
264
def f_str():
265
if self.parent:
266
output.print('if('), self.parent.print(output), output.spaced(
267
'.prototype.__str__)', 'return', self.parent)
268
output.print(
269
'.prototype.__str__.call(this)'), output.end_statement()
270
output.spaced('return', 'this.__repr__()')
271
output.end_statement()
272
273
define_default_method('__str__', f_str)
274
275
# Multiple inheritance
276
def f_basis():
277
output.print('[')
278
for i in range(len(self.bases)):
279
self.bases[i].print(output)
280
if i < self.bases.length - 1:
281
output.comma()
282
output.print(']')
283
284
add_hidden_property('__bases__', f_basis)
285
286
if self.bases.length > 1:
287
output.indent()
288
output.print("ρσ_mixin(")
289
self.name.print(output)
290
for i in range(1, len(self.bases)):
291
output.comma()
292
self.bases[i].print(output)
293
output.print(')'), output.end_statement()
294
295
# Docstring
296
if self.docstrings and self.docstrings.length and output.options.keep_docstrings:
297
298
def f_doc():
299
output.print(JSON.stringify(create_doctring(self.docstrings)))
300
301
add_hidden_property('__doc__', f_doc)
302
303
# Other statements in the class context
304
for stmt in self.statements:
305
if not is_node_type(stmt, AST_Method):
306
output.indent()
307
stmt.print(output)
308
output.newline()
309
310
if decorators.length:
311
output.indent()
312
output.assign(self.name)
313
for di in range(decorators.length):
314
self.name.print(output)
315
output.print(f'.ρσ_decorators[{di}](')
316
self.name.print(output)
317
output.print(')' * decorators.length)
318
output.semicolon()
319
output.newline()
320
output.indent()
321
output.spaced('delete ')
322
self.name.print(output)
323
output.print('.ρσ_decorators')
324
output.semicolon()
325
output.newline()
326
327