rapydscript-ns 0.9.3 → 0.9.5

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 (111) hide show
  1. package/.agignore +1 -1
  2. package/.github/workflows/ci.yml +38 -38
  3. package/=template.pyj +5 -5
  4. package/CHANGELOG.md +18 -0
  5. package/HACKING.md +103 -103
  6. package/LICENSE +24 -24
  7. package/PYTHON_GAPS.md +52 -142
  8. package/README.md +51 -21
  9. package/TODO.md +1 -26
  10. package/add-toc-to-readme +2 -2
  11. package/bin/export +75 -75
  12. package/bin/rapydscript +0 -0
  13. package/bin/web-repl-export +102 -102
  14. package/build +2 -2
  15. package/language-service/index.js +88 -36
  16. package/package.json +1 -1
  17. package/publish.py +37 -37
  18. package/release/baselib-plain-pretty.js +157 -31
  19. package/release/baselib-plain-ugly.js +5 -5
  20. package/release/compiler.js +724 -426
  21. package/release/signatures.json +29 -29
  22. package/session.vim +4 -4
  23. package/setup.cfg +2 -2
  24. package/src/ast.pyj +7 -0
  25. package/src/baselib-containers.pyj +41 -4
  26. package/src/baselib-errors.pyj +4 -3
  27. package/src/baselib-internal.pyj +47 -18
  28. package/src/baselib-str.pyj +16 -3
  29. package/src/compiler.pyj +36 -36
  30. package/src/errors.pyj +30 -30
  31. package/src/lib/aes.pyj +646 -646
  32. package/src/lib/collections.pyj +227 -3
  33. package/src/lib/copy.pyj +120 -120
  34. package/src/lib/elementmaker.pyj +83 -83
  35. package/src/lib/encodings.pyj +126 -126
  36. package/src/lib/gettext.pyj +569 -569
  37. package/src/lib/itertools.pyj +580 -580
  38. package/src/lib/math.pyj +193 -193
  39. package/src/lib/operator.pyj +11 -11
  40. package/src/lib/pprint.pyj +455 -0
  41. package/src/lib/random.pyj +118 -118
  42. package/src/lib/react.pyj +74 -74
  43. package/src/lib/statistics.pyj +0 -0
  44. package/src/lib/traceback.pyj +63 -63
  45. package/src/lib/uuid.pyj +77 -77
  46. package/src/monaco-language-service/completions.js +21 -14
  47. package/src/monaco-language-service/diagnostics.js +2 -2
  48. package/src/monaco-language-service/dts.js +58 -15
  49. package/src/monaco-language-service/package.json +3 -0
  50. package/src/output/classes.pyj +25 -2
  51. package/src/output/codegen.pyj +4 -1
  52. package/src/output/comments.pyj +45 -45
  53. package/src/output/exceptions.pyj +201 -201
  54. package/src/output/jsx.pyj +164 -164
  55. package/src/output/treeshake.pyj +182 -182
  56. package/src/output/utils.pyj +72 -72
  57. package/src/parse.pyj +42 -7
  58. package/src/string_interpolation.pyj +72 -72
  59. package/src/tokenizer.pyj +18 -2
  60. package/src/unicode_aliases.pyj +576 -576
  61. package/src/utils.pyj +192 -192
  62. package/test/_import_one.pyj +37 -37
  63. package/test/_import_two/__init__.pyj +11 -11
  64. package/test/_import_two/level2/deep.pyj +4 -4
  65. package/test/_import_two/other.pyj +6 -6
  66. package/test/_import_two/sub.pyj +13 -13
  67. package/test/aes_vectors.pyj +421 -421
  68. package/test/annotations.pyj +80 -80
  69. package/test/baselib.pyj +23 -0
  70. package/test/chainmap.pyj +185 -0
  71. package/test/dataclasses.pyj +3 -4
  72. package/test/decorators.pyj +77 -77
  73. package/test/docstrings.pyj +39 -39
  74. package/test/elementmaker_test.pyj +45 -45
  75. package/test/enum.pyj +1 -1
  76. package/test/functions.pyj +151 -151
  77. package/test/generators.pyj +41 -41
  78. package/test/generic.pyj +370 -370
  79. package/test/internationalization.pyj +73 -73
  80. package/test/lint.pyj +164 -164
  81. package/test/loops.pyj +85 -85
  82. package/test/numpy.pyj +734 -734
  83. package/test/pprint.pyj +232 -0
  84. package/test/python_features.pyj +1 -1
  85. package/test/repl.pyj +121 -121
  86. package/test/scoped_flags.pyj +76 -76
  87. package/test/statistics.pyj +224 -0
  88. package/test/str.pyj +4 -4
  89. package/test/unit/index.js +455 -0
  90. package/test/unit/language-service-completions.js +2 -0
  91. package/test/unit/language-service-dts.js +113 -0
  92. package/test/unit/language-service-hover.js +455 -455
  93. package/test/unit/language-service.js +135 -2
  94. package/test/unit/web-repl.js +349 -1
  95. package/tools/compiler.d.ts +367 -367
  96. package/tools/completer.js +131 -131
  97. package/tools/export.js +4 -2
  98. package/tools/gettext.js +185 -185
  99. package/tools/ini.js +65 -65
  100. package/tools/msgfmt.js +187 -187
  101. package/tools/repl.js +223 -223
  102. package/tools/test.js +118 -118
  103. package/tools/utils.js +141 -128
  104. package/tools/web_repl.js +95 -95
  105. package/try +41 -41
  106. package/web-repl/env.js +196 -196
  107. package/web-repl/index.html +163 -163
  108. package/web-repl/prism.css +139 -139
  109. package/web-repl/prism.js +113 -113
  110. package/web-repl/rapydscript.js +228 -226
  111. package/web-repl/sha1.js +25 -25
