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
@@ -0,0 +1,309 @@
1
+ # vim:fileencoding=utf-8
2
+ # License: BSD Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
3
+ # globals:regenerate
4
+ from __python__ import hash_literals
5
+
6
+ from utils import make_predicate, defaults, repeat_string
7
+ from tokenizer import is_identifier_char
8
+
9
+ DANGEROUS = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g
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
+
19
+ def to_ascii(str_, identifier):
20
+ return str_.replace(/[\u0080-\uffff]/g, def(ch):
21
+ code = ch.charCodeAt(0).toString(16)
22
+ if code.length <= 2 and not identifier:
23
+ return "\\x" + as_hex(code, 2)
24
+ else:
25
+ return '\\u' + as_hex(code, 4)
26
+
27
+ )
28
+
29
+ def encode_string(str_):
30
+ return JSON.stringify(str_).replace(DANGEROUS, def(a):
31
+ return '\\u' + as_hex(a.charCodeAt(0), 4)
32
+ )
33
+ require_semi_colon_chars = make_predicate("( [ + * / - , .")
34
+
35
+ output_stream_defaults = {
36
+ 'indent_start': 0,
37
+ 'indent_level': 4,
38
+ 'quote_keys': False,
39
+ 'space_colon': True,
40
+ 'ascii_only': False,
41
+ 'width': 80,
42
+ 'max_line_len': 32000,
43
+ 'ie_proof': True,
44
+ 'beautify': False,
45
+ 'source_map': None,
46
+ 'bracketize': False,
47
+ 'semicolons': True,
48
+ 'comments': False,
49
+ 'preserve_line': False,
50
+ 'omit_baselib': False,
51
+ 'baselib_plain': None,
52
+ 'private_scope': True,
53
+ 'keep_docstrings': False,
54
+ 'discard_asserts': False,
55
+ 'module_cache_dir': '',
56
+ 'js_version':5,
57
+ 'write_name': True,
58
+ 'omit_function_metadata': False,
59
+ 'pythonize_strings': False,
60
+ }
61
+
62
+ class OutputStream:
63
+
64
+ def __init__(self, options):
65
+ self.options = defaults(options, output_stream_defaults, True)
66
+ self._indentation = 0
67
+ self.current_col = 0
68
+ self.current_line = 1
69
+ self.current_pos = 0
70
+ self.OUTPUT = ""
71
+ self.might_need_space = False
72
+ self.might_need_semicolon = False
73
+ self._last = None
74
+ self._stack = []
75
+ self.index_counter = 0
76
+ self.with_counter = 0
77
+ self.try_else_counter = 0
78
+ self.match_counter = 0
79
+
80
+ def new_try_else_counter(self):
81
+ self.try_else_counter += 1
82
+ return 'ρσ_try_else_' + self.try_else_counter
83
+
84
+ def make_name(self, name):
85
+ name = name.toString()
86
+ if self.options.ascii_only:
87
+ name = to_ascii(name, True)
88
+
89
+ return name
90
+
91
+ def print_name(self, name):
92
+ self.print(self.make_name(name))
93
+
94
+ def make_indent(self, back):
95
+ return repeat_string(" ", self.options.indent_start + self._indentation - back * self.options.indent_level)
96
+
97
+ # -----[ beautification/minification ]-----
98
+ def last_char(self):
99
+ return self._last.charAt(self._last.length - 1)
100
+
101
+ def maybe_newline(self):
102
+ if self.options.max_line_len and self.current_col > self.options.max_line_len:
103
+ self.print("\n")
104
+
105
+ def print(self, str_):
106
+ str_ = v"String(str_)"
107
+ ch = str_.charAt(0)
108
+ if self.might_need_semicolon:
109
+ if (not ch or ";}".indexOf(ch) < 0) and not /[;]$/.test(self._last):
110
+ if self.options.semicolons or require_semi_colon_chars[ch]:
111
+ self.OUTPUT += ";"
112
+ self.current_col += 1
113
+ self.current_pos += 1
114
+ else:
115
+ self.OUTPUT += "\n"
116
+ self.current_pos += 1
117
+ self.current_line += 1
118
+ self.current_col = 0
119
+
120
+ if not self.options.beautify:
121
+ self.might_need_space = False
122
+
123
+
124
+ self.might_need_semicolon = False
125
+ self.maybe_newline()
126
+
127
+ if not self.options.beautify and self.options.preserve_line and self._stack[self._stack.length - 1]:
128
+ target_line = self._stack[self._stack.length - 1].start.line
129
+ while self.current_line < target_line:
130
+ self.OUTPUT += "\n"
131
+ self.current_pos += 1
132
+ self.current_line += 1
133
+ self.current_col = 0
134
+ self.might_need_space = False
135
+
136
+
137
+ if self.might_need_space:
138
+ prev = self.last_char()
139
+ if is_identifier_char(prev) and (is_identifier_char(ch) or ch is "\\")
140
+ or /^[\+\-\/]$/.test(ch) and ch is prev:
141
+ self.OUTPUT += " "
142
+ self.current_col += 1
143
+ self.current_pos += 1
144
+
145
+ self.might_need_space = False
146
+
147
+ a = str_.split(/\r?\n/)
148
+ n = a.length - 1
149
+ self.current_line += n
150
+ if n is 0:
151
+ self.current_col += a[n].length
152
+ else:
153
+ self.current_col = a[n].length
154
+
155
+ self.current_pos += str_.length
156
+ self._last = str_
157
+ self.OUTPUT += str_
158
+
159
+ def space(self):
160
+ if self.options.beautify:
161
+ self.print(' ')
162
+ else:
163
+ self.might_need_space = True
164
+
165
+ def indent(self, half):
166
+ if self.options.beautify:
167
+ self.print(self.make_indent((0.5 if half else 0)))
168
+
169
+ def with_indent(self, col, proceed):
170
+ if self.options.beautify:
171
+ if col is True:
172
+ col = self.next_indent()
173
+
174
+ save_indentation = self._indentation
175
+ self._indentation = col
176
+ ret = proceed()
177
+ self._indentation = save_indentation
178
+ return ret
179
+ else:
180
+ return proceed()
181
+
182
+ def indentation(self):
183
+ return self._indentation
184
+
185
+ def set_indentation(self, val):
186
+ if self.options.beautify:
187
+ self._indentation = val
188
+
189
+ def newline(self):
190
+ if self.options.beautify:
191
+ self.print("\n")
192
+
193
+ def semicolon(self):
194
+ if self.options.beautify:
195
+ self.print(";")
196
+ else:
197
+ self.might_need_semicolon = True
198
+
199
+ def force_semicolon(self):
200
+ self.might_need_semicolon = False
201
+ self.print(";")
202
+
203
+ def next_indent(self):
204
+ return self._indentation + self.options.indent_level
205
+
206
+ def spaced(self):
207
+ for v'var i=0; i < arguments.length; i++':
208
+ if i > 0:
209
+ self.space()
210
+ if jstype(arguments[i].print) is 'function':
211
+ arguments[i].print(self)
212
+ else:
213
+ self.print(arguments[i])
214
+
215
+ def end_statement(self):
216
+ self.semicolon()
217
+ self.newline()
218
+
219
+ def with_block(self, cont):
220
+ ret = None
221
+ self.print("{")
222
+ self.newline()
223
+ self.with_indent(self.next_indent(), def():
224
+ nonlocal ret
225
+ ret = cont()
226
+ )
227
+ self.indent()
228
+ self.print("}")
229
+ return ret
230
+
231
+ def with_parens(self, cont):
232
+ self.print("(")
233
+ ret = cont()
234
+ self.print(")")
235
+ return ret
236
+
237
+ def with_square(self, cont):
238
+ self.print("[")
239
+ ret = cont()
240
+ self.print("]")
241
+ return ret
242
+
243
+ def comma(self):
244
+ self.print(",")
245
+ self.space()
246
+
247
+ def colon(self):
248
+ self.print(":")
249
+ if self.options.space_colon:
250
+ self.space()
251
+
252
+ def dump_yield(self):
253
+ self.indent()
254
+ self.spaced('var', 'ρσ_regenerator', '=', '{}')
255
+ self.end_statement()
256
+ code = 'ρσ_regenerator.regeneratorRuntime = ' + regenerate(False, self.options.beautify)
257
+ if self.options.beautify:
258
+ code = code.replace(/\/\/.*$/mg, '\n').replace(/^\s*$/gm, '') # strip comments
259
+ ci = self.make_indent(0)
260
+ code = [ci + x for x in code.split('\n')].join('\n')
261
+ self.print(code + '})(ρσ_regenerator)')
262
+ self.end_statement()
263
+
264
+ def get(self):
265
+ return self.OUTPUT
266
+ toString = get
267
+
268
+ def assign(self, name):
269
+ # generates: '[name] = '
270
+ if jstype(name) is "string":
271
+ self.print(name)
272
+ else:
273
+ name.print(self)
274
+ self.space()
275
+ self.print("=")
276
+ self.space()
277
+
278
+ def current_width(self):
279
+ return self.current_col - self._indentation
280
+
281
+ def should_break(self):
282
+ return self.options.width and self.current_width() >= self.options.width
283
+
284
+ def last(self):
285
+ return self._last
286
+
287
+ def print_string(self, str_):
288
+ self.print(encode_string(str_))
289
+
290
+ def line(self):
291
+ return self.current_line
292
+
293
+ def col(self):
294
+ return self.current_col
295
+
296
+ def pos(self):
297
+ return self.current_pos
298
+
299
+ def push_node(self, node):
300
+ self._stack.push(node)
301
+
302
+ def pop_node(self):
303
+ return self._stack.pop()
304
+
305
+ def stack(self):
306
+ return self._stack
307
+
308
+ def parent(self, n):
309
+ return self._stack[self._stack.length - 2 - (n or 0)]
@@ -0,0 +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
@@ -0,0 +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'))