rapydscript-ns 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/.agignore +1 -0
  2. package/.gitattributes +4 -0
  3. package/.github/workflows/ci.yml +38 -0
  4. package/.github/workflows/web-repl-page-deploy.yml +42 -0
  5. package/=template.pyj +5 -0
  6. package/CHANGELOG.md +456 -0
  7. package/CONTRIBUTORS +13 -0
  8. package/HACKING.md +103 -0
  9. package/LICENSE +24 -0
  10. package/README.md +2512 -0
  11. package/TODO.md +327 -0
  12. package/add-toc-to-readme +2 -0
  13. package/bin/export +75 -0
  14. package/bin/rapydscript +70 -0
  15. package/bin/web-repl-export +102 -0
  16. package/build +3 -0
  17. package/package.json +46 -0
  18. package/publish.py +37 -0
  19. package/release/baselib-plain-pretty.js +4370 -0
  20. package/release/baselib-plain-ugly.js +3 -0
  21. package/release/compiler.js +18394 -0
  22. package/release/signatures.json +31 -0
  23. package/session.vim +4 -0
  24. package/setup.cfg +2 -0
  25. package/src/ast.pyj +1356 -0
  26. package/src/baselib-builtins.pyj +279 -0
  27. package/src/baselib-containers.pyj +723 -0
  28. package/src/baselib-errors.pyj +37 -0
  29. package/src/baselib-internal.pyj +421 -0
  30. package/src/baselib-itertools.pyj +97 -0
  31. package/src/baselib-str.pyj +798 -0
  32. package/src/compiler.pyj +36 -0
  33. package/src/errors.pyj +30 -0
  34. package/src/lib/aes.pyj +646 -0
  35. package/src/lib/collections.pyj +695 -0
  36. package/src/lib/elementmaker.pyj +83 -0
  37. package/src/lib/encodings.pyj +126 -0
  38. package/src/lib/functools.pyj +148 -0
  39. package/src/lib/gettext.pyj +569 -0
  40. package/src/lib/itertools.pyj +580 -0
  41. package/src/lib/math.pyj +193 -0
  42. package/src/lib/numpy.pyj +2101 -0
  43. package/src/lib/operator.pyj +11 -0
  44. package/src/lib/pythonize.pyj +20 -0
  45. package/src/lib/random.pyj +118 -0
  46. package/src/lib/re.pyj +470 -0
  47. package/src/lib/traceback.pyj +63 -0
  48. package/src/lib/uuid.pyj +77 -0
  49. package/src/monaco-language-service/analyzer.js +526 -0
  50. package/src/monaco-language-service/builtins.js +543 -0
  51. package/src/monaco-language-service/completions.js +498 -0
  52. package/src/monaco-language-service/diagnostics.js +643 -0
  53. package/src/monaco-language-service/dts.js +550 -0
  54. package/src/monaco-language-service/hover.js +121 -0
  55. package/src/monaco-language-service/index.js +386 -0
  56. package/src/monaco-language-service/scope.js +162 -0
  57. package/src/monaco-language-service/signature.js +144 -0
  58. package/src/output/__init__.pyj +0 -0
  59. package/src/output/classes.pyj +296 -0
  60. package/src/output/codegen.pyj +492 -0
  61. package/src/output/comments.pyj +45 -0
  62. package/src/output/exceptions.pyj +105 -0
  63. package/src/output/functions.pyj +491 -0
  64. package/src/output/literals.pyj +109 -0
  65. package/src/output/loops.pyj +444 -0
  66. package/src/output/modules.pyj +329 -0
  67. package/src/output/operators.pyj +429 -0
  68. package/src/output/statements.pyj +463 -0
  69. package/src/output/stream.pyj +309 -0
  70. package/src/output/treeshake.pyj +182 -0
  71. package/src/output/utils.pyj +72 -0
  72. package/src/parse.pyj +3106 -0
  73. package/src/string_interpolation.pyj +72 -0
  74. package/src/tokenizer.pyj +702 -0
  75. package/src/unicode_aliases.pyj +576 -0
  76. package/src/utils.pyj +192 -0
  77. package/test/_import_one.pyj +37 -0
  78. package/test/_import_two/__init__.pyj +11 -0
  79. package/test/_import_two/level2/__init__.pyj +0 -0
  80. package/test/_import_two/level2/deep.pyj +4 -0
  81. package/test/_import_two/other.pyj +6 -0
  82. package/test/_import_two/sub.pyj +13 -0
  83. package/test/aes_vectors.pyj +421 -0
  84. package/test/annotations.pyj +80 -0
  85. package/test/baselib.pyj +319 -0
  86. package/test/classes.pyj +452 -0
  87. package/test/collections.pyj +152 -0
  88. package/test/decorators.pyj +77 -0
  89. package/test/dict_spread.pyj +76 -0
  90. package/test/docstrings.pyj +39 -0
  91. package/test/elementmaker_test.pyj +45 -0
  92. package/test/ellipsis.pyj +49 -0
  93. package/test/functions.pyj +151 -0
  94. package/test/generators.pyj +41 -0
  95. package/test/generic.pyj +370 -0
  96. package/test/imports.pyj +72 -0
  97. package/test/internationalization.pyj +73 -0
  98. package/test/lint.pyj +164 -0
  99. package/test/loops.pyj +85 -0
  100. package/test/numpy.pyj +734 -0
  101. package/test/omit_function_metadata.pyj +20 -0
  102. package/test/regexp.pyj +55 -0
  103. package/test/repl.pyj +121 -0
  104. package/test/scoped_flags.pyj +76 -0
  105. package/test/starargs.pyj +506 -0
  106. package/test/starred_assign.pyj +104 -0
  107. package/test/str.pyj +198 -0
  108. package/test/subscript_tuple.pyj +53 -0
  109. package/test/unit/fixtures/fibonacci_expected.js +46 -0
  110. package/test/unit/index.js +2989 -0
  111. package/test/unit/language-service-builtins.js +815 -0
  112. package/test/unit/language-service-completions.js +1067 -0
  113. package/test/unit/language-service-dts.js +543 -0
  114. package/test/unit/language-service-hover.js +455 -0
  115. package/test/unit/language-service-scope.js +833 -0
  116. package/test/unit/language-service-signature.js +458 -0
  117. package/test/unit/language-service.js +705 -0
  118. package/test/unit/run-language-service.js +41 -0
  119. package/test/unit/web-repl.js +484 -0
  120. package/tools/build-language-service.js +190 -0
  121. package/tools/cli.js +547 -0
  122. package/tools/compile.js +219 -0
  123. package/tools/compiler.js +108 -0
  124. package/tools/completer.js +131 -0
  125. package/tools/embedded_compiler.js +251 -0
  126. package/tools/export.js +316 -0
  127. package/tools/gettext.js +185 -0
  128. package/tools/ini.js +65 -0
  129. package/tools/lint.js +705 -0
  130. package/tools/msgfmt.js +187 -0
  131. package/tools/repl.js +223 -0
  132. package/tools/self.js +162 -0
  133. package/tools/test.js +118 -0
  134. package/tools/utils.js +128 -0
  135. package/tools/web_repl.js +95 -0
  136. package/try +41 -0
  137. package/web-repl/env.js +74 -0
  138. package/web-repl/index.html +163 -0
  139. package/web-repl/language-service.js +4084 -0
  140. package/web-repl/main.js +254 -0
  141. package/web-repl/prism.css +139 -0
  142. package/web-repl/prism.js +113 -0
  143. package/web-repl/rapydscript.js +435 -0
  144. package/web-repl/sha1.js +25 -0