@@ -1,182 +1,182 @@
1
- # vim:fileencoding=utf-8
2
- # License: BSD
3
- from __python__ import hash_literals
4
-
5
- from ast import (
6
- AST_Function, AST_Class, AST_SimpleStatement, AST_Assign,
7
- AST_SymbolRef, AST_Dot, AST_Sub, AST_Imports, TreeWalker, is_node_type
8
- )
9
- from utils import has_prop
10
-
11
-
12
- def get_top_level_name(stmt):
13
- if is_node_type(stmt, AST_Function) or is_node_type(stmt, AST_Class):
14
- if stmt.name:
15
- return stmt.name.name
16
- return None
17
- if is_node_type(stmt, AST_SimpleStatement):
18
- body = stmt.body
19
- if is_node_type(body, AST_Assign):
20
- lhs = body.left
21
- if is_node_type(lhs, AST_SymbolRef):
22
- return lhs.name
23
- return None
24
-
25
-
26
- def collect_refs_in_node(stmt, top_level_set, refs):
27
- def visit_fn(node, descend):
28
- if is_node_type(node, AST_SymbolRef):
29
- if has_prop(top_level_set, node.name):
30
- refs[node.name] = True
31
- stmt.walk(TreeWalker(visit_fn))
32
-
33
-
34
- def compute_transitive_closure(body, direct_names, nonlocalvars):
35
- nonlocal_set = {}
36
- if nonlocalvars:
37
- for nv in nonlocalvars:
38
- nonlocal_set[nv] = True
39
-
40
- name_map = {}
41
- unnamed_stmts = []
42
- for stmt in body:
43
- name = get_top_level_name(stmt)
44
- if name is not None:
45
- name_map[name] = stmt
46
- else:
47
- unnamed_stmts.push(stmt)
48
-
49
- top_level_set = {}
50
- for name in Object.keys(name_map):
51
- top_level_set[name] = True
52
-
53
- needed = {}
54
- queue = []
55
-
56
- # Always include top-level assignments to nonlocal vars — they affect the
57
- # global JavaScript scope and must never be filtered out.
58
- for name in Object.keys(name_map):
59
- if has_prop(nonlocal_set, name):
60
- needed[name] = True
61
- queue.push(name)
62
-
63
- # Add directly imported names
64
- for name in Object.keys(direct_names):
65
- if not has_prop(needed, name):
66
- needed[name] = True
67
- queue.push(name)
68
-
69
- # Unnamed statements (imports, if-blocks, bare expressions) are always
70
- # included in output, so their references to named top-level items must
71
- # also be included transitively.
72
- always_refs = {}
73
- for stmt in unnamed_stmts:
74
- collect_refs_in_node(stmt, top_level_set, always_refs)
75
- for ref_name in Object.keys(always_refs):
76
- if not has_prop(needed, ref_name):
77
- needed[ref_name] = True
78
- queue.push(ref_name)
79
-
80
- while queue.length > 0:
81
- current = queue.shift()
82
- if not has_prop(name_map, current):
83
- continue
84
- refs = {}
85
- collect_refs_in_node(name_map[current], top_level_set, refs)
86
- for ref_name in Object.keys(refs):
87
- if not has_prop(needed, ref_name):
88
- needed[ref_name] = True
89
- queue.push(ref_name)
90
-
91
- return needed
92
-
93
-
94
- def check_module_attr_access(main_body, info, alias_set):
95
- def visit_fn(node, descend):
96
- if is_node_type(node, AST_Dot):
97
- expr = node.expression
98
- if is_node_type(expr, AST_SymbolRef) and has_prop(alias_set, expr.name):
99
- info.direct_names[node.property] = True
100
- return True
101
- if is_node_type(node, AST_Sub):
102
- expr = node.expression
103
- if is_node_type(expr, AST_SymbolRef) and has_prop(alias_set, expr.name):
104
- info.can_tree_shake = False
105
- for stmt in main_body:
106
- stmt.walk(TreeWalker(visit_fn))
107
-
108
-
109
- def analyze_imports(main_body):
110
- result = {}
111
-
112
- # First pass: walk the entire AST recursively to collect all from-imports
113
- # (including those nested inside functions or other scopes).
114
- def visit_from_imports(node, descend):
115
- if is_node_type(node, AST_Imports):
116
- for imp in node.imports:
117
- if imp.argnames:
118
- key = imp.key
119
- if not has_prop(result, key):
120
- result[key] = {'direct_names': {}, 'can_tree_shake': True}
121
- for argname in imp.argnames:
122
- result[key].direct_names[argname.name] = True
123
- for stmt in main_body:
124
- stmt.walk(TreeWalker(visit_from_imports))
125
-
126
- # Second pass: handle top-level plain imports (import X as Y, import X).
127
- # Attribute tracking via check_module_attr_access applies to main_body scope.
128
- for stmt in main_body:
129
- if not is_node_type(stmt, AST_Imports):
130
- continue
131
- for imp in stmt.imports:
132
- if imp.argnames:
133
- continue # already handled in first pass
134
- key = imp.key
135
- if not has_prop(result, key):
136
- result[key] = {'direct_names': {}, 'can_tree_shake': True}
137
- info = result[key]
138
- if imp.alias:
139
- alias_set = {}
140
- alias_set[imp.alias.name] = True
141
- check_module_attr_access(main_body, info, alias_set)
142
- else:
143
- parts = key.split('.')
144
- if parts.length > 1:
145
- # import X.Y with no alias: user accesses via X.Y.attr which
146
- # requires two-level dot traversal — disable tree-shaking safely
147
- info.can_tree_shake = False
148
- else:
149
- alias_set = {}
150
- alias_set[parts[0]] = True
151
- check_module_attr_access(main_body, info, alias_set)
152
-
153
- return result
154
-
155
-
156
- def tree_shake(ast, context):
157
- import_infos = analyze_imports(ast.body)
158
- for mod_key in Object.keys(import_infos):
159
- info = import_infos[mod_key]
160
- if not info.can_tree_shake:
161
- continue
162
- if not has_prop(ast.imports, mod_key):
163
- continue
164
- mod = ast.imports[mod_key]
165
- # If body is missing (cached module), re-parse to get it
166
- if not mod.body and mod.src_code:
167
- parsed = context.parse(mod.src_code, {
168
- 'filename': mod.filename,
169
- 'module_id': mod_key,
170
- 'libdir': context.libdir,
171
- 'import_dirs': context.import_dirs or [],
172
- 'discard_asserts': context.discard_asserts,
173
- 'for_linting': True,
174
- })
175
- mod.body = parsed.body
176
- mod.localvars = parsed.localvars
177
- if not mod.nonlocalvars:
178
- mod.nonlocalvars = parsed.nonlocalvars
179
- if not mod.body:
180
- continue
181
- needed = compute_transitive_closure(mod.body, info.direct_names, mod.nonlocalvars)
182
- mod.needed_names = needed
1
+ # vim:fileencoding=utf-8
2
+ # License: BSD
3
+ from __python__ import hash_literals
4
+
5
+ from ast import (
6
+ AST_Function, AST_Class, AST_SimpleStatement, AST_Assign,
7
+ AST_SymbolRef, AST_Dot, AST_Sub, AST_Imports, TreeWalker, is_node_type
8
+ )
9
+ from utils import has_prop
10
+
11
+
12
+ def get_top_level_name(stmt):
13
+ if is_node_type(stmt, AST_Function) or is_node_type(stmt, AST_Class):
14
+ if stmt.name:
15
+ return stmt.name.name
16
+ return None
17
+ if is_node_type(stmt, AST_SimpleStatement):
18
+ body = stmt.body
19
+ if is_node_type(body, AST_Assign):
20
+ lhs = body.left
21
+ if is_node_type(lhs, AST_SymbolRef):
22
+ return lhs.name
23
+ return None
24
+
25
+
26
+ def collect_refs_in_node(stmt, top_level_set, refs):
27
+ def visit_fn(node, descend):
28
+ if is_node_type(node, AST_SymbolRef):
29
+ if has_prop(top_level_set, node.name):
30
+ refs[node.name] = True
31
+ stmt.walk(TreeWalker(visit_fn))
32
+
33
+
34
+ def compute_transitive_closure(body, direct_names, nonlocalvars):
35
+ nonlocal_set = {}
36
+ if nonlocalvars:
37
+ for nv in nonlocalvars:
38
+ nonlocal_set[nv] = True
39
+
40
+ name_map = {}
41
+ unnamed_stmts = []
42
+ for stmt in body:
43
+ name = get_top_level_name(stmt)
44
+ if name is not None:
45
+ name_map[name] = stmt
46
+ else:
47
+ unnamed_stmts.push(stmt)
48
+
49
+ top_level_set = {}
50
+ for name in Object.keys(name_map):
51
+ top_level_set[name] = True
52
+
53
+ needed = {}
54
+ queue = []
55
+
56
+ # Always include top-level assignments to nonlocal vars — they affect the
57
+ # global JavaScript scope and must never be filtered out.
58
+ for name in Object.keys(name_map):
59
+ if has_prop(nonlocal_set, name):
60
+ needed[name] = True
61
+ queue.push(name)
62
+
63
+ # Add directly imported names
64
+ for name in Object.keys(direct_names):
65
+ if not has_prop(needed, name):
66
+ needed[name] = True
67
+ queue.push(name)
68
+
69
+ # Unnamed statements (imports, if-blocks, bare expressions) are always
70
+ # included in output, so their references to named top-level items must
71
+ # also be included transitively.
72
+ always_refs = {}
73
+ for stmt in unnamed_stmts:
74
+ collect_refs_in_node(stmt, top_level_set, always_refs)
75
+ for ref_name in Object.keys(always_refs):
76
+ if not has_prop(needed, ref_name):
77
+ needed[ref_name] = True
78
+ queue.push(ref_name)
79
+
80
+ while queue.length > 0:
81
+ current = queue.shift()
82
+ if not has_prop(name_map, current):
83
+ continue
84
+ refs = {}
85
+ collect_refs_in_node(name_map[current], top_level_set, refs)
86
+ for ref_name in Object.keys(refs):
87
+ if not has_prop(needed, ref_name):
88
+ needed[ref_name] = True
89
+ queue.push(ref_name)
90
+
91
+ return needed
92
+
93
+
94
+ def check_module_attr_access(main_body, info, alias_set):
95
+ def visit_fn(node, descend):
96
+ if is_node_type(node, AST_Dot):
97
+ expr = node.expression
98
+ if is_node_type(expr, AST_SymbolRef) and has_prop(alias_set, expr.name):
99
+ info.direct_names[node.property] = True
100
+ return True
101
+ if is_node_type(node, AST_Sub):
102
+ expr = node.expression
103
+ if is_node_type(expr, AST_SymbolRef) and has_prop(alias_set, expr.name):
104
+ info.can_tree_shake = False
105
+ for stmt in main_body:
106
+ stmt.walk(TreeWalker(visit_fn))
107
+
108
+
109
+ def analyze_imports(main_body):
110
+ result = {}
111
+
112
+ # First pass: walk the entire AST recursively to collect all from-imports
113
+ # (including those nested inside functions or other scopes).
114
+ def visit_from_imports(node, descend):
115
+ if is_node_type(node, AST_Imports):
116
+ for imp in node.imports:
117
+ if imp.argnames:
118
+ key = imp.key
119
+ if not has_prop(result, key):
120
+ result[key] = {'direct_names': {}, 'can_tree_shake': True}
121
+ for argname in imp.argnames:
122
+ result[key].direct_names[argname.name] = True
123
+ for stmt in main_body:
124
+ stmt.walk(TreeWalker(visit_from_imports))
125
+
126
+ # Second pass: handle top-level plain imports (import X as Y, import X).
127
+ # Attribute tracking via check_module_attr_access applies to main_body scope.
128
+ for stmt in main_body:
129
+ if not is_node_type(stmt, AST_Imports):
130
+ continue
131
+ for imp in stmt.imports:
132
+ if imp.argnames:
133
+ continue # already handled in first pass
134
+ key = imp.key
135
+ if not has_prop(result, key):
136
+ result[key] = {'direct_names': {}, 'can_tree_shake': True}
137
+ info = result[key]
138
+ if imp.alias:
139
+ alias_set = {}
140
+ alias_set[imp.alias.name] = True
141
+ check_module_attr_access(main_body, info, alias_set)
142
+ else:
143
+ parts = key.split('.')
144
+ if parts.length > 1:
145
+ # import X.Y with no alias: user accesses via X.Y.attr which
146
+ # requires two-level dot traversal — disable tree-shaking safely
147
+ info.can_tree_shake = False
148
+ else:
149
+ alias_set = {}
150
+ alias_set[parts[0]] = True
151
+ check_module_attr_access(main_body, info, alias_set)
152
+
153
+ return result
154
+
155
+
156
+ def tree_shake(ast, context):
157
+ import_infos = analyze_imports(ast.body)
158
+ for mod_key in Object.keys(import_infos):
159
+ info = import_infos[mod_key]
160
+ if not info.can_tree_shake:
161
+ continue
162
+ if not has_prop(ast.imports, mod_key):
163
+ continue
164
+ mod = ast.imports[mod_key]
165
+ # If body is missing (cached module), re-parse to get it
166
+ if not mod.body and mod.src_code:
167
+ parsed = context.parse(mod.src_code, {
168
+ 'filename': mod.filename,
169
+ 'module_id': mod_key,
170
+ 'libdir': context.libdir,
171
+ 'import_dirs': context.import_dirs or [],
172
+ 'discard_asserts': context.discard_asserts,
173
+ 'for_linting': True,
174
+ })
175
+ mod.body = parsed.body
176
+ mod.localvars = parsed.localvars
177
+ if not mod.nonlocalvars:
178
+ mod.nonlocalvars = parsed.nonlocalvars
179
+ if not mod.body:
180
+ continue
181
+ needed = compute_transitive_closure(mod.body, info.direct_names, mod.nonlocalvars)
182
+ mod.needed_names = needed
@@ -1,72 +1,72 @@
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 ast import AST_BlockStatement, is_node_type
6
-
7
- def best_of(a):
8
- best = a[0]
9
- len_ = best.length
10
- for i in range(1, a.length):
11
- if a[i].length < len_:
12
- best = a[i]
13
- len_ = best.length
14
- return best
15
-
16
- def make_num(num):
17
- str_ = num.toString(10)
18
- a = [ str_.replace(/^0\./, ".").replace("e+", "e") ]
19
- m = None
20
-
21
- if Math.floor(num) is num:
22
- if num >= 0:
23
- a.push("0x" + num.toString(16).toLowerCase(), # probably pointless
24
- "0" + num.toString(8))
25
- else:
26
- a.push("-0x" + (-num).toString(16).toLowerCase(), # probably pointless
27
- "-0" + (-num).toString(8))
28
-
29
- if m = /^(.*?)(0+)$/.exec(num):
30
- a.push(m[1] + "e" + m[2].length)
31
-
32
- elif m = /^0?\.(0+)(.*)$/.exec(num):
33
- a.push(m[2] + "e-" + (m[1].length + m[2].length), str_.substr(str_.indexOf(".")))
34
-
35
- return best_of(a)
36
-
37
- def make_block(stmt, output):
38
- if is_node_type(stmt, AST_BlockStatement):
39
- stmt.print(output)
40
- return
41
-
42
- output.with_block(def():
43
- output.indent()
44
- stmt.print(output)
45
- output.newline()
46
- )
47
-
48
- def create_doctring(docstrings):
49
- ans = v'[]'
50
- for ds in docstrings:
51
- ds = str.rstrip(ds.value)
52
- lines = v'[]'
53
- min_leading_whitespace = ''
54
- for line in ds.split(/$/gm):
55
- r = /^\s+/.exec(line)
56
- leading_whitespace = ''
57
- if r:
58
- leading_whitespace = r[0].replace(/[\n\r]/g, '') if r else ''
59
- line = line[r[0].length:]
60
- if not str.strip(line):
61
- lines.push(v'["", ""]')
62
- else:
63
- leading_whitespace = leading_whitespace.replace(/\t/g, ' ')
64
- if leading_whitespace and (not min_leading_whitespace or leading_whitespace.length < min_leading_whitespace.length):
65
- min_leading_whitespace = leading_whitespace
66
- lines.push(v'[leading_whitespace, line]')
67
- for lw, l in lines:
68
- if min_leading_whitespace:
69
- lw = lw[min_leading_whitespace.length:]
70
- ans.push(lw + l)
71
- ans.push('')
72
- return str.rstrip(ans.join('\n'))
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 ast import AST_BlockStatement, is_node_type
6
+
7
+ def best_of(a):
8
+ best = a[0]
9
+ len_ = best.length
10
+ for i in range(1, a.length):
11
+ if a[i].length < len_:
12
+ best = a[i]
13
+ len_ = best.length
14
+ return best
15
+
16
+ def make_num(num):
17
+ str_ = num.toString(10)
18
+ a = [ str_.replace(/^0\./, ".").replace("e+", "e") ]
19
+ m = None
20
+
21
+ if Math.floor(num) is num:
22
+ if num >= 0:
23
+ a.push("0x" + num.toString(16).toLowerCase(), # probably pointless
24
+ "0" + num.toString(8))
25
+ else:
26
+ a.push("-0x" + (-num).toString(16).toLowerCase(), # probably pointless
27
+ "-0" + (-num).toString(8))
28
+
29
+ if m = /^(.*?)(0+)$/.exec(num):
30
+ a.push(m[1] + "e" + m[2].length)
31
+
32
+ elif m = /^0?\.(0+)(.*)$/.exec(num):
33
+ a.push(m[2] + "e-" + (m[1].length + m[2].length), str_.substr(str_.indexOf(".")))
34
+
35
+ return best_of(a)
36
+
37
+ def make_block(stmt, output):
38
+ if is_node_type(stmt, AST_BlockStatement):
39
+ stmt.print(output)
40
+ return
41
+
42
+ output.with_block(def():
43
+ output.indent()
44
+ stmt.print(output)
45
+ output.newline()
46
+ )
47
+
48
+ def create_doctring(docstrings):
49
+ ans = v'[]'
50
+ for ds in docstrings:
51
+ ds = str.rstrip(ds.value)
52
+ lines = v'[]'
53
+ min_leading_whitespace = ''
54
+ for line in ds.split(/$/gm):
55
+ r = /^\s+/.exec(line)
56
+ leading_whitespace = ''
57
+ if r:
58
+ leading_whitespace = r[0].replace(/[\n\r]/g, '') if r else ''
59
+ line = line[r[0].length:]
60
+ if not str.strip(line):
61
+ lines.push(v'["", ""]')
62
+ else:
63
+ leading_whitespace = leading_whitespace.replace(/\t/g, ' ')
64
+ if leading_whitespace and (not min_leading_whitespace or leading_whitespace.length < min_leading_whitespace.length):
65
+ min_leading_whitespace = leading_whitespace
66
+ lines.push(v'[leading_whitespace, line]')
67
+ for lw, l in lines:
68
+ if min_leading_whitespace:
69
+ lw = lw[min_leading_whitespace.length:]
70
+ ans.push(lw + l)
71
+ ans.push('')
72
+ return str.rstrip(ans.join('\n'))
package/src/parse.pyj CHANGED
@@ -6,7 +6,7 @@ from __python__ import hash_literals
6
6
  from utils import make_predicate, array_to_hash, defaults, has_prop, cache_file_name
