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/src/output/modules.pyj
CHANGED
|
@@ -3,11 +3,14 @@
|
|
|
3
3
|
# globals: writefile
|
|
4
4
|
from __python__ import hash_literals
|
|
5
5
|
|
|
6
|
-
from parse import COMPILER_VERSION
|
|
7
|
-
from utils import cache_file_name
|
|
8
6
|
from output.statements import declare_vars, display_body
|
|
9
7
|
from output.stream import OutputStream
|
|
10
8
|
from output.utils import create_doctring
|
|
9
|
+
from output.comments import print_comments, output_comments
|
|
10
|
+
from output.functions import set_module_name
|
|
11
|
+
from parse import get_compiler_version
|
|
12
|
+
from utils import cache_file_name
|
|
13
|
+
|
|
11
14
|
|
|
12
15
|
def write_imports(module, output):
|
|
13
16
|
imports = []
|
|
@@ -116,7 +119,8 @@ def prologue(module, output):
|
|
|
116
119
|
|
|
117
120
|
|
|
118
121
|
def print_top_level(self, output):
|
|
119
|
-
|
|
122
|
+
set_module_name(self.module_id)
|
|
123
|
+
is_main = self.module_id is '__main__'
|
|
120
124
|
|
|
121
125
|
def write_docstrings():
|
|
122
126
|
if is_main and output.options.keep_docstrings and self.docstrings and self.docstrings.length:
|
|
@@ -148,6 +152,10 @@ def print_top_level(self, output):
|
|
|
148
152
|
display_body(self.body, True, output)
|
|
149
153
|
output.newline()
|
|
150
154
|
write_docstrings()
|
|
155
|
+
if self.comments_after and self.comments_after.length:
|
|
156
|
+
output.indent()
|
|
157
|
+
output_comments(self.comments_after, output)
|
|
158
|
+
output.newline()
|
|
151
159
|
)
|
|
152
160
|
)
|
|
153
161
|
output.print("();")
|
|
@@ -164,8 +172,12 @@ def print_top_level(self, output):
|
|
|
164
172
|
|
|
165
173
|
declare_vars(self.localvars, output)
|
|
166
174
|
display_body(self.body, True, output)
|
|
175
|
+
if self.comments_after and self.comments_after.length:
|
|
176
|
+
output_comments(self.comments_after, output)
|
|
177
|
+
set_module_name()
|
|
167
178
|
|
|
168
179
|
def print_module(self, output):
|
|
180
|
+
set_module_name(self.module_id)
|
|
169
181
|
|
|
170
182
|
def output_module(output):
|
|
171
183
|
declare_vars(self.localvars, output)
|
|
@@ -178,6 +190,7 @@ def print_module(self, output):
|
|
|
178
190
|
output.print("function()")
|
|
179
191
|
output.with_block(def():
|
|
180
192
|
# dump the logic of this module
|
|
193
|
+
print_comments(self, output)
|
|
181
194
|
if output.options.write_name:
|
|
182
195
|
output.indent()
|
|
183
196
|
output.print('var ')
|
|
@@ -194,9 +207,9 @@ def print_module(self, output):
|
|
|
194
207
|
output_module(output)
|
|
195
208
|
if self.srchash and self.filename:
|
|
196
209
|
cached = {
|
|
197
|
-
'version':
|
|
210
|
+
'version':get_compiler_version(), 'signature':self.srchash, 'classes': {}, 'baselib':self.baselib,
|
|
198
211
|
'nonlocalvars':self.nonlocalvars, 'imported_module_ids':self.imported_module_ids, 'exports':[],
|
|
199
|
-
'outputs':{}, 'discard_asserts': output.options.discard_asserts
|
|
212
|
+
'outputs':{}, 'discard_asserts': v'!!output.options.discard_asserts'
|
|
200
213
|
}
|
|
201
214
|
for cname in Object.keys(self.classes):
|
|
202
215
|
cobj = self.classes[cname]
|
|
@@ -225,6 +238,7 @@ def print_module(self, output):
|
|
|
225
238
|
output.print("()")
|
|
226
239
|
output.semicolon()
|
|
227
240
|
output.newline()
|
|
241
|
+
set_module_name()
|
|
228
242
|
|
|
229
243
|
def print_imports(container, output):
|
|
230
244
|
is_first_aname = True
|
|
@@ -246,7 +260,6 @@ def print_imports(container, output):
|
|
|
246
260
|
output.end_statement()
|
|
247
261
|
|
|
248
262
|
for self in container.imports:
|
|
249
|
-
output.import_(self.module)
|
|
250
263
|
if self.argnames:
|
|
251
264
|
# A from import
|
|
252
265
|
for argname in self.argnames:
|
package/src/output/operators.pyj
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
# vim:fileencoding=utf-8
|
|
2
2
|
# License: BSD Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
|
3
3
|
from __python__ import hash_literals
|
|
4
|
-
|
|
5
4
|
from ast import (
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
AST_Array, AST_Assign, AST_BaseCall, AST_Binary, AST_Conditional,
|
|
6
|
+
AST_ItemAccess, AST_Number, AST_Object, AST_Return, AST_Seq, AST_Set,
|
|
7
|
+
AST_SimpleStatement, AST_Statement, AST_String, AST_Sub, AST_Symbol,
|
|
8
|
+
AST_SymbolRef, AST_Unary, is_node_type
|
|
9
9
|
)
|
|
10
10
|
from output.loops import unpack_tuple
|
|
11
11
|
|
|
12
|
+
|
|
12
13
|
def print_getattr(self, output, skip_expression): # AST_Dot
|
|
13
14
|
if not skip_expression:
|
|
14
15
|
expr = self.expression
|
|
@@ -54,7 +55,17 @@ def print_rich_getitem(self, output): # AST_ItemAccess
|
|
|
54
55
|
output.print(func + '(')
|
|
55
56
|
self.expression.print(output), output.comma(), self.property.print(output)
|
|
56
57
|
if self.assignment:
|
|
57
|
-
output.comma()
|
|
58
|
+
output.comma()
|
|
59
|
+
asg = self.assignment
|
|
60
|
+
as_op = self.assign_operator
|
|
61
|
+
if as_op.length > 0:
|
|
62
|
+
self.assignment = None
|
|
63
|
+
print_rich_getitem(self, output)
|
|
64
|
+
self.assignment = asg
|
|
65
|
+
output.space()
|
|
66
|
+
output.print(as_op)
|
|
67
|
+
output.space()
|
|
68
|
+
self.assignment.print(output)
|
|
58
69
|
output.print(')')
|
|
59
70
|
|
|
60
71
|
def print_splice_assignment(self, output): # AST_Splice
|
|
@@ -82,7 +93,12 @@ def print_unary_prefix(self, output):
|
|
|
82
93
|
output.print(op)
|
|
83
94
|
if /^[a-z]/i.test(op):
|
|
84
95
|
output.space()
|
|
85
|
-
self.
|
|
96
|
+
if self.parenthesized:
|
|
97
|
+
output.with_parens(def():
|
|
98
|
+
self.expression.print(output)
|
|
99
|
+
)
|
|
100
|
+
else:
|
|
101
|
+
self.expression.print(output)
|
|
86
102
|
|
|
87
103
|
def write_instanceof(left, right, output):
|
|
88
104
|
|
|
@@ -123,19 +139,21 @@ def write_smart_equality(self, output):
|
|
|
123
139
|
output.print('ρσ_' + ('equals(' if self.operator is '==' else 'not_equals('))
|
|
124
140
|
self.left.print(output), output.print(','), output.space(), self.right.print(output), output.print(')')
|
|
125
141
|
|
|
126
|
-
def print_binary_op(self, output):
|
|
127
|
-
comparators = {
|
|
128
|
-
"<": True,
|
|
129
|
-
">": True,
|
|
130
|
-
"<=": True,
|
|
131
|
-
">=": True,
|
|
132
|
-
"==": True,
|
|
133
|
-
"!=": True
|
|
134
|
-
}
|
|
135
|
-
function_ops = {
|
|
136
|
-
"in": "ρσ_in",
|
|
137
|
-
}
|
|
138
142
|
|
|
143
|
+
comparators = {
|
|
144
|
+
"<": True,
|
|
145
|
+
">": True,
|
|
146
|
+
"<=": True,
|
|
147
|
+
">=": True,
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function_ops = {
|
|
151
|
+
"in": "ρσ_in",
|
|
152
|
+
'nin': '!ρσ_in',
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def print_binary_op(self, output):
|
|
139
157
|
if function_ops[self.operator]:
|
|
140
158
|
output.print(function_ops[self.operator])
|
|
141
159
|
output.with_parens(def():
|
|
@@ -144,6 +162,7 @@ def print_binary_op(self, output):
|
|
|
144
162
|
self.right.print(output)
|
|
145
163
|
)
|
|
146
164
|
elif comparators[self.operator] and is_node_type(self.left, AST_Binary) and comparators[self.left.operator]:
|
|
165
|
+
# A chained comparison such as a < b < c
|
|
147
166
|
if is_node_type(self.left.right, AST_Symbol):
|
|
148
167
|
# left side compares against a regular variable,
|
|
149
168
|
# no caching needed
|
|
@@ -184,7 +203,7 @@ def print_binary_op(self, output):
|
|
|
184
203
|
if is_node_type(self.left, AST_Unary) and not self.left.parenthesized:
|
|
185
204
|
left = self.left.expression
|
|
186
205
|
output.print(self.left.operator)
|
|
187
|
-
if output.options.js_version >
|
|
206
|
+
if output.options.js_version > 6:
|
|
188
207
|
output.print('(('), left.print(output), output.spaced(')', '**', '('), self.right.print(output), output.print('))')
|
|
189
208
|
else:
|
|
190
209
|
output.print('Math.pow('), left.print(output), output.comma(), self.right.print(output), output.print(')')
|
|
@@ -194,6 +213,18 @@ def print_binary_op(self, output):
|
|
|
194
213
|
write_instanceof(self.left, self.right, output)
|
|
195
214
|
elif self.operator is '*' and is_node_type(self.left, AST_String):
|
|
196
215
|
self.left.print(output), output.print('.repeat('), self.right.print(output), output.print(')')
|
|
216
|
+
elif self.operator is '===' or self.operator is '!==':
|
|
217
|
+
nan_check = None
|
|
218
|
+
if is_node_type(self.right, AST_Symbol) and self.right.name is 'NaN':
|
|
219
|
+
nan_check = self.left
|
|
220
|
+
if is_node_type(self.left, AST_Symbol) and self.left.name is 'NaN':
|
|
221
|
+
nan_check = self.right
|
|
222
|
+
if nan_check is not None:
|
|
223
|
+
# We use the fact that NaN is the only object that is not equal to
|
|
224
|
+
# itself
|
|
225
|
+
output.spaced(nan_check, '!==' if self.operator is '===' else '===', nan_check)
|
|
226
|
+
else:
|
|
227
|
+
output.spaced(self.left, self.operator, self.right)
|
|
197
228
|
else:
|
|
198
229
|
output.spaced(self.left, self.operator, self.right)
|
|
199
230
|
|
|
@@ -112,7 +112,7 @@ def print_bracketed(node, output, complex, function_preamble, before, after):
|
|
|
112
112
|
if complex:
|
|
113
113
|
display_complex_body(node, False, output, function_preamble)
|
|
114
114
|
else:
|
|
115
|
-
display_body(node.body, False, output
|
|
115
|
+
display_body(node.body, False, output)
|
|
116
116
|
if after:
|
|
117
117
|
after(output)
|
|
118
118
|
)
|
|
@@ -171,7 +171,7 @@ def print_with(self, output):
|
|
|
171
171
|
def print_assert(self, output):
|
|
172
172
|
if output.options.discard_asserts:
|
|
173
173
|
return
|
|
174
|
-
output.spaced('if', '(!'), self.condition.print(output), output.spaced(')', 'throw new AssertionError')
|
|
174
|
+
output.spaced('if', '(!('), self.condition.print(output), output.spaced('))', 'throw new AssertionError')
|
|
175
175
|
if self.message:
|
|
176
176
|
output.print('(')
|
|
177
177
|
self.message.print(output)
|
package/src/output/stream.pyj
CHANGED
|
@@ -8,25 +8,27 @@ from tokenizer import is_identifier_char
|
|
|
8
8
|
|
|
9
9
|
DANGEROUS = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g
|
|
10
10
|
|
|
11
|
+
|
|
12
|
+
def as_hex(code, sz):
|
|
13
|
+
val = code.toString(16)
|
|
14
|
+
if val.length < sz:
|
|
15
|
+
val = '0'.repeat(sz - val.length) + val
|
|
16
|
+
return val
|
|
17
|
+
|
|
18
|
+
|
|
11
19
|
def to_ascii(str_, identifier):
|
|
12
20
|
return str_.replace(/[\u0080-\uffff]/g, def(ch):
|
|
13
21
|
code = ch.charCodeAt(0).toString(16)
|
|
14
22
|
if code.length <= 2 and not identifier:
|
|
15
|
-
|
|
16
|
-
code = "0" + code
|
|
17
|
-
|
|
18
|
-
return "\\x" + code
|
|
23
|
+
return "\\x" + as_hex(code, 2)
|
|
19
24
|
else:
|
|
20
|
-
|
|
21
|
-
code = "0" + code
|
|
22
|
-
|
|
23
|
-
return "\\u" + code
|
|
25
|
+
return '\\u' + as_hex(code, 4)
|
|
24
26
|
|
|
25
27
|
)
|
|
26
28
|
|
|
27
29
|
def encode_string(str_):
|
|
28
30
|
return JSON.stringify(str_).replace(DANGEROUS, def(a):
|
|
29
|
-
return '\\u' + a.charCodeAt(0)
|
|
31
|
+
return '\\u' + as_hex(a.charCodeAt(0), 4)
|
|
30
32
|
)
|
|
31
33
|
require_semi_colon_chars = make_predicate("( [ + * / - , .")
|
|
32
34
|
|
|
@@ -64,7 +66,6 @@ class OutputStream:
|
|
|
64
66
|
self.current_line = 1
|
|
65
67
|
self.current_pos = 0
|
|
66
68
|
self.OUTPUT = ""
|
|
67
|
-
self.IMPORTED = {}
|
|
68
69
|
self.might_need_space = False
|
|
69
70
|
self.might_need_semicolon = False
|
|
70
71
|
self._last = None
|
|
@@ -249,7 +250,7 @@ class OutputStream:
|
|
|
249
250
|
self.indent()
|
|
250
251
|
self.spaced('var', 'ρσ_regenerator', '=', '{}')
|
|
251
252
|
self.end_statement()
|
|
252
|
-
code = regenerate(False, self.options.beautify)
|
|
253
|
+
code = 'ρσ_regenerator.regeneratorRuntime = ' + regenerate(False, self.options.beautify)
|
|
253
254
|
if self.options.beautify:
|
|
254
255
|
code = code.replace(/\/\/.*$/mg, '\n').replace(/^\s*$/gm, '') # strip comments
|
|
255
256
|
ci = self.make_indent(0)
|
|
@@ -259,9 +260,7 @@ class OutputStream:
|
|
|
259
260
|
|
|
260
261
|
def get(self):
|
|
261
262
|
return self.OUTPUT
|
|
262
|
-
|
|
263
|
-
def toString(self):
|
|
264
|
-
return self.OUTPUT
|
|
263
|
+
toString = get
|
|
265
264
|
|
|
266
265
|
def assign(self, name):
|
|
267
266
|
# generates: '[name] = '
|
|
@@ -285,13 +284,6 @@ class OutputStream:
|
|
|
285
284
|
def print_string(self, str_):
|
|
286
285
|
self.print(encode_string(str_))
|
|
287
286
|
|
|
288
|
-
def import_(self, module):
|
|
289
|
-
if not Object.prototype.hasOwnProperty.call(self.IMPORTED, module.key):
|
|
290
|
-
self.IMPORTED[module.key] = module
|
|
291
|
-
|
|
292
|
-
def is_main(self):
|
|
293
|
-
return self.OUTPUT.length is 0
|
|
294
|
-
|
|
295
287
|
def line(self):
|
|
296
288
|
return self.current_line
|
|
297
289
|
|
package/src/parse.pyj
CHANGED
|
@@ -29,8 +29,17 @@ from tokenizer import tokenizer, is_token, RESERVED_WORDS
|
|
|
29
29
|
COMPILER_VERSION = '__COMPILER_VERSION__'
|
|
30
30
|
PYTHON_FLAGS = {'dict_literals':True, 'overload_getitem':True, 'bound_methods':True, 'hash_literals':True}
|
|
31
31
|
|
|
32
|
+
|
|
33
|
+
def get_compiler_version():
|
|
34
|
+
return COMPILER_VERSION
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def static_predicate(names):
|
|
38
|
+
return {k:True for k in names.split(' ')}
|
|
39
|
+
|
|
32
40
|
NATIVE_CLASSES = {
|
|
33
41
|
'Image': {},
|
|
42
|
+
'FileReader': {},
|
|
34
43
|
'RegExp': {},
|
|
35
44
|
'Error': {},
|
|
36
45
|
'EvalError': {},
|
|
@@ -41,24 +50,26 @@ NATIVE_CLASSES = {
|
|
|
41
50
|
'TypeError': {},
|
|
42
51
|
'URIError': {},
|
|
43
52
|
'Object': {
|
|
44
|
-
'static':
|
|
45
|
-
|
|
46
|
-
'getOwnPropertySymbols
|
|
47
|
-
'defineProperties
|
|
48
|
-
|
|
53
|
+
'static': static_predicate(
|
|
54
|
+
'getOwnPropertyNames getOwnPropertyDescriptor getOwnPropertyDescriptors'
|
|
55
|
+
' getOwnPropertySymbols keys entries values create defineProperty'
|
|
56
|
+
' defineProperties getPrototypeOf setPrototypeOf assign'
|
|
57
|
+
' seal isSealed is preventExtensions isExtensible'
|
|
58
|
+
' freeze isFrozen'
|
|
59
|
+
)
|
|
49
60
|
},
|
|
50
61
|
'String': {
|
|
51
|
-
'static':
|
|
62
|
+
'static': static_predicate("fromCharCode")
|
|
52
63
|
},
|
|
53
64
|
'Array': {
|
|
54
|
-
'static':
|
|
65
|
+
'static': static_predicate("isArray from of")
|
|
55
66
|
},
|
|
56
67
|
'Function': {},
|
|
57
68
|
'Date': {
|
|
58
|
-
'static':
|
|
69
|
+
'static': static_predicate("UTC now parse")
|
|
59
70
|
},
|
|
60
71
|
'ArrayBuffer': {
|
|
61
|
-
'static':
|
|
72
|
+
'static': static_predicate('isView transfer')
|
|
62
73
|
},
|
|
63
74
|
'DataView': {},
|
|
64
75
|
'Float32Array': {},
|
|
@@ -76,7 +87,7 @@ NATIVE_CLASSES = {
|
|
|
76
87
|
'Set': {},
|
|
77
88
|
'WeakSet': {},
|
|
78
89
|
'Promise': {
|
|
79
|
-
'static':
|
|
90
|
+
'static': static_predicate('all race reject resolve')
|
|
80
91
|
},
|
|
81
92
|
'WebSocket': {},
|
|
82
93
|
'XMLHttpRequest': {},
|
|
@@ -97,7 +108,7 @@ ERROR_CLASSES = {
|
|
|
97
108
|
'AssertionError': {},
|
|
98
109
|
'ZeroDivisionError': {},
|
|
99
110
|
}
|
|
100
|
-
COMMON_STATIC =
|
|
111
|
+
COMMON_STATIC = static_predicate('call apply bind toString')
|
|
101
112
|
FORBIDDEN_CLASS_VARS = 'prototype constructor'.split(' ')
|
|
102
113
|
|
|
103
114
|
# -----[ Parser (constants) ]-----
|
|
@@ -119,7 +130,7 @@ PRECEDENCE = (def(a, ret):
|
|
|
119
130
|
[ "^" ],
|
|
120
131
|
[ "&" ],
|
|
121
132
|
[ "==", "===", "!=", "!==" ],
|
|
122
|
-
[ "<", ">", "<=", ">=", "in", "instanceof" ],
|
|
133
|
+
[ "<", ">", "<=", ">=", "in", "nin", "instanceof" ],
|
|
123
134
|
[ ">>", "<<", ">>>" ],
|
|
124
135
|
[ "+", "-" ],
|
|
125
136
|
[ "*", "/", "//", "%" ],
|
|
@@ -320,7 +331,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
320
331
|
continue
|
|
321
332
|
|
|
322
333
|
# recursive descent into conditional, loop and exception bodies
|
|
323
|
-
for option in ('body', 'alternative', 'bcatch'):
|
|
334
|
+
for option in ('body', 'alternative', 'bcatch', 'condition'):
|
|
324
335
|
opt = stmt[option]
|
|
325
336
|
if opt:
|
|
326
337
|
extend(scan_for_local_vars(opt))
|
|
@@ -467,13 +478,20 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
467
478
|
expect(".")
|
|
468
479
|
expect_token("keyword", "while")
|
|
469
480
|
tmp = expression(True)
|
|
481
|
+
if is_node_type(tmp, AST_Assign):
|
|
482
|
+
croak('Assignments in do loop conditions are not allowed')
|
|
470
483
|
semicolon()
|
|
471
484
|
return tmp
|
|
472
485
|
)()
|
|
473
486
|
})
|
|
474
487
|
elif tmp_ is "while":
|
|
488
|
+
while_cond = expression(True)
|
|
489
|
+
if is_node_type(while_cond, AST_Assign):
|
|
490
|
+
croak('Assignments in while loop conditions are not allowed')
|
|
491
|
+
if not is_('punc', ':'):
|
|
492
|
+
croak('Expected a colon after the while statement')
|
|
475
493
|
return new AST_While({
|
|
476
|
-
'condition':
|
|
494
|
+
'condition': while_cond,
|
|
477
495
|
'body': in_loop(statement)
|
|
478
496
|
})
|
|
479
497
|
elif tmp_ is "for":
|
|
@@ -739,7 +757,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
739
757
|
cached = None
|
|
740
758
|
|
|
741
759
|
srchash = sha1sum(src_code) # noqa:undef
|
|
742
|
-
if cached and cached.version is COMPILER_VERSION and cached.signature is srchash and cached.discard_asserts is options.discard_asserts:
|
|
760
|
+
if cached and cached.version is COMPILER_VERSION and cached.signature is srchash and cached.discard_asserts is v'!!options.discard_asserts':
|
|
743
761
|
for ikey in cached.imported_module_ids:
|
|
744
762
|
do_import(ikey) # Ensure all modules imported by the cached module are also imported
|
|
745
763
|
imported_modules[key] = {
|
|
@@ -880,7 +898,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
880
898
|
externaldecorator = has_simple_decorator(S.decorators, 'external')
|
|
881
899
|
|
|
882
900
|
class_details = {
|
|
883
|
-
"static":
|
|
901
|
+
"static": {},
|
|
884
902
|
'bound': v'[]',
|
|
885
903
|
'classvars': {},
|
|
886
904
|
'processing': name.name,
|
|
@@ -969,7 +987,9 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
969
987
|
if is_node_type(node, AST_Method):
|
|
970
988
|
class_var_names[node.name.name] = True
|
|
971
989
|
return
|
|
972
|
-
|
|
990
|
+
if is_node_type(node, AST_Function):
|
|
991
|
+
return
|
|
992
|
+
if is_node_type(node, AST_Assign) and is_node_type(node.left, AST_SymbolRef):
|
|
973
993
|
varname = node.left.name
|
|
974
994
|
if FORBIDDEN_CLASS_VARS.indexOf(varname) is not -1:
|
|
975
995
|
token_error(node.left.start, varname + ' is not allowed as a class variable name')
|
|
@@ -1002,7 +1022,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1002
1022
|
if staticloc:
|
|
1003
1023
|
if property_getter or property_setter:
|
|
1004
1024
|
croak('A method cannot be both static and a property getter/setter')
|
|
1005
|
-
S.classes[S.classes.length - 2][in_class].static
|
|
1025
|
+
S.classes[S.classes.length - 2][in_class].static[name.name] = True
|
|
1006
1026
|
staticmethod = True
|
|
1007
1027
|
elif name.name is not "__init__" and S.scoped_flags.get('bound_methods'):
|
|
1008
1028
|
S.classes[S.classes.length - 2][in_class].bound.push(name.name)
|
|
@@ -1689,7 +1709,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1689
1709
|
return sym
|
|
1690
1710
|
|
|
1691
1711
|
def is_static_method(cls, method):
|
|
1692
|
-
if COMMON_STATIC
|
|
1712
|
+
if has_prop(COMMON_STATIC, method) or (cls.static and has_prop(cls.static, method)):
|
|
1693
1713
|
return True
|
|
1694
1714
|
else:
|
|
1695
1715
|
return False
|
|
@@ -1782,7 +1802,9 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1782
1802
|
# regular index (arr[index])
|
|
1783
1803
|
if is_py_sub:
|
|
1784
1804
|
assignment = None
|
|
1785
|
-
|
|
1805
|
+
assign_operator = ''
|
|
1806
|
+
if is_("operator") and ASSIGNMENT[S.token.value]:
|
|
1807
|
+
assign_operator = S.token.value[:-1]
|
|
1786
1808
|
next()
|
|
1787
1809
|
assignment = expression(True)
|
|
1788
1810
|
return subscripts(new AST_ItemAccess({
|
|
@@ -1792,6 +1814,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1792
1814
|
'value': 0
|
|
1793
1815
|
}),
|
|
1794
1816
|
'assignment':assignment,
|
|
1817
|
+
'assign_operator': assign_operator,
|
|
1795
1818
|
'end': prev()
|
|
1796
1819
|
}), allow_calls)
|
|
1797
1820
|
|
|
@@ -1941,10 +1964,11 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1941
1964
|
return new AST_EmptyStatement({'stype':'@', 'start':prev(), 'end':prev()})
|
|
1942
1965
|
if is_("operator") and UNARY_PREFIX[start.value]:
|
|
1943
1966
|
next()
|
|
1967
|
+
is_parenthesized = is_('punc', '(')
|
|
1944
1968
|
S.in_delete = start.value is 'delete'
|
|
1945
1969
|
expr = maybe_unary(allow_calls)
|
|
1946
1970
|
S.in_delete = False
|
|
1947
|
-
ex = make_unary(AST_UnaryPrefix, start.value, expr)
|
|
1971
|
+
ex = make_unary(AST_UnaryPrefix, start.value, expr, is_parenthesized)
|
|
1948
1972
|
ex.start = start
|
|
1949
1973
|
ex.end = prev()
|
|
1950
1974
|
return ex
|
|
@@ -1952,23 +1976,21 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1952
1976
|
val = expr_atom(allow_calls)
|
|
1953
1977
|
return val
|
|
1954
1978
|
|
|
1955
|
-
def make_unary(ctor, op, expr):
|
|
1979
|
+
def make_unary(ctor, op, expr, is_parenthesized):
|
|
1956
1980
|
return new ctor({
|
|
1957
1981
|
'operator': op,
|
|
1958
|
-
'expression': expr
|
|
1982
|
+
'expression': expr,
|
|
1983
|
+
'parenthesized': is_parenthesized
|
|
1959
1984
|
})
|
|
1960
1985
|
|
|
1961
1986
|
def expr_op(left, min_prec, no_in):
|
|
1962
1987
|
op = S.token.value if is_('operator') else None
|
|
1963
|
-
not_in = False
|
|
1964
1988
|
if op is "!" and peek().type is "operator" and peek().value is "in":
|
|
1965
1989
|
next()
|
|
1966
|
-
op =
|
|
1967
|
-
not_in = True
|
|
1990
|
+
S.token.value = op = 'nin'
|
|
1968
1991
|
|
|
1969
|
-
if op is "in":
|
|
1970
|
-
|
|
1971
|
-
op = None
|
|
1992
|
+
if no_in and (op is "in" or op is 'nin'):
|
|
1993
|
+
op = None
|
|
1972
1994
|
|
|
1973
1995
|
prec = PRECEDENCE[op] if op is not None else None
|
|
1974
1996
|
if prec is not None and prec > min_prec:
|
|
@@ -1981,13 +2003,6 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1981
2003
|
'right': right,
|
|
1982
2004
|
'end': right.end
|
|
1983
2005
|
})
|
|
1984
|
-
if not_in:
|
|
1985
|
-
ret = new AST_UnaryPrefix({
|
|
1986
|
-
'start': left.start,
|
|
1987
|
-
'operator': "!",
|
|
1988
|
-
'expression': ret,
|
|
1989
|
-
'end': right.end
|
|
1990
|
-
})
|
|
1991
2006
|
return expr_op(ret, min_prec, no_in)
|
|
1992
2007
|
return left
|
|
1993
2008
|
|
|
@@ -2166,6 +2181,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2166
2181
|
toplevel.baselib = baselib_items
|
|
2167
2182
|
toplevel.scoped_flags = S.scoped_flags.stack[0]
|
|
2168
2183
|
importing_modules[module_id] = False
|
|
2184
|
+
toplevel.comments_after = S.token.comments_before or v'[]'
|
|
2169
2185
|
return toplevel
|
|
2170
2186
|
|
|
2171
2187
|
return run_parser
|
|
@@ -14,7 +14,12 @@ def render_markup(markup):
|
|
|
14
14
|
key += ch
|
|
15
15
|
pos += 1
|
|
16
16
|
fmtspec = markup[pos:]
|
|
17
|
-
|
|
17
|
+
prefix = ''
|
|
18
|
+
if key.endsWith('='):
|
|
19
|
+
prefix=key
|
|
20
|
+
key = key[:-1]
|
|
21
|
+
return 'ρσ_str.format("' + prefix + '{' + fmtspec + '}", ' + key + ')'
|
|
22
|
+
|
|
18
23
|
|
|
19
24
|
def interpolate(template, raise_error):
|
|
20
25
|
pos = in_brace = 0
|
package/src/tokenizer.pyj
CHANGED
|
@@ -458,7 +458,10 @@ def tokenizer(raw_text, filename):
|
|
|
458
458
|
else:
|
|
459
459
|
return token(tok_type, '')
|
|
460
460
|
|
|
461
|
-
while
|
|
461
|
+
while True:
|
|
462
|
+
ch = next(True, True)
|
|
463
|
+
if not ch:
|
|
464
|
+
break
|
|
462
465
|
if ch is "\n" and not is_multiline:
|
|
463
466
|
parse_error("End of line while scanning string literal")
|
|
464
467
|
|
|
@@ -529,7 +532,10 @@ def tokenizer(raw_text, filename):
|
|
|
529
532
|
else: # empty regexp (//)
|
|
530
533
|
mods = read_name()
|
|
531
534
|
return token("regexp", RegExp(regexp, mods))
|
|
532
|
-
while
|
|
535
|
+
while True:
|
|
536
|
+
ch = next(True)
|
|
537
|
+
if not ch:
|
|
538
|
+
break
|
|
533
539
|
if in_comment:
|
|
534
540
|
if ch is '\n':
|
|
535
541
|
in_comment = False
|
package/test/baselib.pyj
CHANGED
|
@@ -20,6 +20,11 @@ assrt.deepEqual(['a', 'b'], list('ab'))
|
|
|
20
20
|
assrt.ok(q is not list(q))
|
|
21
21
|
assrt.deepEqual(q, list(q))
|
|
22
22
|
assrt.ok(isinstance([], (String, list)))
|
|
23
|
+
assrt.ok(isinstance(1, int))
|
|
24
|
+
assrt.ok(not isinstance(v'new Number(1)', int))
|
|
25
|
+
assrt.ok(not isinstance(1.1, int))
|
|
26
|
+
assrt.ok(isinstance(1.1, float))
|
|
27
|
+
assrt.ok(not isinstance(v'new Number(1.1)', float))
|
|
23
28
|
m = Map()
|
|
24
29
|
m.set('a', 1)
|
|
25
30
|
assrt.equal(len(m), 1)
|
|
@@ -70,6 +75,9 @@ assrt.equal(int('a', 16), 10)
|
|
|
70
75
|
assrt.throws(def ():int('a');, ValueError)
|
|
71
76
|
assrt.equal(float('10.3'), 10.3)
|
|
72
77
|
assrt.throws(def ():float('a');, ValueError)
|
|
78
|
+
assrt.equal(int(2*1e-7), 0)
|
|
79
|
+
assrt.equal(int(10*1e-7), 0)
|
|
80
|
+
assrt.equal(float(3*1e-7), 3e-7)
|
|
73
81
|
|
|
74
82
|
# sum()
|
|
75
83
|
assrt.equal(6, sum([1, 2, 3]))
|
|
@@ -259,6 +267,8 @@ assrt.equal(b == a, False)
|
|
|
259
267
|
a, b = range(1111111111)
|
|
260
268
|
assrt.equal(a, 0)
|
|
261
269
|
assrt.equal(b, 1)
|
|
270
|
+
assrt.equal(len(range(10)), 10)
|
|
271
|
+
assrt.equal(str(range(10)), 'range(0, 10, 1)')
|
|
262
272
|
|
|
263
273
|
assrt.deepEqual(divmod(7, 3), [2, 1])
|
|
264
274
|
assrt.deepEqual(divmod(-7, 3), [-3, 2])
|
package/test/classes.pyj
CHANGED
|
@@ -401,6 +401,7 @@ class B2(B1):
|
|
|
401
401
|
def two(self):
|
|
402
402
|
return self.b2
|
|
403
403
|
assrt.equal(B2().two(), 2)
|
|
404
|
+
assrt.equal(B2().b1, 1)
|
|
404
405
|
|
|
405
406
|
|
|
406
407
|
class Cvar:
|
|
@@ -426,3 +427,26 @@ assrt.equal(Cvar.a, 2)
|
|
|
426
427
|
assrt.equal(Cvar().val(), 3)
|
|
427
428
|
assrt.equal(Cvar().incb(), 1)
|
|
428
429
|
assrt.equal(Cvar().incb(), 2)
|
|
430
|
+
|
|
431
|
+
class anon_func_in_class:
|
|
432
|
+
|
|
433
|
+
f = def():
|
|
434
|
+
func_var = 1
|
|
435
|
+
return func_var
|
|
436
|
+
|
|
437
|
+
def func_var(self):
|
|
438
|
+
pass
|
|
439
|
+
|
|
440
|
+
assrt.equal(jstype(anon_func_in_class.prototype.func_var), 'function')
|
|
441
|
+
anon_func_in_class.prototype.f()
|
|
442
|
+
assrt.equal(jstype(anon_func_in_class.prototype.func_var), 'function')
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def decorate(cls):
|
|
446
|
+
assrt.equal(cls.prototype.somevar, 1)
|
|
447
|
+
return cls
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
@decorate
|
|
451
|
+
class decorated:
|
|
452
|
+
somevar = 1
|
package/test/collections.pyj
CHANGED
|
@@ -69,6 +69,13 @@ assrt.deepEqual(a, [3,2,1])
|
|
|
69
69
|
a.pysort()
|
|
70
70
|
assrt.deepEqual(a, [1,2,3])
|
|
71
71
|
|
|
72
|
+
# misc interface
|
|
73
|
+
a = [1,2,3]
|
|
74
|
+
assrt.equal(a.pypop(), 3)
|
|
75
|
+
assrt.deepEqual(a, [1,2])
|
|
76
|
+
assrt.equal(a.pypop(0), 1)
|
|
77
|
+
assrt.deepEqual(a, [2])
|
|
78
|
+
|
|
72
79
|
# strings
|
|
73
80
|
assrt.ok("tes" in "this is a test")
|
|
74
81
|
|
|
@@ -104,6 +111,7 @@ assrt.equal(d1.fun2(3), 4)
|
|
|
104
111
|
assrt.equal(len(d0), 3)
|
|
105
112
|
assrt.equal(d2.get(1), 2)
|
|
106
113
|
assrt.equal(d2.get('a'), 'b')
|
|
114
|
+
assrt.deepEqual(d2.popitem(), ['a', 'b'])
|
|
107
115
|
|
|
108
116
|
# assignment
|
|
109
117
|
d1["bar"] += "!"
|