package/src/ast.pyj ADDED
@@ -0,0 +1,1356 @@
1
+ # vim:fileencoding=utf-8
2
+ # License: BSD Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
3
+ from __python__ import hash_literals
4
+
5
+ from utils import noop
6
+
7
+ def is_node_type(node, typ):
8
+ return v'node instanceof typ'
9
+
10
+ # Basic classes {{{
11
+
12
+ class AST:
13
+
14
+ properties = {}
15
+
16
+ def __init__(self, initializer):
17
+ # Walk the prototype change and copy all defined properties from the
18
+ # initializer object
19
+ if initializer:
20
+ obj = self
21
+ while True:
22
+ obj = Object.getPrototypeOf(obj)
23
+ if obj is None:
24
+ break
25
+ for v'var i in obj.properties': # noqa: unused-local
26
+ v'self[i] = initializer[i]'
27
+
28
+ def clone(self):
29
+ return v'new self.constructor(self)'
30
+
31
+
32
+ class AST_Token(AST):
33
+ ' Tokens generated by the tokenizer in the first stage of parsing '
34
+ properties = {
35
+ 'type': 'The type of the token',
36
+ 'value': 'The value of the token',
37
+ 'line': 'The line number at which the token occurs',
38
+ 'col': 'The column number at which the token occurs',
39
+ 'pos': '',
40
+ 'endpos': '',
41
+ 'nlb':'True iff there was a newline before this token',
42
+ 'comments_before':'True iff there were comments before this token',
43
+ 'file':'The filename in which this token occurs',
44
+ 'leading_whitespace': 'The leading whitespace for the line on which this token occurs',
45
+ }
46
+
47
+ class AST_Node(AST):
48
+ "Base class of all AST nodes"
49
+ properties = {
50
+ 'start': "[AST_Token] The first token of this node",
51
+ 'end': "[AST_Token] The last token of this node"
52
+ }
53
+
54
+ def _walk(self, visitor):
55
+ return visitor._visit(self)
56
+
57
+ def walk(self, visitor):
58
+ return self._walk(visitor)
59
+
60
+ def _dump(self, depth=100, omit={'start', 'end'}, offset=0, include_name=True):
61
+ p = console.log
62
+ reset = "\x1b[0m"
63
+ yellow = "\x1b[33m"
64
+ blue = "\x1b[34m"
65
+ green = "\x1b[32m"
66
+ red = "\x1b[31m"
67
+ magenta = "\x1b[35m"
68
+ pad = Array(offset + 1).join(' ')
69
+
70
+ if include_name:
71
+ p(pad + yellow + self.constructor.name.slice(4) + reset)
72
+ for key in self:
73
+ if key in omit:
74
+ continue
75
+
76
+ if Array.isArray(self[key]):
77
+ if self[key].length:
78
+ p(pad + ' ' + blue + key + ': ' + reset + '[')
79
+ if depth > 1:
80
+ for element in self[key]:
81
+ element._dump(depth-1, omit, offset+1, True)
82
+ else:
83
+ for element in self[key]:
84
+ p(pad + ' ' + yellow + element.constructor.name.slice(4) + reset)
85
+ p(pad + ' ]')
86
+ else:
87
+ p(pad + ' ' + blue + key + ': ' + reset + '[]')
88
+ elif self[key]:
89
+ if is_node_type(self[key], AST):
90
+ tname = self[key].constructor.name.slice(4)
91
+ if tname is 'Token':
92
+ p(pad + ' ' + blue + key + ': ' + magenta + tname + reset)
93
+ for property in self[key]:
94
+ p(pad + ' ' + blue + property + ': ' + reset + self[key][property])
95
+ else:
96
+ p(pad + ' ' + blue + key + ': ' + yellow + tname + reset)
97
+ if depth > 1:
98
+ self[key]._dump(depth-1, omit, offset+1, False)
99
+ elif jstype(self[key]) is "string":
100
+ p(pad + ' ' + blue + key + ': ' + green + '"' + self[key] + '"' + reset)
101
+ elif jstype(self[key]) is "number":
102
+ p(pad + ' ' + blue + key + ': ' + green + self[key] + reset)
103
+ else:
104
+ # unexpected object
105
+ p(pad + ' ' + blue + key + ': ' + red + self[key] + reset)
106
+ else:
107
+ # none/undefined
108
+ p(pad + ' ' + blue + key + ': ' + reset + self[key])
109
+
110
+ def dump(self, depth=2, omit={}):
111
+ ' a more user-friendly way to dump the AST tree than console.log'
112
+ return self._dump(depth, omit, 0, True)
113
+ # }}}
114
+
115
+ # Statements {{{
116
+
117
+ class AST_Statement(AST_Node):
118
+ "Base class of all statements"
119
+
120
+ class AST_Debugger(AST_Statement):
121
+ "Represents a debugger statement"
122
+
123
+ class AST_Directive(AST_Statement):
124
+ 'Represents a directive, like "use strict";'
125
+ properties = {
126
+ 'value': "[string] The value of this directive as a plain string (it's not an AST_String!)",
127
+ 'scope': "[AST_Scope/S] The scope that this directive affects"
128
+ }
129
+
130
+ class AST_SimpleStatement(AST_Statement):
131
+ "A statement consisting of an expression, i.e. a = 1 + 2"
132
+ properties = {
133
+ 'body': "[AST_Node] an expression node (should not be instanceof AST_Statement)"
134
+ }
135
+
136
+ def _walk(self, visitor):
137
+ return visitor._visit(self, def():
138
+ self.body._walk(visitor)
139
+ )
140
+
141
+ class AST_AnnotatedAssign(AST_Statement):
142
+ "An annotated variable assignment: `x: int = 1` or just `x: int`"
143
+ properties = {
144
+ 'target': "[AST_SymbolRef|AST_Dot] the variable being annotated",
145
+ 'annotation': "[AST_Node] the type annotation expression",
146
+ 'value': "[AST_Node?] the assigned value, or null if no assignment"
147
+ }
148
+
149
+ def _walk(self, visitor):
150
+ return visitor._visit(self, def():
151
+ self.target._walk(visitor)
152
+ self.annotation._walk(visitor)
153
+ if self.value:
154
+ self.value._walk(visitor)
155
+ )
156
+
157
+ class AST_Assert(AST_Statement):
158
+ "An assert statement, e.g. assert True, 'an error message'"
159
+ properties = {
160
+ 'condition': "[AST_Node] the expression that should be tested",
161
+ 'message': "[AST_Node*] the expression that is the error message or None",
162
+ }
163
+
164
+ def _walk(self, visitor):
165
+ return visitor._visit(self, def():
166
+ self.condition._walk(visitor)
167
+ if self.message:
168
+ self.message._walk(visitor)
169
+ )
170
+
171
+
172
+ def walk_body(node, visitor):
173
+ if is_node_type(node.body, AST_Statement):
174
+ node.body._walk(visitor)
175
+ elif node.body:
176
+ for stat in node.body:
177
+ stat._walk(visitor)
178
+
179
+ class AST_Block(AST_Statement):
180
+ "A body of statements (usually bracketed)"
181
+ properties = {
182
+ 'body': "[AST_Statement*] an array of statements"
183
+ }
184
+
185
+ def _walk(self, visitor):
186
+ return visitor._visit(self, def():
187
+ walk_body(self, visitor)
188
+ )
189
+
190
+ class AST_BlockStatement(AST_Block):
191
+ "A block statement"
192
+
193
+ class AST_EmptyStatement(AST_Statement):
194
+ "The empty statement (empty block or simply a semicolon)"
195
+ properties = {
196
+ 'stype': "[string] the type of empty statement. Is ; for semicolons",
197
+ }
198
+
199
+ def _walk(self, visitor):
200
+ return visitor._visit(self)
201
+
202
+ class AST_StatementWithBody(AST_Statement):
203
+ "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`"
204
+ properties = {
205
+ 'body': "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement"
206
+ }
207
+
208
+ def _walk(self, visitor):
209
+ return visitor._visit(self, def():
210
+ self.body._walk(visitor)
211
+ )
212
+
213
+ class AST_DWLoop(AST_StatementWithBody):
214
+ "Base class for do/while statements"
215
+ properties = {
216
+ 'condition': "[AST_Node] the loop condition. Should not be instanceof AST_Statement"
217
+ }
218
+
219
+ def _walk(self, visitor):
220
+ return visitor._visit(self, def():
221
+ self.condition._walk(visitor)
222
+ self.body._walk(visitor)
223
+ )
224
+
225
+ class AST_Do(AST_DWLoop):
226
+ "A `do` statement"
227
+
228
+ class AST_While(AST_DWLoop):
229
+ "A `while` statement"
230
+
231
+ class AST_ForIn(AST_StatementWithBody):
232
+ "A `for ... in` statement"
233
+ properties = {
234
+ 'init': "[AST_Node] the `for/in` initialization code",
235
+ 'name': "[AST_SymbolRef?] the loop variable, only if `init` is AST_Var",
236
+ 'object': "[AST_Node] the object that we're looping through"
237
+ }
238
+
239
+ def _walk(self, visitor):
240
+ return visitor._visit(self, def():
241
+ self.init._walk(visitor)
242
+ if (self.name) self.name._walk(visitor)
243
+ self.object._walk(visitor)
244
+ if self.body:
245
+ self.body._walk(visitor)
246
+ )
247
+
248
+ class AST_ForJS(AST_StatementWithBody):
249
+ "A `for ... in` statement"
250
+ properties = {
251
+ 'condition': "[AST_Verbatim] raw JavaScript conditional"
252
+ }
253
+
254
+ class AST_ListComprehension(AST_ForIn):
255
+ "A list comprehension expression"
256
+ properties = {
257
+ 'condition': "[AST_Node] the `if` condition for the first for-clause",
258
+ 'statement': "[AST_Node] statement to perform on each element before returning it",
259
+ 'clauses': "[Array] additional for-clauses for nested comprehensions"
260
+ }
261
+
262
+ def _walk(self, visitor):
263
+ return visitor._visit(self, def():
264
+ self.init._walk(visitor)
265
+ self.object._walk(visitor)
266
+ self.statement._walk(visitor)
267
+ if (self.condition) self.condition._walk(visitor)
268
+ if self.clauses:
269
+ for clause in self.clauses:
270
+ clause.init._walk(visitor)
271
+ clause.object._walk(visitor)
272
+ if clause.condition:
273
+ clause.condition._walk(visitor)
274
+ )
275
+
276
+ class AST_SetComprehension(AST_ListComprehension):
277
+ 'A set comprehension'
278
+
279
+ class AST_DictComprehension(AST_ListComprehension):
280
+ 'A dict comprehension'
281
+ properties = {
282
+ 'value_statement': "[AST_Node] statement to perform on each value before returning it",
283
+ 'is_pydict': "[bool] True if this comprehension is for a python dict",
284
+ 'is_jshash': "[bool] True if this comprehension is for a js hash",
285
+ }
286
+
287
+ def _walk(self, visitor):
288
+ return visitor._visit(self, def():
289
+ self.init._walk(visitor)
290
+ self.object._walk(visitor)
291
+ self.statement._walk(visitor)
292
+ self.value_statement._walk(visitor)
293
+ if (self.condition) self.condition._walk(visitor)
294
+ if self.clauses:
295
+ for clause in self.clauses:
296
+ clause.init._walk(visitor)
297
+ clause.object._walk(visitor)
298
+ if clause.condition:
299
+ clause.condition._walk(visitor)
300
+ )
301
+
302
+ class AST_GeneratorComprehension(AST_ListComprehension):
303
+ 'A generator comprehension'
304
+
305
+ class AST_With(AST_StatementWithBody):
306
+ "A `with` statement"
307
+ properties = {
308
+ 'clauses': "[AST_WithClause*] the `with` clauses (comma separated)"
309
+ }
310
+
311
+ def _walk(self, visitor):
312
+ return visitor._visit(self, def():
313
+ for exp in self.clauses:
314
+ exp._walk(visitor)
315
+ self.body._walk(visitor)
316
+ )
317
+
318
+ class AST_WithClause(AST_Node):
319
+ 'A clause in a with statement'
320
+ properties = {
321
+ 'expression': '[AST_Node] the expression',
322
+ 'alias': '[AST_SymbolAlias?] optional alias for this expression',
323
+ }
324
+
325
+ def _walk(self, visitor):
326
+ return visitor._visit(self, def():
327
+ self.expression._walk(visitor)
328
+ if self.alias:
329
+ self.alias._walk(visitor)
330
+ )
331
+
332
+ # Match/case statement {{{
333
+
334
+ class AST_MatchPattern(AST_Node):
335
+ "Base class for all match patterns"
336
+
337
+ class AST_MatchWildcard(AST_MatchPattern):
338
+ "Wildcard pattern: _"
339
+
340
+ class AST_MatchCapture(AST_MatchPattern):
341
+ "Capture pattern: a simple name that binds the matched value"
342
+ properties = {
343
+ 'name': "[string] the variable name to capture into"
344
+ }
345
+
346
+ class AST_MatchLiteral(AST_MatchPattern):
347
+ "Literal pattern: 42, 'hello', True, False, None, or a dotted value reference"
348
+ properties = {
349
+ 'value': "[AST_Node] the literal value (or dotted name) to match against"
350
+ }
351
+
352
+ def _walk(self, visitor):
353
+ return visitor._visit(self, def():
354
+ self.value._walk(visitor)
355
+ )
356
+
357
+ class AST_MatchOr(AST_MatchPattern):
358
+ "OR pattern: pat1 | pat2 | ..."
359
+ properties = {
360
+ 'patterns': "[AST_MatchPattern*] the alternative patterns"
361
+ }
362
+
363
+ def _walk(self, visitor):
364
+ return visitor._visit(self, def():
365
+ for p in self.patterns:
366
+ p._walk(visitor)
367
+ )
368
+
369
+ class AST_MatchAs(AST_MatchPattern):
370
+ "AS pattern: pattern as name (or bare catch-all when pattern is None)"
371
+ properties = {
372
+ 'pattern': "[AST_MatchPattern?] the inner pattern, or None for a bare catch-all",
373
+ 'name': "[string] the variable name to bind the matched value to"
374
+ }
375
+
376
+ def _walk(self, visitor):
377
+ return visitor._visit(self, def():
378
+ if self.pattern:
379
+ self.pattern._walk(visitor)
380
+ )
381
+
382
+ class AST_MatchStar(AST_MatchPattern):
383
+ "Star element inside a sequence pattern: *name or *_"
384
+ properties = {
385
+ 'name': "[string?] the capture name, or None for *_ (discard)"
386
+ }
387
+
388
+ class AST_MatchSequence(AST_MatchPattern):
389
+ "Sequence pattern: [a, b, *rest]"
390
+ properties = {
391
+ 'elements': "[AST_MatchPattern*] the element patterns (may include AST_MatchStar)"
392
+ }
393
+
394
+ def _walk(self, visitor):
395
+ return visitor._visit(self, def():
396
+ for e in self.elements:
397
+ e._walk(visitor)
398
+ )
399
+
400
+ class AST_MatchMapping(AST_MatchPattern):
401
+ "Mapping pattern: {'key': value, ...}"
402
+ properties = {
403
+ 'keys': "[AST_Node*] the key expressions (literals)",
404
+ 'values': "[AST_MatchPattern*] the corresponding value patterns",
405
+ 'rest_name': "[string?] capture name for remaining items (**rest), or None"
406
+ }
407
+
408
+ def _walk(self, visitor):
409
+ return visitor._visit(self, def():
410
+ for k in self.keys:
411
+ k._walk(visitor)
412
+ for v in self.values:
413
+ v._walk(visitor)
414
+ )
415
+
416
+ class AST_MatchClass(AST_MatchPattern):
417
+ "Class pattern: ClassName(pos_pat, kw=pat, ...)"
418
+ properties = {
419
+ 'cls': "[AST_Node] the class reference expression",
420
+ 'positional': "[AST_MatchPattern*] positional argument patterns",
421
+ 'keys': "[string*] keyword argument names",
422
+ 'values': "[AST_MatchPattern*] keyword argument value patterns"
423
+ }
424
+
425
+ def _walk(self, visitor):
426
+ return visitor._visit(self, def():
427
+ self.cls._walk(visitor)
428
+ for p in self.positional:
429
+ p._walk(visitor)
430
+ for v in self.values:
431
+ v._walk(visitor)
432
+ )
433
+
434
+ class AST_MatchCase(AST_Node):
435
+ "A single case clause inside a match statement"
436
+ properties = {
437
+ 'pattern': "[AST_MatchPattern] the pattern to match",
438
+ 'guard': "[AST_Node?] optional guard expression (after 'if')",
439
+ 'body': "[AST_Statement] the body to execute when the pattern matches"
440
+ }
441
+
442
+ def _walk(self, visitor):
443
+ return visitor._visit(self, def():
444
+ self.pattern._walk(visitor)
445
+ if self.guard:
446
+ self.guard._walk(visitor)
447
+ self.body._walk(visitor)
448
+ )
449
+
450
+ class AST_Match(AST_Statement):
451
+ "A match/case statement"
452
+ properties = {
453
+ 'subject': "[AST_Node] the expression being matched",
454
+ 'cases': "[AST_MatchCase*] the case clauses"
455
+ }
456
+
457
+ def _walk(self, visitor):
458
+ return visitor._visit(self, def():
459
+ self.subject._walk(visitor)
460
+ for c in self.cases:
461
+ c._walk(visitor)
462
+ )
463
+
464
+ # }}}
465
+
466
+ # Scope and functions {{{
467
+
468
+ class AST_Scope(AST_Block):
469
+ "Base class for all statements introducing a lexical scope"
470
+ properties = {
471
+ 'localvars': "[SymbolDef*] list of variables local to this scope",
472
+ 'docstrings': "[AST_String*] list of docstrings for this scope",
473
+ }
474
+
475
+
476
+ class AST_Toplevel(AST_Scope):
477
+ "The toplevel scope"
478
+ properties = {
479
+ 'globals': "[Object/S] a map of name -> SymbolDef for all undeclared names",
480
+ 'baselib': "[Object/s] a collection of used parts of baselib",
481
+ 'imports': "[Object/S] a map of module_id->AST_Toplevel for all imported modules (this represents all imported modules across all source files)",
482
+ 'imported_module_ids': "[string*] a list of module ids that were imported by this module, specifically",
483
+ 'nonlocalvars': "[String*] a list of all non-local variable names (names that come from the global scope)",
484
+ 'shebang': "[string] If #! line is present, it will be stored here",
485
+ 'import_order': "[number] The global order in which this scope was imported",
486
+ 'module_id': "[string] The id of this module",
487
+ 'exports': "[SymbolDef*] list of names exported from this module",
488
+ 'classes': "[Object/S] a map of class names to AST_Class for classes defined in this module",
489
+ 'filename': "[string] The absolute path to the file from which this module was read",
490
+ 'srchash': "[string] SHA1 hash of source code, used for caching",
491
+ 'comments_after': '[array] True iff there were comments before this token',
492
+ }
493
+
494
+ class AST_Import(AST_Statement):
495
+ "Container for a single import"
496
+
497
+ properties = {
498
+ 'module': "[AST_SymbolVar] name of the module we're importing",
499
+ 'key': "[string] The key by which this module is stored in the global modules mapping",
500
+ 'alias': "[AST_SymbolAlias] The name this module is imported as, can be None. For import x as y statements.",
501
+ 'argnames': "[AST_ImportedVar*] names of objects to be imported",
502
+ 'body': "[AST_TopLevel] parsed contents of the imported file",
503
+ }
504
+
505
+ def _walk(self, visitor):
506
+ return visitor._visit(self, def():
507
+ if self.alias:
508
+ self.alias._walk(visitor)
509
+ if self.argnames:
510
+ for arg in self.argnames:
511
+ arg._walk(visitor)
512
+ )
513
+
514
+ class AST_Imports(AST_Statement):
515
+ "Container for a single import"
516
+ properties = {
517
+ 'imports': "[AST_Import+] array of imports",
518
+ }
519
+
520
+ def _walk(self, visitor):
521
+ return visitor._visit(self, def():
522
+ for imp in self.imports:
523
+ imp._walk(visitor)
524
+ )
525
+
526
+ class AST_Decorator(AST_Node):
527
+ "Class for function decorators"
528
+ properties = {
529
+ 'expression': "[AST_Node] the decorator expression"
530
+ }
531
+
532
+ def _walk(self, visitor):
533
+ return visitor._visit(self, def():
534
+ if self.expression:
535
+ self.expression.walk(visitor)
536
+ )
537
+
538
+ class AST_Lambda(AST_Scope):
539
+ "Base class for functions"
540
+ properties = {
541
+ 'name': "[AST_SymbolDeclaration?] the name of this function",
542
+ 'argnames': "[AST_SymbolFunarg*] array of function arguments",
543
+ 'decorators': "[AST_Decorator*] function decorators, if any",
544
+ 'is_generator': "[bool*] True iff this function is a generator",
545
+ 'is_async': "[bool*] True iff this function is an async function",
546
+ 'is_expression': "[bool*] True iff this function is a function expression",
547
+ 'is_anonymous': "[bool*] True iff this function is an anonymous function",
548
+ "return_annotation": "[AST_Node?] The return type annotation provided (if any)",
549
+ }
550
+
551
+ def _walk(self, visitor):
552
+ return visitor._visit(self, def():
553
+ if self.decorators:
554
+ for d in self.decorators:
555
+ d.walk(visitor)
556
+ if self.name:
557
+ self.name._walk(visitor)
558
+
559
+ for arg in self.argnames:
560
+ arg._walk(visitor)
561
+ if self.argnames.starargs:
562
+ self.argnames.starargs._walk(visitor)
563
+ if self.argnames.kwargs:
564
+ self.argnames.kwargs._walk(visitor)
565
+ walk_body(self, visitor)
566
+ )
567
+
568
+ class AST_Function(AST_Lambda):
569
+ "A function expression"
570
+
571
+ class AST_Class(AST_Scope):
572
+ "A class declaration"
573
+ properties = {
574
+ 'name': "[AST_SymbolDeclaration?] the name of this class",
575
+ 'init': "[AST_Function] constructor for the class",
576
+ 'parent': "[AST_Symbol?] parent class this class inherits from",
577
+ 'bases': "[AST_Symbol*] list of base classes this class inherits from",
578
+ "static": "[dict] A hash whose keys are names of static methods for this class",
579
+ 'classmethod': "[dict] A hash whose keys are names of classmethods for this class",
580
+ 'external': "[boolean] true if class is declared elsewhere, but will be within current scope at runtime",
581
+ 'bound': "[string*] list of methods that need to be bound to self",
582
+ 'decorators': "[AST_Decorator*] function decorators, if any",
583
+ 'module_id': "[string] The id of the module this class is defined in",
584
+ 'statements': "[AST_Node*] list of statements in the class scope (excluding method definitions)",
585
+ 'dynamic_properties': '[dict] map of dynamic property names to property descriptors of the form {getter:AST_Method, setter:AST_Method',
586
+ 'classvars': '[dict] map containing all class variables as keys, to be used to easily test for existence of a class variable',
587
+ }
588
+
589
+ def _walk(self, visitor):
590
+ return visitor._visit(self, def():
591
+ if self.decorators:
592
+ for d in self.decorators:
593
+ d.walk(visitor)
594
+ self.name._walk(visitor)
595
+ walk_body(self, visitor)
596
+ if (self.parent) self.parent._walk(visitor)
597
+ )
598
+
599
+ class AST_Method(AST_Lambda):
600
+ "A class method definition"
601
+ properties = {
602
+ "static": "[boolean] true if method is static",
603
+ "is_classmethod": "[boolean] true if method is a classmethod",
604
+ "is_getter": "[boolean] true if method is a property getter",
605
+ "is_setter": "[boolean] true if method is a property setter",
606
+ }
607
+
608
+ # }}}
609
+
610
+ # Jumps(break/continue/etc) {{{
611
+
612
+ class AST_Jump(AST_Statement):
613
+ "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)"
614
+
615
+ class AST_Exit(AST_Jump):
616
+ "Base class for “exits” (`return` and `throw`)"
617
+ properties = {
618
+ 'value': "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return"
619
+ }
620
+
621
+ def _walk(self, visitor):
622
+ return visitor._visit(self, def():
623
+ if self.value:
624
+ self.value._walk(visitor)
625
+ )
626
+
627
+ class AST_Return(AST_Exit):
628
+ "A `return` statement"
629
+
630
+ class AST_Yield(AST_Return):
631
+ "A `yield` statement"
632
+ properties = {
633
+ 'is_yield_from': "[bool] True iff this is a yield from, False otherwise"
634
+ }
635
+
636
+ class AST_Await(AST_Node):
637
+ "An `await` expression"
638
+ properties = {
639
+ 'value': "[AST_Node] the expression being awaited"
640
+ }
641
+
642
+ def _walk(self, visitor):
643
+ return visitor._visit(self, def():
644
+ if self.value:
645
+ self.value._walk(visitor)
646
+ )
647
+
648
+ class AST_Throw(AST_Exit):
649
+ "A `throw` statement"
650
+
651
+ class AST_LoopControl(AST_Jump):
652
+ "Base class for loop control statements (`break` and `continue`)"
653
+
654
+ class AST_Break(AST_LoopControl):
655
+ "A `break` statement"
656
+
657
+ class AST_Continue(AST_LoopControl):
658
+ "A `continue` statement"
659
+ # }}}
660
+
661
+ # If {{{
662
+ class AST_If(AST_StatementWithBody):
663
+ "A `if` statement"
664
+ properties = {
665
+ 'condition': "[AST_Node] the `if` condition",
666
+ 'alternative': "[AST_Statement?] the `else` part, or null if not present"
667
+ }
668
+
669
+ def _walk(self, visitor):
670
+ return visitor._visit(self, def():
671
+ self.condition._walk(visitor)
672
+ self.body._walk(visitor)
673
+ if self.alternative:
674
+ self.alternative._walk(visitor)
675
+ )
676
+ # }}}
677
+
678
+ # EXCEPTIONS {{{
679
+
680
+ class AST_Try(AST_Block):
681
+ "A `try` statement"
682
+ properties = {
683
+ 'bcatch': "[AST_Catch?] the catch block, or null if not present",
684
+ 'bfinally': "[AST_Finally?] the finally block, or null if not present",
685
+ 'belse': '[AST_Else?] the else block for null if not present',
686
+ }
687
+
688
+ def _walk(self, visitor):
689
+ return visitor._visit(self, def():
690
+ walk_body(self, visitor)
691
+ if self.bcatch:
692
+ self.bcatch._walk(visitor)
693
+
694
+ if self.belse:
695
+ self.belse._walk(visitor)
696
+
697
+ if self.bfinally:
698
+ self.bfinally._walk(visitor)
699
+ )
700
+
701
+ class AST_Catch(AST_Block):
702
+ "A `catch` node; only makes sense as part of a `try` statement"
703
+
704
+ class AST_Except(AST_Block):
705
+ "An `except` node for RapydScript, which resides inside the catch block"
706
+ properties = {
707
+ 'argname': "[AST_SymbolCatch] symbol for the exception",
708
+ 'errors': "[AST_SymbolVar*] error classes to catch in this block"
709
+ }
710
+
711
+ def _walk(self, visitor):
712
+ return visitor._visit(this, def():
713
+ if (self.argname):
714
+ self.argname.walk(visitor)
715
+ if (self.errors):
716
+ for e in self.errors: e.walk(visitor)
717
+ walk_body(self, visitor)
718
+ )
719
+
720
+ class AST_Finally(AST_Block):
721
+ "A `finally` node; only makes sense as part of a `try` statement"
722
+
723
+ class AST_Else(AST_Block):
724
+ 'An `else` node; only makes sense as part of `try` statement'
725
+
726
+ # }}}
727
+
728
+ # VAR/CONST {{{
729
+ class AST_Definitions(AST_Statement):
730
+ "Base class for `var` or `const` nodes (variable declarations/initializations)"
731
+ properties = {
732
+ 'definitions': "[AST_VarDef*] array of variable definitions"
733
+ }
734
+
735
+ def _walk(self, visitor):
736
+ return visitor._visit(self, def():
737
+ for def_ in self.definitions:
738
+ def_._walk(visitor)
739
+ )
740
+
741
+ class AST_Var(AST_Definitions):
742
+ "A `var` statement"
743
+
744
+ class AST_VarDef(AST_Node):
745
+ "A variable declaration; only appears in a AST_Definitions node"
746
+ properties = {
747
+ 'name': "[AST_SymbolVar|AST_SymbolNonlocal] name of the variable",
748
+ 'value': "[AST_Node?] initializer, or null if there's no initializer"
749
+ }
750
+
751
+ def _walk(self, visitor):
752
+ return visitor._visit(self, def():
753
+ self.name._walk(visitor)
754
+ if self.value:
755
+ self.value._walk(visitor)
756
+ )
757
+ # }}}
758
+
759
+ # Miscellaneous {{{
760
+
761
+ class AST_BaseCall(AST_Node):
762
+ "A base class for function calls"
763
+ properties = {
764
+ 'args': "[AST_Node*] array of arguments"
765
+ }
766
+
767
+ class AST_Call(AST_BaseCall):
768
+ "A function call expression"
769
+ properties = {
770
+ 'expression': "[AST_Node] expression to invoke as function"
771
+ }
772
+
773
+ def _walk(self, visitor):
774
+ return visitor._visit(self, def():
775
+ self.expression._walk(visitor)
776
+ for arg in self.args:
777
+ arg._walk(visitor)
778
+ if self.args.kwargs:
779
+ for arg in self.args.kwargs:
780
+ arg[0]._walk(visitor)
781
+ arg[1]._walk(visitor)
782
+ if self.args.kwarg_items:
783
+ for arg in self.args.kwarg_items:
784
+ arg._walk(visitor)
785
+ )
786
+
787
+
788
+ class AST_ClassCall(AST_BaseCall):
789
+ "A function call expression"
790
+ properties = {
791
+ "class": "[string] name of the class method belongs to",
792
+ 'method': "[string] class method being called",
793
+ "static": "[boolean] defines whether the method is static"
794
+ }
795
+
796
+ def _walk(self, visitor):
797
+ return visitor._visit(self, def():
798
+ if (self.expression) self.expression._walk(visitor)
799
+ for arg in self.args:
800
+ arg._walk(visitor)
801
+ for arg in self.args.kwargs:
802
+ arg[0]._walk(visitor)
803
+ arg[1]._walk(visitor)
804
+ for arg in self.args.kwarg_items:
805
+ arg._walk(visitor)
806
+ )
807
+
808
+ class AST_Super(AST_Node):
809
+ "Represents a resolved super() proxy, carrying the parent class expression"
810
+ properties = {
811
+ 'parent': "[AST_Node] the parent class expression",
812
+ 'class_name': "[string] name of the class where super() appears",
813
+ }
814
+
815
+ def _walk(self, visitor):
816
+ return visitor._visit(self, def():
817
+ if self.parent:
818
+ self.parent._walk(visitor)
819
+ )
820
+
821
+ class AST_New(AST_Call):
822
+ "An object instantiation. Derives from a function call since it has exactly the same properties"
823
+
824
+ class AST_Seq(AST_Node):
825
+ "A sequence expression (two comma-separated expressions)"
826
+ properties = {
827
+ 'car': "[AST_Node] first element in sequence",
828
+ 'cdr': "[AST_Node] second element in sequence"
829
+ }
830
+
831
+ def to_array(self):
832
+ p = self
833
+ a = []
834
+ while p:
835
+ a.push(p.car)
836
+ if p.cdr and not (is_node_type(p.cdr, AST_Seq)):
837
+ a.push(p.cdr)
838
+ break
839
+ p = p.cdr
840
+ return a
841
+
842
+ def add(self, node):
843
+ p = self
844
+ while p:
845
+ if not (is_node_type(p.cdr, AST_Seq)):
846
+ cell = AST_Seq.cons(p.cdr, node)
847
+ return p.cdr = cell
848
+ p = p.cdr
849
+
850
+ def _walk(self, visitor):
851
+ return visitor._visit(self, def():
852
+ self.car._walk(visitor)
853
+ if self.cdr:
854
+ self.cdr._walk(visitor)
855
+ )
856
+
857
+ def cons(self, x, y):
858
+ # Should be called as a classmethod: AST_Seq.cons()
859
+ seq = new AST_Seq(x)
860
+ seq.car = x
861
+ seq.cdr = y
862
+ return seq
863
+
864
+ def from_array(self, array):
865
+ # Should be called as a classmethod: AST_Seq.from_array()
866
+ if array.length is 0:
867
+ return None
868
+
869
+ if array.length is 1:
870
+ return array[0].clone()
871
+
872
+ ans = None
873
+ for i in range(array.length-1, -1, -1):
874
+ ans = AST_Seq.cons(array[i], ans)
875
+
876
+ p = ans
877
+ while p:
878
+ if p.cdr and not p.cdr.cdr:
879
+ p.cdr = p.cdr.car
880
+ break
881
+ p = p.cdr
882
+ return ans
883
+
884
+ class AST_PropAccess(AST_Node):
885
+ 'Base class for property access expressions, i.e. `a.foo` or `a["foo"]`'
886
+ properties = {
887
+ 'expression': "[AST_Node] the “container” expression",
888
+ 'property': "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node",
889
+ }
890
+
891
+ class AST_Dot(AST_PropAccess):
892
+ "A dotted property access expression"
893
+
894
+ def _walk(self, visitor):
895
+ return visitor._visit(self, def():
896
+ self.expression._walk(visitor)
897
+ )
898
+
899
+ class AST_Sub(AST_PropAccess):
900
+ 'Index-style property access, i.e. `a["foo"]`'
901
+
902
+ def _walk(self, visitor):
903
+ return visitor._visit(self, def():
904
+ self.expression._walk(visitor)
905
+ self.property._walk(visitor)
906
+ )
907
+
908
+ class AST_ItemAccess(AST_PropAccess):
909
+ 'Python index-style property access, i.e. `a.__getitem__("foo")`'
910
+ properties = {
911
+ 'assignment': "[AST_Node or None] Not None if this is an assignment (a[x] = y) rather than a simple access",
912
+ 'assign_operator': "[String] The operator for a assignment like += or empty string if plain assignment",
913
+ }
914
+
915
+ def _walk(self, visitor):
916
+ return visitor._visit(self, def():
917
+ self.expression._walk(visitor)
918
+ self.property._walk(visitor)
919
+ if self.assignment:
920
+ self.assignment._walk(visitor)
921
+ )
922
+
923
+ class AST_Splice(AST_PropAccess):
924
+ 'Index-style property access, i.e. `a[3:5]`'
925
+ properties = {
926
+ 'property2': "[AST_Node] the 2nd property to access - typically ending index for the array.",
927
+ 'assignment': "[AST_Node] The data being spliced in."
928
+ }
929
+
930
+ def _walk(self, visitor):
931
+ return visitor._visit(self, def():
932
+ self.expression._walk(visitor)
933
+ self.property._walk(visitor)
934
+ if self.property2:
935
+ self.property2._walk(visitor)
936
+ )
937
+
938
+ class AST_Unary(AST_Node):
939
+ "Base class for unary expressions"
940
+ properties = {
941
+ 'operator': "[string] the operator",
942
+ 'expression': "[AST_Node] expression that this unary operator applies to",
943
+ 'parenthesized': "[bool] Whether this unary expression was parenthesized",
944
+ 'overloaded': "[bool] Whether to use Python-style operator overloading dispatch"
945
+ }
946
+
947
+ def _walk(self, visitor):
948
+ return visitor._visit(self, def():
949
+ self.expression._walk(visitor)
950
+ )
951
+
952
+ class AST_UnaryPrefix(AST_Unary):
953
+ "Unary prefix expression, i.e. `typeof i` or `del i`"
954
+
955
+ class AST_Binary(AST_Node):
956
+ "Binary expression, i.e. `a + b`"
957
+ properties = {
958
+ 'left': "[AST_Node] left-hand side expression",
959
+ 'operator': "[string] the operator",
960
+ 'right': "[AST_Node] right-hand side expression",
961
+ 'overloaded': "[bool] Whether to use Python-style operator overloading dispatch"
962
+ }
963
+
964
+ def _walk(self, visitor):
965
+ return visitor._visit(self, def():
966
+ self.left._walk(visitor)
967
+ self.right._walk(visitor)
968
+ )
969
+
970
+ class AST_Existential(AST_Node):
971
+ "Existential operator a?"
972
+ properties = {
973
+ 'expression': "[AST_Node] The expression whose existence we need to check",
974
+ 'after': "[None|string|AST_Node] is None when there is nothing following this operator, is a string when there is as AST_PropAccess following this operator, is an AST_Node if it is used a a shorthand for the conditional ternary, i.e. a ? b == a if a? else b",
975
+ }
976
+
977
+ def _walk(self, visitor):
978
+ return visitor._visit(self, def():
979
+ self.expression._walk(visitor)
980
+ if self.after is not None and jstype(self.after) is 'object':
981
+ self.after._walk(visitor)
982
+ )
983
+
984
+ class AST_Conditional(AST_Node):
985
+ "Conditional expression using the ternary operator, i.e. `a if b else c`"
986
+ properties = {
987
+ 'condition': "[AST_Node]",
988
+ 'consequent': "[AST_Node]",
989
+ 'alternative': "[AST_Node]",
990
+ }
991
+
992
+ def _walk(self, visitor):
993
+ return visitor._visit(self, def():
994
+ self.condition._walk(visitor)
995
+ self.consequent._walk(visitor)
996
+ self.alternative._walk(visitor)
997
+ )
998
+
999
+ class AST_Assign(AST_Binary):
1000
+ "An assignment expression — `a = b + 5`"
1001
+
1002
+ def is_chained(self):
1003
+ return is_node_type(self.right, AST_Assign) or (
1004
+ is_node_type(self.right, AST_Seq) and (
1005
+ is_node_type(self.right.car, AST_Assign) or is_node_type(self.right.cdr, AST_Assign))
1006
+ )
1007
+
1008
+ def traverse_chain(self):
1009
+ right = self.right
1010
+ while True:
1011
+ if is_node_type(right, AST_Assign):
1012
+ right = right.right
1013
+ continue
1014
+ if is_node_type(right, AST_Seq):
1015
+ if is_node_type(right.car, AST_Assign):
1016
+ right = new AST_Seq({'car':right.car.right, 'cdr': right.cdr})
1017
+ continue
1018
+ if is_node_type(right.cdr, AST_Assign):
1019
+ right = right.cdr.right
1020
+ continue
1021
+ break
1022
+ left_hand_sides = v'[self.left]'
1023
+ next = self.right
1024
+ while True:
1025
+ if is_node_type(next, AST_Assign):
1026
+ left_hand_sides.push(next.left)
1027
+ next = next.right
1028
+ continue
1029
+ if is_node_type(next, AST_Seq):
1030
+ if is_node_type(next.cdr, AST_Assign):
1031
+ assign = next.cdr
1032
+ left_hand_sides.push(new AST_Seq({'car':next.car, 'cdr':assign.left}))
1033
+ next = assign.right
1034
+ continue
1035
+ break
1036
+ return left_hand_sides, right
1037
+
1038
+
1039
+ class AST_NamedExpr(AST_Node):
1040
+ "Walrus operator (named expression): `name := value`"
1041
+ properties = {
1042
+ 'name': "[AST_SymbolRef] the symbol being assigned to",
1043
+ 'value': "[AST_Node] the value expression",
1044
+ }
1045
+
1046
+ def _walk(self, visitor):
1047
+ return visitor._visit(self, def():
1048
+ self.name._walk(visitor)
1049
+ self.value._walk(visitor)
1050
+ )
1051
+
1052
+
1053
+ class AST_Starred(AST_Node):
1054
+ "A starred assignment target: `*name` in `a, *name, b = iterable`"
1055
+ properties = {
1056
+ 'expression': "[AST_SymbolRef] the symbol being collected into",
1057
+ }
1058
+
1059
+ def _walk(self, visitor):
1060
+ return visitor._visit(self, def():
1061
+ self.expression._walk(visitor)
1062
+ )
1063
+
1064
+ # }}}
1065
+
1066
+ # LITERALS {{{
1067
+
1068
+ class AST_Array(AST_Node):
1069
+ "An array literal"
1070
+ properties = {
1071
+ 'elements': "[AST_Node*] array of elements"
1072
+ }
1073
+
1074
+ def _walk(self, visitor):
1075
+ return visitor._visit(self, def():
1076
+ for el in self.elements:
1077
+ el._walk(visitor)
1078
+ )
1079
+
1080
+ def flatten(self):
1081
+ def flatten(arr):
1082
+ ans = []
1083
+ for value in arr:
1084
+ if is_node_type(value, AST_Seq):
1085
+ value = value.to_array()
1086
+ elif is_node_type(value, AST_Array):
1087
+ value = value.elements
1088
+ if Array.isArray(value):
1089
+ ans = ans.concat(flatten(value))
1090
+ else:
1091
+ ans.push(value)
1092
+ return ans
1093
+ return flatten(self.elements)
1094
+
1095
+ class AST_Object(AST_Node):
1096
+ "An object literal"
1097
+ properties = {
1098
+ 'properties': "[AST_ObjectProperty*] array of properties",
1099
+ 'is_pydict': "[bool] True if this object is a python dict literal",
1100
+ 'is_jshash': "[bool] True if this object is a js hash literal",
1101
+ }
1102
+
1103
+ def _walk(self, visitor):
1104
+ return visitor._visit(self, def():
1105
+ for prop in self.properties:
1106
+ prop._walk(visitor)
1107
+ )
1108
+
1109
+ class AST_ExpressiveObject(AST_Object):
1110
+ 'An object literal with expressions for some keys'
1111
+
1112
+ class AST_ObjectProperty(AST_Node):
1113
+ "Base class for literal object properties"
1114
+ properties = {
1115
+ 'key': "[AST_Node] the property expression",
1116
+ 'value': "[AST_Node] property value. For setters and getters this is an AST_Function.",
1117
+ 'quoted': '',
1118
+ }
1119
+
1120
+ def _walk(self, visitor):
1121
+ return visitor._visit(self, def():
1122
+ self.key._walk(visitor)
1123
+ self.value._walk(visitor)
1124
+ )
1125
+
1126
+ class AST_ObjectKeyVal(AST_ObjectProperty):
1127
+ "A key: value object property"
1128
+
1129
+ class AST_ObjectSpread(AST_Node):
1130
+ "A **expr spread item inside an object/dict literal"
1131
+ properties = {
1132
+ 'value': "[AST_Node] the expression being spread",
1133
+ }
1134
+
1135
+ def _walk(self, visitor):
1136
+ return visitor._visit(self, def():
1137
+ self.value._walk(visitor)
1138
+ )
1139
+
1140
+ class AST_Set(AST_Node):
1141
+ "A set literal"
1142
+ properties = {
1143
+ 'items': "[AST_SetItem*] array of items"
1144
+ }
1145
+
1146
+ def _walk(self, visitor):
1147
+ return visitor._visit(self, def():
1148
+ for prop in self.items:
1149
+ prop._walk(visitor)
1150
+ )
1151
+
1152
+ class AST_SetItem(AST_Node):
1153
+ "An item in a set literal"
1154
+ properties = {
1155
+ 'value': "[AST_Node] The value of this item",
1156
+ }
1157
+
1158
+ def _walk(self, visitor):
1159
+ return visitor._visit(self, def():
1160
+ self.value._walk(visitor)
1161
+ )
1162
+
1163
+ class AST_Symbol(AST_Node):
1164
+ "Base class for all symbols"
1165
+ properties = {
1166
+ 'name': "[string] name of this symbol",
1167
+ 'scope': "[AST_Scope/S] the current scope (not necessarily the definition scope)",
1168
+ 'thedef': "[SymbolDef/S] the definition of this symbol"
1169
+ }
1170
+
1171
+ class AST_SymbolAlias(AST_Symbol):
1172
+ "An alias used in an import statement or with statement"
1173
+
1174
+ class AST_SymbolDeclaration(AST_Symbol):
1175
+ "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)"
1176
+ properties = {
1177
+ 'init': "[AST_Node*/S] array of initializers for this declaration."
1178
+ }
1179
+
1180
+ class AST_SymbolVar(AST_SymbolDeclaration):
1181
+ "Symbol defining a variable"
1182
+
1183
+ class AST_ImportedVar(AST_SymbolVar):
1184
+ "Symbol defining an imported symbol"
1185
+ properties = {
1186
+ 'alias': "AST_SymbolAlias the alias for this imported symbol"
1187
+ }
1188
+
1189
+ class AST_SymbolNonlocal(AST_SymbolDeclaration):
1190
+ "A nonlocal declaration"
1191
+
1192
+ class AST_SymbolFunarg(AST_SymbolVar):
1193
+ "Symbol naming a function argument, possibly with an annotation."
1194
+ properties = {
1195
+ 'annotation': "[AST_Node?] The annotation provided for this argument (if any)"
1196
+ }
1197
+
1198
+ class AST_SymbolDefun(AST_SymbolDeclaration):
1199
+ "Symbol defining a function"
1200
+
1201
+ class AST_SymbolLambda(AST_SymbolDeclaration):
1202
+ "Symbol naming a function expression"
1203
+
1204
+ class AST_SymbolCatch(AST_SymbolDeclaration):
1205
+ "Symbol naming the exception in catch"
1206
+
1207
+ class AST_SymbolRef(AST_Symbol):
1208
+ "Reference to some symbol (not definition/declaration)"
1209
+ properties = {
1210
+ 'parens': "[boolean/S] if true, this variable is wrapped in parentheses"
1211
+ }
1212
+
1213
+ class AST_This(AST_Symbol):
1214
+ "The `this` symbol"
1215
+
1216
+ class AST_Constant(AST_Node):
1217
+ "Base class for all constants"
1218
+
1219
+ class AST_String(AST_Constant):
1220
+ "A string literal"
1221
+ properties = {
1222
+ 'value': "[string] the contents of this string"
1223
+ }
1224
+
1225
+ class AST_Verbatim(AST_Constant):
1226
+ "Raw JavaScript code"
1227
+ properties = {
1228
+ 'value': "[string] A string of raw JS code"
1229
+ }
1230
+
1231
+ class AST_Number(AST_Constant):
1232
+ "A number literal"
1233
+ properties = {
1234
+ 'value': "[number] the numeric value"
1235
+ }
1236
+
1237
+ class AST_RegExp(AST_Constant):
1238
+ "A regexp literal"
1239
+ properties = {
1240
+ 'value': "[RegExp] the actual regexp"
1241
+ }
1242
+
1243
+ class AST_Atom(AST_Constant):
1244
+ "Base class for atoms"
1245
+ def __init__(self, initializer):
1246
+ if initializer:
1247
+ self.start = initializer.start
1248
+ self.end = initializer.end
1249
+
1250
+ class AST_Null(AST_Atom):
1251
+ "The `null` atom"
1252
+ value = None
1253
+
1254
+ class AST_Ellipsis(AST_Atom):
1255
+ "The `...` (Ellipsis) literal"
1256
+ value = v'ρσ_Ellipsis'
1257
+
1258
+ class AST_NaN(AST_Atom):
1259
+ "The impossible value"
1260
+ value = v'NaN'
1261
+
1262
+ class AST_Undefined(AST_Atom):
1263
+ "The `undefined` value"
1264
+ value = v'undefined'
1265
+
1266
+ class AST_Hole(AST_Atom):
1267
+ "A hole in an array"
1268
+ value = v'undefined'
1269
+
1270
+ class AST_Infinity(AST_Atom):
1271
+ "The `Infinity` value"
1272
+ value = v'Infinity'
1273
+
1274
+ class AST_Boolean(AST_Atom):
1275
+ "Base class for booleans"
1276
+
1277
+ class AST_False(AST_Boolean):
1278
+ "The `false` atom"
1279
+ value = False
1280
+
1281
+ class AST_True(AST_Boolean):
1282
+ "The `true` atom"
1283
+ value = True
1284
+
1285
+ # }}}
1286
+
1287
+ # TreeWalker {{{
1288
+
1289
+ class TreeWalker:
1290
+
1291
+ def __init__(self, callback):
1292
+ self.visit = callback
1293
+ self.stack = []
1294
+
1295
+ def _visit(self, node, descend):
1296
+ self.stack.push(node)
1297
+ ret = self.visit(node, ((def(): descend.call(node);) if descend else noop))
1298
+ if not ret and descend:
1299
+ descend.call(node)
1300
+
1301
+ self.stack.pop()
1302
+ return ret
1303
+
1304
+ def parent(self, n):
1305
+ return self.stack[self.stack.length - 2 - (n or 0)]
1306
+
1307
+ def push(self, node):
1308
+ self.stack.push(node)
1309
+
1310
+ def pop(self):
1311
+ return self.stack.pop()
1312
+
1313
+ def self(s):
1314
+ return s.stack[s.stack.length - 1]
1315
+
1316
+ def find_parent(self, type):
1317
+ stack = self.stack
1318
+ for i in range(stack.length-1, -1, -1):
1319
+ x = stack[i]
1320
+ if is_node_type(x, type):
1321
+ return x
1322
+
1323
+ def in_boolean_context(self):
1324
+ stack = self.stack
1325
+ i = stack.length
1326
+ self = stack[i -= 1]
1327
+ while i > 0:
1328
+ p = stack[i -= 1]
1329
+ if is_node_type(p, AST_If) and p.condition is self
1330
+ or is_node_type(p, AST_Conditional) and p.condition is self
1331
+ or is_node_type(p, AST_DWLoop) and p.condition is self
1332
+ or is_node_type(p, AST_UnaryPrefix) and p.operator is "!" and p.expression is self:
1333
+ return True
1334
+ if not (is_node_type(p, AST_Binary) and (p.operator is "&&" or p.operator is "||")):
1335
+ return False
1336
+ self = p
1337
+ # }}}
1338
+
1339
+ class Found(Exception):
1340
+ pass
1341
+
1342
+ def has_calls(expression):
1343
+ # Technically, in JavaScript property access is also dynamic and can
1344
+ # involve function calls. However, there is no way to determine which
1345
+ # property accesses are dynamic, so we ignore them, as they would lead to
1346
+ # too many false positives.
1347
+ if not expression:
1348
+ return False
1349
+ try:
1350
+ expression.walk(new TreeWalker(def(node):
1351
+ if is_node_type(node, AST_BaseCall) or is_node_type(node, AST_ItemAccess):
1352
+ raise Found()
1353
+ ))
1354
+ except Found:
1355
+ return True
1356
+ return False