7
7
  from errors import SyntaxError, ImportError
8
8
  from ast import (
9
- AST_Array, AST_Assign, AST_Binary, AST_BlockStatement, AST_Break,
9
+ AST_Array, AST_Assign, AST_BigInt, AST_Binary, AST_BlockStatement, AST_Break,
10
10
  AST_Call, AST_Catch, AST_Class, AST_ClassCall, AST_Conditional,
11
11
  AST_Constant, AST_Continue, AST_DWLoop, AST_Debugger, AST_Decorator,
12
12
  AST_Definitions, AST_DictComprehension, AST_Directive, AST_Do, AST_Dot,
@@ -144,7 +144,7 @@ PRECEDENCE = (def(a, ret):
144
144
 
145
145
  STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ])
146
146
 
147
- ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "imaginary", "string", "bytes_literal", "regexp", "name", "js" ])
147
+ ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "bigint", "imaginary", "string", "bytes_literal", "regexp", "name", "js" ])
148
148
 
149
149
  compile_time_decorators = ['staticmethod', 'classmethod', 'external', 'property']
150
150
 
@@ -520,7 +520,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
520
520
  return new AST_Directive({
521
521
  'value': tmp_
522
522
  })
523
- elif tmp_ is "num" or tmp_ is "regexp" or tmp_ is "operator" or tmp_ is "atom" or tmp_ is "js":
523
+ elif tmp_ is "num" or tmp_ is "bigint" or tmp_ is "regexp" or tmp_ is "operator" or tmp_ is "atom" or tmp_ is "js":
524
524
  return simple_statement()
