rapydscript-ng 0.7.18 → 0.7.22
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.
- package/.github/workflows/ci.yml +40 -0
- package/CHANGELOG.md +49 -1
- package/README.md +22 -7
- package/bin/web-repl-export +2 -2
- package/package.json +2 -2
- package/publish.py +9 -8
- package/release/baselib-plain-pretty.js +1707 -1044
- package/release/baselib-plain-ugly.js +3 -1
- package/release/compiler.js +5530 -3366
- package/release/signatures.json +18 -17
- package/src/ast.pyj +3 -1
- package/src/baselib-builtins.pyj +14 -3
- package/src/baselib-containers.pyj +13 -6
- package/src/baselib-internal.pyj +5 -1
- package/src/baselib-str.pyj +15 -2
- package/src/lib/elementmaker.pyj +2 -2
- package/src/lib/gettext.pyj +8 -7
- package/src/lib/random.pyj +1 -0
- package/src/lib/re.pyj +4 -3
- package/src/lib/traceback.pyj +16 -4
- package/src/output/classes.pyj +33 -5
- package/src/output/codegen.pyj +5 -38
- package/src/output/comments.pyj +45 -0
- package/src/output/functions.pyj +30 -19
- package/src/output/modules.pyj +19 -6
- package/src/output/operators.pyj +50 -19
- package/src/output/statements.pyj +2 -2
- package/src/output/stream.pyj +13 -21
- package/src/parse.pyj +52 -36
- package/src/string_interpolation.pyj +6 -1
- package/src/tokenizer.pyj +8 -2
- package/test/baselib.pyj +10 -0
- package/test/classes.pyj +24 -0
- package/test/collections.pyj +8 -0
- package/test/functions.pyj +16 -0
- package/test/generic.pyj +39 -1
- package/test/internationalization.pyj +8 -2
- package/test/regexp.pyj +3 -2
- package/test/scoped_flags.pyj +2 -0
- package/test/starargs.pyj +43 -0
- package/test/str.pyj +19 -8
- package/tools/cli.js +6 -1
- package/tools/compiler.js +3 -3
- package/tools/embedded_compiler.js +3 -3
- package/tools/export.js +3 -3
- package/tools/gettext.js +5 -2
- package/tools/lint.js +24 -13
- package/tools/msgfmt.js +1 -1
- package/web-repl/env.js +7 -1
- package/.appveyor.yml +0 -13
- package/.npmignore +0 -9
- package/.travis.yml +0 -12
package/release/signatures.json
CHANGED
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
{
|
|
2
|
-
"ast": "
|
|
3
|
-
"baselib-builtins": "
|
|
4
|
-
"baselib-containers": "
|
|
2
|
+
"ast": "7a1a1800d9ee7af7f7153eee38002e4e9dcfb71e",
|
|
3
|
+
"baselib-builtins": "50927b38fded9bd9dbe14c42a20dd8e930ac021f",
|
|
4
|
+
"baselib-containers": "f7ac21a4dfc6311693239ea1eb45e74fae45a3f5",
|
|
5
5
|
"baselib-errors": "f2423e1e2489bdd7fb8c8725bb76436898c8008c",
|
|
6
|
-
"baselib-internal": "
|
|
6
|
+
"baselib-internal": "1b77d40970a8ef2d886132dc7c21c9510d2eb4cd",
|
|
7
7
|
"baselib-itertools": "ab1f3257642c8d26fab1ff9d392814a459a60cdb",
|
|
8
|
-
"baselib-str": "
|
|
8
|
+
"baselib-str": "8c396e4fae02ae34b6d3d805becf7bfdd36625ee",
|
|
9
9
|
"compiler": "cfbfceb0439fed3302f78d80b303dca713b25e7b",
|
|
10
10
|
"errors": "d1b33848d19b141e19cc079cf78421f29b6d2c05",
|
|
11
11
|
"output/__init__": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
|
|
12
|
-
"output/classes": "
|
|
13
|
-
"output/codegen": "
|
|
12
|
+
"output/classes": "d05c1992cc91b337a4e4ff137b0aa3d626e6624b",
|
|
13
|
+
"output/codegen": "0519a88c2704fe60b98fe747ca39f6be43b9abf3",
|
|
14
|
+
"output/comments": "78ec38d8b34da96c078653e2d0d4049d7003906b",
|
|
14
15
|
"output/exceptions": "c7d90155694c7108e94d0940a160ae83725421d7",
|
|
15
|
-
"output/functions": "
|
|
16
|
+
"output/functions": "abaa81b171359eb77be6ea87cbdf9d7421d4622b",
|
|
16
17
|
"output/literals": "fdbfb744fec8dfea1e1c62cb49767c60160fd402",
|
|
17
18
|
"output/loops": "f59cc623320f57edb01953f7877d712758e9f825",
|
|
18
|
-
"output/modules": "
|
|
19
|
-
"output/operators": "
|
|
20
|
-
"output/statements": "
|
|
21
|
-
"output/stream": "
|
|
19
|
+
"output/modules": "bd3e3f3f6794fb6e401867b4d011c4e3aab98893",
|
|
20
|
+
"output/operators": "f8142836a13b75680cb4874391db9e871fad0cad",
|
|
21
|
+
"output/statements": "7d8dfdc0b43e3e430be7ce3b23ffaf1b41408d8c",
|
|
22
|
+
"output/stream": "46375cb467477ac898546e818bfdfa5be738c352",
|
|
22
23
|
"output/utils": "595968f96f6fdcc51eb41c34d64c92bb595e3cb1",
|
|
23
|
-
"parse": "
|
|
24
|
-
"string_interpolation": "
|
|
25
|
-
"tokenizer": "
|
|
24
|
+
"parse": "d5c1a77662dfcff841dfcd368d5dbb129a592f5d",
|
|
25
|
+
"string_interpolation": "bff1cc76d772d24d35707f6c794f38734ca08376",
|
|
26
|
+
"tokenizer": "00fc24a41edac9f9b31735e6290348005a623cef",
|
|
26
27
|
"unicode_aliases": "79ac6eaa5e6be44a5397d62c561f854a8fe7528e",
|
|
27
28
|
"utils": "c1666db819aa7c8db38697e34e18362e3cb45869",
|
|
28
|
-
"#compiler#": "
|
|
29
|
-
"#compiled_with#": "
|
|
29
|
+
"#compiler#": "d98fcbb15d08dae74d9c7371ea28fea676642e67",
|
|
30
|
+
"#compiled_with#": "d98fcbb15d08dae74d9c7371ea28fea676642e67"
|
|
30
31
|
}
|
package/src/ast.pyj
CHANGED
|
@@ -326,6 +326,7 @@ class AST_Toplevel(AST_Scope):
|
|
|
326
326
|
'classes': "[Object/S] a map of class names to AST_Class for classes defined in this module",
|
|
327
327
|
'filename': "[string] The absolute path to the file from which this module was read",
|
|
328
328
|
'srchash': "[string] SHA1 hash of source code, used for caching",
|
|
329
|
+
'comments_after': '[array] True iff there were comments before this token',
|
|
329
330
|
}
|
|
330
331
|
|
|
331
332
|
class AST_Import(AST_Statement):
|
|
@@ -411,7 +412,7 @@ class AST_Class(AST_Scope):
|
|
|
411
412
|
'init': "[AST_Function] constructor for the class",
|
|
412
413
|
'parent': "[AST_Symbol?] parent class this class inherits from",
|
|
413
414
|
'bases': "[AST_Symbol*] list of base classes this class inherits from",
|
|
414
|
-
"static": "[
|
|
415
|
+
"static": "[dict] A hash whose keys are names of static methods for this class",
|
|
415
416
|
'external': "[boolean] true if class is declared elsewhere, but will be within current scope at runtime",
|
|
416
417
|
'bound': "[string*] list of methods that need to be bound to self",
|
|
417
418
|
'decorators': "[AST_Decorator*] function decorators, if any",
|
|
@@ -718,6 +719,7 @@ class AST_ItemAccess(AST_PropAccess):
|
|
|
718
719
|
'Python index-style property access, i.e. `a.__getitem__("foo")`'
|
|
719
720
|
properties = {
|
|
720
721
|
'assignment': "[AST_Node or None] Not None if this is an assignment (a[x] = y) rather than a simple access",
|
|
722
|
+
'assign_operator': "[String] The operator for a assignment like += or empty string if plain assignment",
|
|
721
723
|
}
|
|
722
724
|
|
|
723
725
|
def _walk(self, visitor):
|
package/src/baselib-builtins.pyj
CHANGED
|
@@ -15,13 +15,19 @@ def ρσ_print():
|
|
|
15
15
|
console.log(parts.join(' '))
|
|
16
16
|
|
|
17
17
|
def ρσ_int(val, base):
|
|
18
|
-
|
|
18
|
+
if jstype(val) is "number":
|
|
19
|
+
ans = val | 0
|
|
20
|
+
else:
|
|
21
|
+
ans = parseInt(val, base or 10)
|
|
19
22
|
if isNaN(ans):
|
|
20
23
|
raise ValueError('Invalid literal for int with base ' + (base or 10) + ': ' + val)
|
|
21
24
|
return ans
|
|
22
25
|
|
|
23
|
-
def ρσ_float():
|
|
24
|
-
|
|
26
|
+
def ρσ_float(val):
|
|
27
|
+
if jstype(val) is "number":
|
|
28
|
+
ans = val
|
|
29
|
+
else:
|
|
30
|
+
ans = parseFloat(val)
|
|
25
31
|
if isNaN(ans):
|
|
26
32
|
raise ValueError('Could not convert string to float: ' + arguments[0])
|
|
27
33
|
return ans
|
|
@@ -171,6 +177,11 @@ def ρσ_range(start, stop, step):
|
|
|
171
177
|
if not this._cached:
|
|
172
178
|
this._cached = list(this)
|
|
173
179
|
return this._cached.index(val)
|
|
180
|
+
ans.__len__ = def():
|
|
181
|
+
return length
|
|
182
|
+
ans.__repr__ = def():
|
|
183
|
+
return f'range({start}, {stop}, {step})'
|
|
184
|
+
ans.__str__ = ans.toString = ans.__repr__
|
|
174
185
|
if jstype(Proxy) is 'function':
|
|
175
186
|
ans = new Proxy(ans, {
|
|
176
187
|
'get': def(obj, prop):
|
|
@@ -81,6 +81,8 @@ def ρσ_list_index(val, start, stop):
|
|
|
81
81
|
def ρσ_list_pop(index):
|
|
82
82
|
if this.length is 0:
|
|
83
83
|
raise IndexError('list is empty')
|
|
84
|
+
if index is undefined:
|
|
85
|
+
index = -1
|
|
84
86
|
ans = this.splice(index, 1)
|
|
85
87
|
if not ans.length:
|
|
86
88
|
raise IndexError('pop index out of range')
|
|
@@ -464,7 +466,7 @@ Object.defineProperties(ρσ_set.prototype, {
|
|
|
464
466
|
s.add(r.value)
|
|
465
467
|
r = iterator.next()
|
|
466
468
|
|
|
467
|
-
ρσ_set.prototype.toString = ρσ_set.prototype.inspect = def():
|
|
469
|
+
ρσ_set.prototype.toString = ρσ_set.prototype.__repr__ = ρσ_set.prototype.__str__ = ρσ_set.prototype.inspect = def():
|
|
468
470
|
return '{' + list(this).join(', ') + '}'
|
|
469
471
|
|
|
470
472
|
ρσ_set.prototype.__eq__ = def(other):
|
|
@@ -630,11 +632,16 @@ Object.defineProperties(ρσ_dict.prototype, {
|
|
|
630
632
|
return ans
|
|
631
633
|
|
|
632
634
|
ρσ_dict.prototype.popitem = def ():
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
635
|
+
last = None
|
|
636
|
+
e = this.jsmap.entries()
|
|
637
|
+
while True:
|
|
638
|
+
r = e.next()
|
|
639
|
+
if r.done:
|
|
640
|
+
if last is None:
|
|
641
|
+
raise KeyError('dict is empty')
|
|
642
|
+
this.jsmap.delete(last.value[0])
|
|
643
|
+
return last.value
|
|
644
|
+
last = r
|
|
638
645
|
|
|
639
646
|
ρσ_dict.prototype.update = def ():
|
|
640
647
|
if arguments.length is 0:
|
package/src/baselib-internal.pyj
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# vim:fileencoding=utf-8
|
|
2
2
|
# License: BSD
|
|
3
3
|
|
|
4
|
-
# globals: exports, console, ρσ_iterator_symbol, ρσ_kwargs_symbol, ρσ_arraylike, ρσ_list_contains, ρσ_list_constructor, ρσ_str
|
|
4
|
+
# globals: exports, console, ρσ_iterator_symbol, ρσ_kwargs_symbol, ρσ_arraylike, ρσ_list_contains, ρσ_list_constructor, ρσ_str, ρσ_int, ρσ_float
|
|
5
5
|
|
|
6
6
|
def ρσ_eslice(arr, step, start, end):
|
|
7
7
|
if jstype(arr) is 'string' or v'arr instanceof String':
|
|
@@ -261,6 +261,10 @@ def ρσ_instanceof():
|
|
|
261
261
|
return True
|
|
262
262
|
if q is ρσ_str and (jstype(obj) is 'string' or v'obj instanceof String'):
|
|
263
263
|
return True
|
|
264
|
+
if q is ρσ_int and (jstype(obj) is 'number' and Number.isInteger(obj)):
|
|
265
|
+
return True
|
|
266
|
+
if q is ρσ_float and (jstype(obj) is 'number' and not Number.isInteger(obj)):
|
|
267
|
+
return True
|
|
264
268
|
if bases.length > 1:
|
|
265
269
|
for v'var c = 1; c < bases.length; c++':
|
|
266
270
|
cls = bases[c]
|
package/src/baselib-str.pyj
CHANGED
|
@@ -4,6 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
# globals: ρσ_kwargs_symbol, ρσ_list_decorate, ρσ_iterator_symbol, HTMLElement
|
|
6
6
|
|
|
7
|
+
# Locale can’t be changed in-flight, so we just retrieve this once.
|
|
8
|
+
# Sadly older node versions (< 8) don’t support formatToParts
|
|
9
|
+
# decimal_sep = Intl.NumberFormat() \
|
|
10
|
+
# .formatToParts(1.1) \
|
|
11
|
+
# .find(def(part): return part.type == 'decimal';) \
|
|
12
|
+
# .value
|
|
13
|
+
decimal_sep = (1.1).toLocaleString()[1]
|
|
14
|
+
|
|
7
15
|
def ρσ_repr_js_builtin(x, as_array):
|
|
8
16
|
ans = v'[]'
|
|
9
17
|
b = '{}'
|
|
@@ -174,7 +182,7 @@ define_str_func('format', def ():
|
|
|
174
182
|
(\#)? # integer base specifier
|
|
175
183
|
(0)? # zero-padding
|
|
176
184
|
(\d+)? # width
|
|
177
|
-
([,_])? # use a
|
|
185
|
+
([,_])? # use a grouping (thousands) seperator
|
|
178
186
|
(?:\.(\d+))? # precision
|
|
179
187
|
([bcdeEfFgGnosxX%])? # type
|
|
180
188
|
///
|
|
@@ -253,7 +261,7 @@ define_str_func('format', def ():
|
|
|
253
261
|
else:
|
|
254
262
|
value = value.toExponential(prec - 1)
|
|
255
263
|
value = value.replace(/0+$/g, '')
|
|
256
|
-
if value[-1] is
|
|
264
|
+
if value[-1] is decimal_sep:
|
|
257
265
|
value = value[:-1]
|
|
258
266
|
if ftype is 'G':
|
|
259
267
|
value = value.toUpperCase()
|
|
@@ -334,6 +342,9 @@ define_str_func('format', def ():
|
|
|
334
342
|
key, transformer, format_spec = parse_markup(markup)
|
|
335
343
|
if transformer and v"['a', 'r', 's']".indexOf(transformer) is -1:
|
|
336
344
|
raise ValueError('Unknown conversion specifier: ' + transformer)
|
|
345
|
+
ends_with_equal = key.endsWith('=')
|
|
346
|
+
if ends_with_equal:
|
|
347
|
+
key = key[:-1]
|
|
337
348
|
lkey = key.length and split(key, /[.\[]/, 1)[0]
|
|
338
349
|
if lkey:
|
|
339
350
|
explicit = True
|
|
@@ -359,6 +370,8 @@ define_str_func('format', def ():
|
|
|
359
370
|
ans = '' + object
|
|
360
371
|
if format_spec:
|
|
361
372
|
ans = apply_formatting(ans, format_spec)
|
|
373
|
+
if ends_with_equal:
|
|
374
|
+
ans = f'{key}={ans}'
|
|
362
375
|
return ans
|
|
363
376
|
|
|
364
377
|
|
package/src/lib/elementmaker.pyj
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
|
|
4
4
|
html_elements = {
|
|
5
5
|
'a', 'abbr', 'acronym', 'address', 'area',
|
|
6
|
-
'article', 'aside', 'audio', 'b', 'big', 'blockquote', 'br', 'button',
|
|
6
|
+
'article', 'aside', 'audio', 'b', 'base', 'big', 'body', 'blockquote', 'br', 'button',
|
|
7
7
|
'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup',
|
|
8
8
|
'command', 'datagrid', 'datalist', 'dd', 'del', 'details', 'dfn',
|
|
9
9
|
'dialog', 'dir', 'div', 'dl', 'dt', 'em', 'event-source', 'fieldset',
|
|
10
10
|
'figcaption', 'figure', 'footer', 'font', 'form', 'header', 'h1',
|
|
11
|
-
'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'iframe', 'img', 'input', 'ins',
|
|
11
|
+
'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'head', 'i', 'iframe', 'img', 'input', 'ins',
|
|
12
12
|
'keygen', 'kbd', 'label', 'legend', 'li', 'm', 'map', 'menu', 'meter',
|
|
13
13
|
'multicol', 'nav', 'nextid', 'ol', 'output', 'optgroup', 'option',
|
|
14
14
|
'p', 'pre', 'progress', 'q', 's', 'samp', 'script', 'section', 'select',
|
package/src/lib/gettext.pyj
CHANGED
|
@@ -531,29 +531,31 @@ def register_callback(func):
|
|
|
531
531
|
register_callback.install_callbacks.push(func)
|
|
532
532
|
register_callback.install_callbacks = v'[]'
|
|
533
533
|
|
|
534
|
+
empty_translation_data = {'entries': {}}
|
|
535
|
+
|
|
534
536
|
class Translations:
|
|
535
537
|
|
|
536
538
|
def __init__(self, translation_data):
|
|
537
|
-
translation_data = translation_data or
|
|
538
|
-
func = _get_plural_forms_function(translation_data
|
|
539
|
+
translation_data = translation_data or empty_translation_data
|
|
540
|
+
func = _get_plural_forms_function(translation_data.plural_forms)
|
|
539
541
|
self.translations = [[translation_data, func]]
|
|
540
542
|
self.language = translation_data['language']
|
|
541
543
|
|
|
542
544
|
def add_fallback(self, fallback):
|
|
543
|
-
fallback = fallback or
|
|
544
|
-
func = _get_plural_forms_function(fallback
|
|
545
|
+
fallback = fallback or empty_translation_data
|
|
546
|
+
func = _get_plural_forms_function(fallback.plural_forms)
|
|
545
547
|
self.translations.push([fallback, func])
|
|
546
548
|
|
|
547
549
|
def gettext(self, text):
|
|
548
550
|
for t in self.translations:
|
|
549
|
-
m = t[0]
|
|
551
|
+
m = t[0].entries
|
|
550
552
|
if has_prop(m, text):
|
|
551
553
|
return m[text][0]
|
|
552
554
|
return text
|
|
553
555
|
|
|
554
556
|
def ngettext(self, text, plural, n):
|
|
555
557
|
for t in self.translations:
|
|
556
|
-
m = t[0]
|
|
558
|
+
m = t[0].entries
|
|
557
559
|
if has_prop(m, text):
|
|
558
560
|
idx = t[1](n)
|
|
559
561
|
return m[text][idx] or (text if n is 1 else plural)
|
|
@@ -565,4 +567,3 @@ class Translations:
|
|
|
565
567
|
return self.gettext.apply(self, arguments)
|
|
566
568
|
_ngettext = def ():
|
|
567
569
|
return self.ngettext.apply(self, arguments)
|
|
568
|
-
|
package/src/lib/random.pyj
CHANGED
package/src/lib/re.pyj
CHANGED
|
@@ -125,9 +125,12 @@ def _expand(groups, repl, group_name_map):
|
|
|
125
125
|
return '\\' + q
|
|
126
126
|
|
|
127
127
|
ans = ch = ''
|
|
128
|
-
while
|
|
128
|
+
while True:
|
|
129
|
+
ch = next()
|
|
129
130
|
if ch is '\\':
|
|
130
131
|
ans += read_escape_sequence()
|
|
132
|
+
elif not ch:
|
|
133
|
+
break
|
|
131
134
|
else:
|
|
132
135
|
ans += ch
|
|
133
136
|
return ans
|
|
@@ -184,8 +187,6 @@ def transform_regex(source, flags):
|
|
|
184
187
|
flags |= flag_map[q]
|
|
185
188
|
pos = close + 1
|
|
186
189
|
continue
|
|
187
|
-
if extension is '<':
|
|
188
|
-
raise SyntaxError('Look behind assertions are not supported in JavaScript')
|
|
189
190
|
if extension is '(':
|
|
190
191
|
raise SyntaxError('Group existence assertions are not supported in JavaScript')
|
|
191
192
|
if extension is 'P':
|
package/src/lib/traceback.pyj
CHANGED
|
@@ -2,18 +2,30 @@
|
|
|
2
2
|
# License: BSD Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
|
3
3
|
# globals: ρσ_str, ρσ_last_exception
|
|
4
4
|
|
|
5
|
+
|
|
5
6
|
def _get_internal_traceback(err):
|
|
6
7
|
if isinstance(err, Exception) and err.stack:
|
|
7
8
|
lines = ρσ_str.splitlines(err.stack)
|
|
9
|
+
final_lines = v'[]'
|
|
10
|
+
found_sentinel = False
|
|
8
11
|
for i, line in enumerate(lines):
|
|
9
|
-
|
|
12
|
+
sline = ρσ_str.strip(line)
|
|
13
|
+
if i is 0:
|
|
14
|
+
final_lines.push(line)
|
|
15
|
+
continue
|
|
16
|
+
if found_sentinel:
|
|
17
|
+
final_lines.push(line)
|
|
18
|
+
continue
|
|
10
19
|
# These two conditions work on desktop Chrome and Firefox to identify the correct
|
|
11
20
|
# line in the traceback.
|
|
12
|
-
if
|
|
13
|
-
|
|
21
|
+
if sline.startsWith('at new ' + err.name) or sline.startsWith(err.name + '@'):
|
|
22
|
+
found_sentinel = True
|
|
23
|
+
return final_lines.join('\n')
|
|
14
24
|
return err and err.stack
|
|
15
25
|
|
|
16
26
|
def format_exception(exc, limit):
|
|
27
|
+
if jstype(exc) is 'undefined':
|
|
28
|
+
exc = ρσ_last_exception
|
|
17
29
|
if not isinstance(exc, Error):
|
|
18
30
|
if exc and exc.toString:
|
|
19
31
|
return [exc.toString()]
|
|
@@ -22,7 +34,7 @@ def format_exception(exc, limit):
|
|
|
22
34
|
if tb:
|
|
23
35
|
lines = ρσ_str.splitlines(tb)
|
|
24
36
|
e = lines[0]
|
|
25
|
-
lines =
|
|
37
|
+
lines = lines[1:]
|
|
26
38
|
if limit:
|
|
27
39
|
lines = lines[:limit+1] if limit > 0 else lines[limit:]
|
|
28
40
|
lines.reverse()
|
package/src/output/classes.pyj
CHANGED
|
@@ -5,6 +5,7 @@ from __python__ import hash_literals
|
|
|
5
5
|
from ast import AST_Class, AST_Method, is_node_type
|
|
6
6
|
from output.functions import decorate, function_definition, function_annotation
|
|
7
7
|
from output.utils import create_doctring
|
|
8
|
+
from utils import has_prop
|
|
8
9
|
|
|
9
10
|
def print_class(output):
|
|
10
11
|
self = this
|
|
@@ -14,7 +15,7 @@ def print_class(output):
|
|
|
14
15
|
def class_def(method, is_var):
|
|
15
16
|
output.indent()
|
|
16
17
|
self.name.print(output)
|
|
17
|
-
if not is_var and method and self.static
|
|
18
|
+
if not is_var and method and has_prop(self.static, method):
|
|
18
19
|
output.assign("." + method)
|
|
19
20
|
else:
|
|
20
21
|
if is_var:
|
|
@@ -27,7 +28,7 @@ def print_class(output):
|
|
|
27
28
|
if not is_property:
|
|
28
29
|
class_def(name)
|
|
29
30
|
# only strip first argument if the method is static
|
|
30
|
-
is_static = self.static
|
|
31
|
+
is_static = has_prop(self.static, name)
|
|
31
32
|
strip_first = not is_static
|
|
32
33
|
|
|
33
34
|
# decorate the method
|
|
@@ -74,15 +75,25 @@ def print_class(output):
|
|
|
74
75
|
output.end_statement()
|
|
75
76
|
)
|
|
76
77
|
|
|
77
|
-
|
|
78
|
-
if
|
|
78
|
+
decorators = self.decorators or v'[]'
|
|
79
|
+
if decorators.length:
|
|
79
80
|
output.print('var ')
|
|
80
81
|
output.assign(self.name)
|
|
81
|
-
|
|
82
|
+
write_constructor()
|
|
82
83
|
output.semicolon()
|
|
83
84
|
else:
|
|
84
85
|
write_constructor()
|
|
85
86
|
output.newline()
|
|
87
|
+
if decorators.length:
|
|
88
|
+
output.indent()
|
|
89
|
+
self.name.print(output)
|
|
90
|
+
output.spaced('.ρσ_decorators', '=', '[')
|
|
91
|
+
num = decorators.length
|
|
92
|
+
for i in range(num):
|
|
93
|
+
decorators[i].expression.print(output)
|
|
94
|
+
output.spaced(',' if i < num - 1 else ']')
|
|
95
|
+
output.semicolon()
|
|
96
|
+
output.newline()
|
|
86
97
|
|
|
87
98
|
# inheritance
|
|
88
99
|
if self.parent:
|
|
@@ -233,3 +244,20 @@ def print_class(output):
|
|
|
233
244
|
output.indent()
|
|
234
245
|
stmt.print(output)
|
|
235
246
|
output.newline()
|
|
247
|
+
|
|
248
|
+
if decorators.length:
|
|
249
|
+
output.indent()
|
|
250
|
+
output.assign(self.name)
|
|
251
|
+
for di in range(decorators.length):
|
|
252
|
+
self.name.print(output)
|
|
253
|
+
output.print(f'.ρσ_decorators[{di}](')
|
|
254
|
+
self.name.print(output)
|
|
255
|
+
output.print(')' * decorators.length)
|
|
256
|
+
output.semicolon()
|
|
257
|
+
output.newline()
|
|
258
|
+
output.indent()
|
|
259
|
+
output.spaced('delete ')
|
|
260
|
+
self.name.print(output)
|
|
261
|
+
output.print('.ρσ_decorators')
|
|
262
|
+
output.semicolon()
|
|
263
|
+
output.newline()
|
package/src/output/codegen.pyj
CHANGED
|
@@ -8,9 +8,9 @@ from utils import noop
|
|
|
8
8
|
from parse import PRECEDENCE
|
|
9
9
|
from ast import (
|
|
10
10
|
AST_Array, AST_Assign, AST_BaseCall, AST_Binary, AST_BlockStatement, AST_Break,
|
|
11
|
-
|
|
11
|
+
AST_Class, AST_Conditional, AST_Constant, AST_Continue,
|
|
12
12
|
AST_Debugger, AST_Definitions, AST_Directive, AST_Do, AST_Dot, is_node_type,
|
|
13
|
-
AST_EmptyStatement, AST_Exit, AST_ExpressiveObject,
|
|
13
|
+
AST_EmptyStatement, AST_Exit, AST_ExpressiveObject, AST_ForIn,
|
|
14
14
|
AST_ForJS, AST_Function, AST_Hole, AST_If, AST_Imports, AST_Infinity,
|
|
15
15
|
AST_Lambda, AST_ListComprehension, AST_LoopControl, AST_NaN, AST_New, AST_Node,
|
|
16
16
|
AST_Number, AST_Object, AST_ObjectKeyVal, AST_ObjectProperty, AST_PropAccess,
|
|
@@ -25,6 +25,7 @@ from output.classes import print_class
|
|
|
25
25
|
from output.literals import print_array, print_obj_literal, print_object, print_set, print_regexp
|
|
26
26
|
from output.loops import print_do_loop, print_while_loop, print_for_loop_body, print_for_in, print_list_comprehension
|
|
27
27
|
from output.modules import print_top_level, print_imports
|
|
28
|
+
from output.comments import print_comments
|
|
28
29
|
from output.operators import (
|
|
29
30
|
print_getattr, print_getitem, print_rich_getitem, print_splice_assignment,
|
|
30
31
|
print_unary_prefix, print_binary_op, print_assign,
|
|
@@ -57,42 +58,8 @@ def generate_code():
|
|
|
57
58
|
|
|
58
59
|
# -----[ comments ]-----
|
|
59
60
|
AST_Node.prototype.add_comments = def(output):
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if c:
|
|
63
|
-
start = self.start
|
|
64
|
-
if start and not start._comments_dumped:
|
|
65
|
-
start._comments_dumped = True
|
|
66
|
-
comments = start.comments_before
|
|
67
|
-
# XXX: ugly fix for https://github.com/mishoo/RapydScript2/issues/112
|
|
68
|
-
# if this node is `return` or `throw`, we cannot allow comments before
|
|
69
|
-
# the returned or thrown value.
|
|
70
|
-
if is_node_type(self, AST_Exit) and self.value and self.value.start.comments_before and self.value.start.comments_before.length > 0:
|
|
71
|
-
comments = (comments or []).concat(self.value.start.comments_before)
|
|
72
|
-
self.value.start.comments_before = []
|
|
73
|
-
|
|
74
|
-
if c.test:
|
|
75
|
-
comments = comments.filter(def(comment):
|
|
76
|
-
return c.test(comment.value)
|
|
77
|
-
)
|
|
78
|
-
elif jstype(c) is "function":
|
|
79
|
-
comments = comments.filter(def(comment):
|
|
80
|
-
return c(self, comment)
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
for comm in comments:
|
|
84
|
-
if comm.type is "comment1":
|
|
85
|
-
output.print("//" + comm.value + "\n")
|
|
86
|
-
output.indent()
|
|
87
|
-
elif comm.type is "comment2":
|
|
88
|
-
output.print("/*" + comm.value + "*/")
|
|
89
|
-
if start.nlb:
|
|
90
|
-
output.print("\n")
|
|
91
|
-
output.indent()
|
|
92
|
-
else:
|
|
93
|
-
output.space()
|
|
94
|
-
|
|
95
|
-
|
|
61
|
+
if not is_node_type(this, AST_Toplevel):
|
|
62
|
+
print_comments(this, output)
|
|
96
63
|
|
|
97
64
|
# -----[ PARENTHESES ]-----
|
|
98
65
|
def PARENS(nodetype, func):
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# vim:fileencoding=utf-8
|
|
2
|
+
# License: BSD Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
|
3
|
+
from __python__ import hash_literals
|
|
4
|
+
|
|
5
|
+
from ast import AST_Exit, is_node_type
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def output_comments(comments, output, nlb):
|
|
9
|
+
for comm in comments:
|
|
10
|
+
if comm.type is "comment1":
|
|
11
|
+
output.print("//" + comm.value + "\n")
|
|
12
|
+
output.indent()
|
|
13
|
+
elif comm.type is "comment2":
|
|
14
|
+
output.print("/*" + comm.value + "*/")
|
|
15
|
+
if nlb:
|
|
16
|
+
output.print("\n")
|
|
17
|
+
output.indent()
|
|
18
|
+
else:
|
|
19
|
+
output.space()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def print_comments(self, output):
|
|
23
|
+
c = output.options.comments
|
|
24
|
+
if c:
|
|
25
|
+
start = self.start
|
|
26
|
+
if start and not start._comments_dumped:
|
|
27
|
+
start._comments_dumped = True
|
|
28
|
+
comments = start.comments_before
|
|
29
|
+
# XXX: ugly fix for https://github.com/mishoo/RapydScript2/issues/112
|
|
30
|
+
# if this node is `return` or `throw`, we cannot allow comments before
|
|
31
|
+
# the returned or thrown value.
|
|
32
|
+
if is_node_type(self, AST_Exit) and self.value and self.value.start.comments_before and self.value.start.comments_before.length > 0:
|
|
33
|
+
comments = (comments or v'[]').concat(self.value.start.comments_before)
|
|
34
|
+
self.value.start.comments_before = v'[]'
|
|
35
|
+
|
|
36
|
+
if c.test:
|
|
37
|
+
comments = comments.filter(def(comment):
|
|
38
|
+
return c.test(comment.value)
|
|
39
|
+
)
|
|
40
|
+
elif jstype(c) is "function":
|
|
41
|
+
comments = comments.filter(def(comment):
|
|
42
|
+
return c(self, comment)
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
output_comments(comments, output, start.nlb)
|
package/src/output/functions.pyj
CHANGED
|
@@ -10,6 +10,12 @@ from output.utils import create_doctring
|
|
|
10
10
|
from output.operators import print_getattr
|
|
11
11
|
|
|
12
12
|
anonfunc = 'ρσ_anonfunc'
|
|
13
|
+
module_name = 'null'
|
|
14
|
+
|
|
15
|
+
def set_module_name(x):
|
|
16
|
+
nonlocal module_name
|
|
17
|
+
module_name = '"' + x + '"' if x else 'null'
|
|
18
|
+
|
|
13
19
|
|
|
14
20
|
# Function definition {{{
|
|
15
21
|
|
|
@@ -148,7 +154,7 @@ def function_annotation(self, output, strip_first, name):
|
|
|
148
154
|
output.print('true')
|
|
149
155
|
|
|
150
156
|
# Create __argnames__
|
|
151
|
-
if self.argnames.length:
|
|
157
|
+
if self.argnames.length > (1 if strip_first else 0):
|
|
152
158
|
props.__argnames__ = def():
|
|
153
159
|
output.print('[')
|
|
154
160
|
for i, arg in enumerate(self.argnames):
|
|
@@ -164,29 +170,28 @@ def function_annotation(self, output, strip_first, name):
|
|
|
164
170
|
props.__doc__ = def():
|
|
165
171
|
output.print(JSON.stringify(create_doctring(self.docstrings)))
|
|
166
172
|
|
|
173
|
+
props.__module__ = def():
|
|
174
|
+
output.print(module_name)
|
|
175
|
+
|
|
167
176
|
names = Object.keys(props)
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
output.print(')'), output.end_statement()
|
|
177
|
+
output.indent()
|
|
178
|
+
# Only define the properties if they were not already defined, which
|
|
179
|
+
# can happen if the function definition is inside a loop, for example.
|
|
180
|
+
output.spaced('if', '(!' + fname + '.' + names[0] + ')', 'Object.defineProperties(' + fname)
|
|
181
|
+
output.comma()
|
|
182
|
+
output.with_block(def():
|
|
183
|
+
for v'var i = 0; i < names.length; i++':
|
|
184
|
+
name = names[i]
|
|
185
|
+
output.indent(), output.spaced(name, ':', '{value:', ''), props[name](), output.print('}')
|
|
186
|
+
if i < names.length - 1:
|
|
187
|
+
output.print(',')
|
|
188
|
+
output.newline()
|
|
189
|
+
)
|
|
190
|
+
output.print(')'), output.end_statement()
|
|
183
191
|
|
|
184
192
|
|
|
185
193
|
def function_definition(self, output, strip_first, as_expression):
|
|
186
194
|
as_expression = as_expression or self.is_expression or self.is_anonymous
|
|
187
|
-
if not self.argnames.length and not self.return_annotation and (not output.options.keep_docstrings or not self.docstrings or not self.docstrings.length):
|
|
188
|
-
# This function has no annotations so dont wrap it needlessly
|
|
189
|
-
as_expression = False
|
|
190
195
|
if as_expression:
|
|
191
196
|
orig_indent = output.indentation()
|
|
192
197
|
output.set_indentation(output.next_indent())
|
|
@@ -268,8 +273,10 @@ def print_this(expression, output):
|
|
|
268
273
|
output.print('this')
|
|
269
274
|
|
|
270
275
|
def print_function_call(self, output):
|
|
276
|
+
is_prototype_call = False
|
|
271
277
|
|
|
272
278
|
def print_function_name(no_call):
|
|
279
|
+
nonlocal is_prototype_call
|
|
273
280
|
if is_node_type(self, AST_ClassCall):
|
|
274
281
|
# class methods are called through the prototype unless static
|
|
275
282
|
if self.static:
|
|
@@ -277,6 +284,7 @@ def print_function_call(self, output):
|
|
|
277
284
|
output.print(".")
|
|
278
285
|
output.print(self.method)
|
|
279
286
|
else:
|
|
287
|
+
is_prototype_call = True
|
|
280
288
|
self.class.print(output)
|
|
281
289
|
output.print(".prototype.")
|
|
282
290
|
output.print(self.method)
|
|
@@ -396,6 +404,9 @@ def print_function_call(self, output):
|
|
|
396
404
|
output.print('.apply(')
|
|
397
405
|
do_print_this()
|
|
398
406
|
|
|
407
|
+
if is_prototype_call and self.args.length > 1:
|
|
408
|
+
self.args.shift()
|
|
409
|
+
|
|
399
410
|
print_positional_args()
|
|
400
411
|
|
|
401
412
|
if has_kwargs:
|