525
525
  elif tmp_ is "punc":
526
526
  tmp_ = S.token.value
@@ -797,6 +797,8 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
797
797
  return new AST_String({'start': tok, 'value': tok.value, 'end': tok})
798
798
  elif tok.type is 'num':
799
799
  return new AST_Number({'start': tok, 'value': tok.value, 'end': tok})
800
+ elif tok.type is 'bigint':
801
+ return new AST_BigInt({'start': tok, 'value': tok.value, 'end': tok})
800
802
  elif tok.type is 'atom':
801
803
  if tok.value is 'True':
802
804
  return new AST_True({'start': tok, 'end': tok})
@@ -810,15 +812,18 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
810
812
  """Parse a single atomic/closed pattern (no OR, no AS)."""
811
813
  start = S.token
812
814
 
813
- # Negative number literal: -42
814
- if is_('operator', '-') and peek().type is 'num':
815
+ # Negative number literal: -42 or -42n
816
+ if is_('operator', '-') and (peek().type is 'num' or peek().type is 'bigint'):
815
817
  next() # consume '-'
816
- val = -S.token.value
817
818
  tok = S.token
819
+ if tok.type is 'bigint':
820
+ val_node = new AST_BigInt({'start': start, 'value': '-' + tok.value, 'end': tok})
821
+ else:
822
+ val_node = new AST_Number({'start': start, 'value': -tok.value, 'end': tok})
818
823
  next()
819
824
  return new AST_MatchLiteral({
820
825
  'start': start,
821
- 'value': new AST_Number({'start': start, 'value': val, 'end': tok}),
826
+ 'value': val_node,
822
827
  'end': prev()
823
828
  })
824
829
 
@@ -832,6 +837,16 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
832
837
  'end': prev()
833
838
  })
834
839
 
840
+ # BigInt literal
841
+ if is_('bigint'):
842
+ tok = S.token
843
+ next()
844
+ return new AST_MatchLiteral({
845
+ 'start': tok,
846
+ 'value': new AST_BigInt({'start': tok, 'value': tok.value, 'end': tok}),
847
+ 'end': prev()
848
+ })
849
+
835
850
  # String literal
836
851
  if is_('string'):
837
852
  tok = S.token
@@ -1607,6 +1622,20 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
1607
1622
  if parent_details and parent_details.has_attr_dunders:
1608
1623
  definition.has_attr_dunders = True
1609
1624
  class_details.has_attr_dunders = True
1625
+ # Detect __slots__ = [...] in class body
1626
+ for stmt in definition.body:
1627
+ assign = stmt
1628
+ if is_node_type(stmt, AST_SimpleStatement):
1629
+ assign = stmt.body
1630
+ if is_node_type(assign, AST_Assign) and is_node_type(assign.left, AST_SymbolRef) and assign.left.name is '__slots__':
1631
+ if is_node_type(assign.right, AST_Array):
1632
+ slot_names = []
1633
+ for elem in assign.right.elements:
1634
+ if is_node_type(elem, AST_String):
1635
+ slot_names.push(elem.value)
1636
+ definition.slots = slot_names
1637
+ class_details.slots = slot_names
1638
+ break
1610
1639
  # find the class variables
1611
1640
  class_var_names = {}
1612
1641
  # Ensure that if a class variable refers to another class variable in
@@ -2245,6 +2274,12 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
2245
2274
  'end': tok,
2246
2275
  'value': tok.value
2247
2276
  })
2277
+ elif tmp_ is "bigint":
2278
+ return new AST_BigInt({
2279
+ 'start': tok,
2280
+ 'end': tok,
2281
+ 'value': tok.value
2282
+ })
2248
2283
  elif tmp_ is "imaginary":
2249
2284
  return new AST_Call({
2250
2285
  'start': tok,