rapydscript-ng 0.7.24 → 0.8.1
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/CHANGELOG.md +28 -0
- package/README.md +80 -26
- package/bin/build.ts +117 -0
- package/bin/package.json +1 -0
- package/bin/rapydscript +65 -62
- package/build_wheels.py +133 -0
- package/editor-plugins/README.md +80 -0
- package/editor-plugins/nvim.lua +321 -0
- package/local-agent.md +28 -0
- package/package.json +4 -5
- package/publish.py +27 -17
- package/release/baselib-plain-pretty.js +448 -326
- package/release/baselib-plain-ugly.js +3 -3
- package/release/compiler.js +9027 -8139
- package/release/signatures.json +27 -27
- package/release/stdlib_modules.json +1 -0
- package/src/ast.pyj +428 -280
- package/src/baselib-builtins.pyj +49 -28
- package/src/baselib-containers.pyj +241 -226
- package/src/baselib-errors.pyj +8 -1
- package/src/baselib-internal.pyj +38 -23
- package/src/baselib-itertools.pyj +13 -7
- package/src/baselib-str.pyj +59 -84
- package/src/compiler.pyj +4 -4
- package/src/errors.pyj +3 -4
- package/src/lib/aes.pyj +46 -32
- package/src/lib/elementmaker.pyj +11 -9
- package/src/lib/encodings.pyj +15 -5
- package/src/lib/gettext.pyj +9 -4
- package/src/lib/math.pyj +106 -45
- package/src/lib/operator.pyj +10 -10
- package/src/lib/pythonize.pyj +2 -1
- package/src/lib/random.pyj +28 -21
- package/src/lib/re.pyj +492 -19
- package/src/lib/traceback.pyj +171 -29
- package/src/lib/uuid.pyj +2 -2
- package/src/output/classes.pyj +28 -27
- package/src/output/codegen.pyj +87 -83
- package/src/output/comments.pyj +8 -8
- package/src/output/exceptions.pyj +20 -21
- package/src/output/functions.pyj +66 -64
- package/src/output/literals.pyj +24 -23
- package/src/output/loops.pyj +84 -142
- package/src/output/modules.pyj +55 -68
- package/src/output/operators.pyj +40 -29
- package/src/output/statements.pyj +21 -15
- package/src/output/stream.pyj +82 -56
- package/src/output/utils.pyj +12 -8
- package/src/parse.pyj +971 -620
- package/src/string_interpolation.pyj +5 -3
- package/src/tokenizer.pyj +188 -148
- package/src/utils.pyj +32 -15
- package/test/_treeshake_mod.pyj +30 -0
- package/test/_treeshake_side_effect.pyj +9 -0
- package/test/ast_serialization.pyj +392 -0
- package/test/async.pyj +95 -0
- package/test/baselib.pyj +1 -2
- package/test/embedded_compiler.pyj +57 -0
- package/test/fmt.pyj +291 -0
- package/test/generic.pyj +16 -3
- package/test/imports.pyj +8 -6
- package/test/internationalization.pyj +38 -37
- package/test/lint.pyj +120 -117
- package/test/lsp.pyj +257 -0
- package/test/repl.pyj +70 -65
- package/test/sourcemaps.pyj +315 -0
- package/test/starargs.pyj +46 -39
- package/test/str.pyj +8 -0
- package/test/traceback.pyj +263 -0
- package/test/treeshaking.pyj +181 -0
- package/test/web_repl_export.pyj +88 -0
- package/tools/ast_serialize.mjs +557 -0
- package/tools/cli.mjs +531 -0
- package/tools/compile.mjs +205 -0
- package/tools/compiler.mjs +159 -0
- package/tools/{completer.js → completer.mjs} +6 -6
- package/tools/{embedded_compiler.js → embedded_compiler.mjs} +17 -13
- package/tools/export.js +109 -56
- package/tools/fmt.mjs +975 -0
- package/tools/{gettext.js → gettext.mjs} +46 -53
- package/tools/ini.mjs +175 -0
- package/tools/{lint.js → lint.mjs} +78 -55
- package/tools/lsp.mjs +964 -0
- package/tools/lsp_protocol.mjs +259 -0
- package/tools/lsp_symbols.mjs +418 -0
- package/tools/{msgfmt.js → msgfmt.mjs} +18 -18
- package/tools/{repl.js → repl.mjs} +56 -42
- package/tools/{self.js → self.mjs} +71 -46
- package/tools/sourcemap.mjs +123 -0
- package/tools/test.mjs +252 -0
- package/tools/treeshake.mjs +400 -0
- package/tools/{utils.js → utils.mjs} +26 -23
- package/tools/{web_repl.js → web_repl.mjs} +15 -13
- package/tools/web_repl_export.mjs +97 -0
- package/tree-sitter/README.md +101 -0
- package/tree-sitter/grammar.js +992 -0
- package/tree-sitter/package.json +43 -0
- package/tree-sitter/queries/highlights.scm +232 -0
- package/tree-sitter/queries/indents.scm +64 -0
- package/tree-sitter/queries/injections.scm +14 -0
- package/tree-sitter/queries/locals.scm +108 -0
- package/tree-sitter/src/grammar.json +4976 -0
- package/tree-sitter/src/node-types.json +2901 -0
- package/tree-sitter/src/parser.c +196465 -0
- package/tree-sitter/src/scanner.c +294 -0
- package/tree-sitter/src/tree_sitter/alloc.h +54 -0
- package/tree-sitter/src/tree_sitter/array.h +330 -0
- package/tree-sitter/src/tree_sitter/parser.h +286 -0
- package/tree-sitter/test/corpus/chaining.txt +99 -0
- package/tree-sitter/test/corpus/classes.txt +147 -0
- package/tree-sitter/test/corpus/comprehensions.txt +155 -0
- package/tree-sitter/test/corpus/containers.txt +242 -0
- package/tree-sitter/test/corpus/control_flow.txt +361 -0
- package/tree-sitter/test/corpus/decorators.txt +64 -0
- package/tree-sitter/test/corpus/existential.txt +102 -0
- package/tree-sitter/test/corpus/functions.txt +293 -0
- package/tree-sitter/test/corpus/imports.txt +117 -0
- package/tree-sitter/test/corpus/literals.txt +135 -0
- package/tree-sitter/test/corpus/operators.txt +296 -0
- package/tree-sitter/test/corpus/statements.txt +189 -0
- package/tree-sitter/test/corpus/strings.txt +90 -0
- package/tree-sitter/test/corpus/subscripts.txt +227 -0
- package/tree-sitter/tree-sitter.json +36 -0
- package/web-repl/env.js +35 -23
- package/web-repl/main.js +8 -8
- package/bin/export +0 -75
- package/bin/web-repl-export +0 -102
- package/tools/cli.js +0 -523
- package/tools/compile.js +0 -184
- package/tools/compiler.js +0 -84
- package/tools/ini.js +0 -65
- package/tools/test.js +0 -110
package/src/output/stream.pyj
CHANGED
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
# vim:fileencoding=utf-8
|
|
2
2
|
# License: BSD Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
|
3
|
-
# globals:regenerate
|
|
4
3
|
from __python__ import hash_literals
|
|
5
4
|
|
|
6
|
-
from utils import make_predicate, defaults, repeat_string
|
|
7
5
|
from tokenizer import is_identifier_char
|
|
6
|
+
from utils import make_predicate, defaults, repeat_string
|
|
8
7
|
|
|
9
8
|
DANGEROUS = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g
|
|
10
9
|
|
|
10
|
+
# Pre-computed ASCII lookup for identifier characters used in the space-emission
|
|
11
|
+
# hot path. Avoids the full unicode-aware is_identifier_char() for the common case.
|
|
12
|
+
_IDENT_CHARS = v'(function(){var t=new Uint8Array(128),s="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$";for(var i=0;i<s.length;i++)t[s.charCodeAt(i)]=1;return t;})()'
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _is_ident_char(ch):
|
|
16
|
+
code = ch.charCodeAt(0)
|
|
17
|
+
if code < 128:
|
|
18
|
+
return v'_IDENT_CHARS[code]'
|
|
19
|
+
return is_identifier_char(ch)
|
|
20
|
+
|
|
11
21
|
|
|
12
22
|
def as_hex(code, sz):
|
|
13
23
|
val = code.toString(16)
|
|
@@ -17,20 +27,20 @@ def as_hex(code, sz):
|
|
|
17
27
|
|
|
18
28
|
|
|
19
29
|
def to_ascii(str_, identifier):
|
|
20
|
-
return str_.replace(/[\u0080-\uffff]/g, def(ch):
|
|
30
|
+
return str_.replace(/[\u0080-\uffff]/g, def (ch):
|
|
21
31
|
code = ch.charCodeAt(0).toString(16)
|
|
22
32
|
if code.length <= 2 and not identifier:
|
|
23
|
-
return
|
|
33
|
+
return '\\x' + as_hex(code, 2)
|
|
24
34
|
else:
|
|
25
35
|
return '\\u' + as_hex(code, 4)
|
|
26
|
-
|
|
27
36
|
)
|
|
28
37
|
|
|
38
|
+
|
|
29
39
|
def encode_string(str_):
|
|
30
|
-
return JSON.stringify(str_).replace(DANGEROUS, def(a):
|
|
40
|
+
return JSON.stringify(str_).replace(DANGEROUS, def (a):
|
|
31
41
|
return '\\u' + as_hex(a.charCodeAt(0), 4)
|
|
32
42
|
)
|
|
33
|
-
require_semi_colon_chars = make_predicate(
|
|
43
|
+
require_semi_colon_chars = make_predicate('( [ + * / - , .')
|
|
34
44
|
|
|
35
45
|
output_stream_defaults = {
|
|
36
46
|
'indent_start': 0,
|
|
@@ -43,6 +53,7 @@ output_stream_defaults = {
|
|
|
43
53
|
'ie_proof': True,
|
|
44
54
|
'beautify': False,
|
|
45
55
|
'source_map': None,
|
|
56
|
+
'source_map_line_offset': 0,
|
|
46
57
|
'bracketize': False,
|
|
47
58
|
'semicolons': True,
|
|
48
59
|
'comments': False,
|
|
@@ -53,26 +64,34 @@ output_stream_defaults = {
|
|
|
53
64
|
'keep_docstrings': False,
|
|
54
65
|
'discard_asserts': False,
|
|
55
66
|
'module_cache_dir': '',
|
|
56
|
-
'js_version':
|
|
67
|
+
'js_version': 6,
|
|
57
68
|
'write_name': True,
|
|
58
69
|
}
|
|
59
70
|
|
|
60
|
-
class OutputStream:
|
|
61
71
|
|
|
72
|
+
class OutputStream:
|
|
62
73
|
def __init__(self, options):
|
|
63
74
|
self.options = defaults(options, output_stream_defaults, True)
|
|
64
75
|
self._indentation = 0
|
|
65
76
|
self.current_col = 0
|
|
66
77
|
self.current_line = 1
|
|
67
78
|
self.current_pos = 0
|
|
68
|
-
self.
|
|
79
|
+
self._fragments = v'[]'
|
|
69
80
|
self.might_need_space = False
|
|
70
81
|
self.might_need_semicolon = False
|
|
71
82
|
self._last = None
|
|
72
|
-
self._stack = []
|
|
83
|
+
self._stack = v'[]'
|
|
73
84
|
self.index_counter = 0
|
|
74
85
|
self.with_counter = 0
|
|
75
86
|
self.try_else_counter = 0
|
|
87
|
+
self._source_map_segments = v'[]' if self.options.source_map else None
|
|
88
|
+
# Indentation string cache: avoids repeat_string() on every indent() call
|
|
89
|
+
self._indent_cache_val = -1
|
|
90
|
+
self._indent_cache_str = ''
|
|
91
|
+
# Install no-op add_mapping on the instance when source maps are disabled,
|
|
92
|
+
# avoiding a null check and array push per node in the hot output walk.
|
|
93
|
+
if not self.options.source_map:
|
|
94
|
+
self.add_mapping = def (node): pass
|
|
76
95
|
|
|
77
96
|
def new_try_else_counter(self):
|
|
78
97
|
self.try_else_counter += 1
|
|
@@ -89,7 +108,13 @@ class OutputStream:
|
|
|
89
108
|
self.print(self.make_name(name))
|
|
90
109
|
|
|
91
110
|
def make_indent(self, back):
|
|
92
|
-
|
|
111
|
+
target = self.options.indent_start + self._indentation - (back or 0) * self.options.indent_level
|
|
112
|
+
if target == self._indent_cache_val:
|
|
113
|
+
return self._indent_cache_str
|
|
114
|
+
s = repeat_string(' ', target)
|
|
115
|
+
self._indent_cache_val = target
|
|
116
|
+
self._indent_cache_str = s
|
|
117
|
+
return s
|
|
93
118
|
|
|
94
119
|
# -----[ beautification/minification ]-----
|
|
95
120
|
def last_char(self):
|
|
@@ -97,19 +122,19 @@ class OutputStream:
|
|
|
97
122
|
|
|
98
123
|
def maybe_newline(self):
|
|
99
124
|
if self.options.max_line_len and self.current_col > self.options.max_line_len:
|
|
100
|
-
self.print(
|
|
125
|
+
self.print('\n')
|
|
101
126
|
|
|
102
127
|
def print(self, str_):
|
|
103
128
|
str_ = v"String(str_)"
|
|
104
129
|
ch = str_.charAt(0)
|
|
105
130
|
if self.might_need_semicolon:
|
|
106
|
-
if (not ch or
|
|
131
|
+
if (not ch or ';}'.indexOf(ch) < 0) and not /[;]$/.test(self._last):
|
|
107
132
|
if self.options.semicolons or require_semi_colon_chars[ch]:
|
|
108
|
-
self.
|
|
133
|
+
self._fragments.push(';')
|
|
109
134
|
self.current_col += 1
|
|
110
135
|
self.current_pos += 1
|
|
111
136
|
else:
|
|
112
|
-
self.
|
|
137
|
+
self._fragments.push('\n')
|
|
113
138
|
self.current_pos += 1
|
|
114
139
|
self.current_line += 1
|
|
115
140
|
self.current_col = 0
|
|
@@ -117,41 +142,41 @@ class OutputStream:
|
|
|
117
142
|
if not self.options.beautify:
|
|
118
143
|
self.might_need_space = False
|
|
119
144
|
|
|
120
|
-
|
|
121
145
|
self.might_need_semicolon = False
|
|
122
146
|
self.maybe_newline()
|
|
123
147
|
|
|
124
148
|
if not self.options.beautify and self.options.preserve_line and self._stack[self._stack.length - 1]:
|
|
125
149
|
target_line = self._stack[self._stack.length - 1].start.line
|
|
126
150
|
while self.current_line < target_line:
|
|
127
|
-
self.
|
|
151
|
+
self._fragments.push('\n')
|
|
128
152
|
self.current_pos += 1
|
|
129
153
|
self.current_line += 1
|
|
130
154
|
self.current_col = 0
|
|
131
155
|
self.might_need_space = False
|
|
132
156
|
|
|
133
|
-
|
|
134
157
|
if self.might_need_space:
|
|
135
158
|
prev = self.last_char()
|
|
136
|
-
if
|
|
159
|
+
if _is_ident_char(prev) and (_is_ident_char(ch) or ch is '\\')
|
|
137
160
|
or /^[\+\-\/]$/.test(ch) and ch is prev:
|
|
138
|
-
self.
|
|
161
|
+
self._fragments.push(' ')
|
|
139
162
|
self.current_col += 1
|
|
140
163
|
self.current_pos += 1
|
|
141
164
|
|
|
142
165
|
self.might_need_space = False
|
|
143
166
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
self.
|
|
147
|
-
if n
|
|
148
|
-
self.current_col +=
|
|
167
|
+
# Fast path: no newlines (the vast majority of tokens).
|
|
168
|
+
# Avoids regex allocation and array creation for single-line fragments.
|
|
169
|
+
self.current_pos += str_.length
|
|
170
|
+
if str_.indexOf('\n') < 0:
|
|
171
|
+
self.current_col += str_.length
|
|
149
172
|
else:
|
|
150
|
-
|
|
173
|
+
a = str_.split('\n')
|
|
174
|
+
n = a.length - 1
|
|
175
|
+
self.current_line += n
|
|
176
|
+
self.current_col = v'a[n].length'
|
|
151
177
|
|
|
152
|
-
self.current_pos += str_.length
|
|
153
178
|
self._last = str_
|
|
154
|
-
self.
|
|
179
|
+
self._fragments.push(str_)
|
|
155
180
|
|
|
156
181
|
def space(self):
|
|
157
182
|
if self.options.beautify:
|
|
@@ -185,17 +210,17 @@ class OutputStream:
|
|
|
185
210
|
|
|
186
211
|
def newline(self):
|
|
187
212
|
if self.options.beautify:
|
|
188
|
-
self.print(
|
|
213
|
+
self.print('\n')
|
|
189
214
|
|
|
190
215
|
def semicolon(self):
|
|
191
216
|
if self.options.beautify:
|
|
192
|
-
self.print(
|
|
217
|
+
self.print(';')
|
|
193
218
|
else:
|
|
194
219
|
self.might_need_semicolon = True
|
|
195
220
|
|
|
196
221
|
def force_semicolon(self):
|
|
197
222
|
self.might_need_semicolon = False
|
|
198
|
-
self.print(
|
|
223
|
+
self.print(';')
|
|
199
224
|
|
|
200
225
|
def next_indent(self):
|
|
201
226
|
return self._indentation + self.options.indent_level
|
|
@@ -215,61 +240,49 @@ class OutputStream:
|
|
|
215
240
|
|
|
216
241
|
def with_block(self, cont):
|
|
217
242
|
ret = None
|
|
218
|
-
self.print(
|
|
243
|
+
self.print('{')
|
|
219
244
|
self.newline()
|
|
220
|
-
self.with_indent(self.next_indent(), def():
|
|
245
|
+
self.with_indent(self.next_indent(), def ():
|
|
221
246
|
nonlocal ret
|
|
222
247
|
ret = cont()
|
|
223
248
|
)
|
|
224
249
|
self.indent()
|
|
225
|
-
self.print(
|
|
250
|
+
self.print('}')
|
|
226
251
|
return ret
|
|
227
252
|
|
|
228
253
|
def with_parens(self, cont):
|
|
229
|
-
self.print(
|
|
254
|
+
self.print('(')
|
|
230
255
|
ret = cont()
|
|
231
|
-
self.print(
|
|
256
|
+
self.print(')')
|
|
232
257
|
return ret
|
|
233
258
|
|
|
234
259
|
def with_square(self, cont):
|
|
235
|
-
self.print(
|
|
260
|
+
self.print('[')
|
|
236
261
|
ret = cont()
|
|
237
|
-
self.print(
|
|
262
|
+
self.print(']')
|
|
238
263
|
return ret
|
|
239
264
|
|
|
240
265
|
def comma(self):
|
|
241
|
-
self.print(
|
|
266
|
+
self.print(',')
|
|
242
267
|
self.space()
|
|
243
268
|
|
|
244
269
|
def colon(self):
|
|
245
|
-
self.print(
|
|
270
|
+
self.print(':')
|
|
246
271
|
if self.options.space_colon:
|
|
247
272
|
self.space()
|
|
248
273
|
|
|
249
|
-
def dump_yield(self):
|
|
250
|
-
self.indent()
|
|
251
|
-
self.spaced('var', 'ρσ_regenerator', '=', '{}')
|
|
252
|
-
self.end_statement()
|
|
253
|
-
code = 'ρσ_regenerator.regeneratorRuntime = ' + regenerate(False, self.options.beautify)
|
|
254
|
-
if self.options.beautify:
|
|
255
|
-
code = code.replace(/\/\/.*$/mg, '\n').replace(/^\s*$/gm, '') # strip comments
|
|
256
|
-
ci = self.make_indent(0)
|
|
257
|
-
code = [ci + x for x in code.split('\n')].join('\n')
|
|
258
|
-
self.print(code + '})(ρσ_regenerator)')
|
|
259
|
-
self.end_statement()
|
|
260
|
-
|
|
261
274
|
def get(self):
|
|
262
|
-
return self.
|
|
275
|
+
return self._fragments.join('')
|
|
263
276
|
toString = get
|
|
264
277
|
|
|
265
278
|
def assign(self, name):
|
|
266
279
|
# generates: '[name] = '
|
|
267
|
-
if jstype(name) is
|
|
280
|
+
if jstype(name) is 'string':
|
|
268
281
|
self.print(name)
|
|
269
282
|
else:
|
|
270
283
|
name.print(self)
|
|
271
284
|
self.space()
|
|
272
|
-
self.print(
|
|
285
|
+
self.print('=')
|
|
273
286
|
self.space()
|
|
274
287
|
|
|
275
288
|
def current_width(self):
|
|
@@ -304,3 +317,16 @@ class OutputStream:
|
|
|
304
317
|
|
|
305
318
|
def parent(self, n):
|
|
306
319
|
return self._stack[self._stack.length - 2 - (n or 0)]
|
|
320
|
+
|
|
321
|
+
def add_mapping(self, node):
|
|
322
|
+
if self._source_map_segments is not None and node.start and node.start.file:
|
|
323
|
+
self._source_map_segments.push(v'[self.current_line - 1 + self.options.source_map_line_offset, self.current_col, node.start.file, node.start.line - 1, node.start.col]')
|
|
324
|
+
|
|
325
|
+
def add_cached_mappings(self, segments, line_offset):
|
|
326
|
+
if self._source_map_segments is None:
|
|
327
|
+
return
|
|
328
|
+
for seg in segments:
|
|
329
|
+
self._source_map_segments.push(v'[seg[0] + line_offset, seg[1], seg[2], seg[3], seg[4]]')
|
|
330
|
+
|
|
331
|
+
def get_source_map_segments(self):
|
|
332
|
+
return self._source_map_segments
|
package/src/output/utils.pyj
CHANGED
|
@@ -4,6 +4,7 @@ from __python__ import hash_literals
|
|
|
4
4
|
|
|
5
5
|
from ast import AST_BlockStatement, is_node_type
|
|
6
6
|
|
|
7
|
+
|
|
7
8
|
def best_of(a):
|
|
8
9
|
best = a[0]
|
|
9
10
|
len_ = best.length
|
|
@@ -13,38 +14,41 @@ def best_of(a):
|
|
|
13
14
|
len_ = best.length
|
|
14
15
|
return best
|
|
15
16
|
|
|
17
|
+
|
|
16
18
|
def make_num(num):
|
|
17
19
|
str_ = num.toString(10)
|
|
18
|
-
a = [
|
|
20
|
+
a = [str_.replace(/^0\./, '.').replace('e+', 'e')]
|
|
19
21
|
m = None
|
|
20
22
|
|
|
21
23
|
if Math.floor(num) is num:
|
|
22
24
|
if num >= 0:
|
|
23
|
-
a.push(
|
|
24
|
-
|
|
25
|
+
a.push('0x' + num.toString(16).toLowerCase(), # probably pointless
|
|
26
|
+
'0' + num.toString(8))
|
|
25
27
|
else:
|
|
26
|
-
a.push(
|
|
27
|
-
|
|
28
|
+
a.push('-0x' + (-num).toString(16).toLowerCase(), # probably pointless
|
|
29
|
+
'-0' + (-num).toString(8))
|
|
28
30
|
|
|
29
31
|
if m = /^(.*?)(0+)$/.exec(num):
|
|
30
|
-
a.push(m[1] +
|
|
32
|
+
a.push(m[1] + 'e' + m[2].length)
|
|
31
33
|
|
|
32
34
|
elif m = /^0?\.(0+)(.*)$/.exec(num):
|
|
33
|
-
a.push(m[2] +
|
|
35
|
+
a.push(m[2] + 'e-' + (m[1].length + m[2].length), str_.substr(str_.indexOf('.')))
|
|
34
36
|
|
|
35
37
|
return best_of(a)
|
|
36
38
|
|
|
39
|
+
|
|
37
40
|
def make_block(stmt, output):
|
|
38
41
|
if is_node_type(stmt, AST_BlockStatement):
|
|
39
42
|
stmt.print(output)
|
|
40
43
|
return
|
|
41
44
|
|
|
42
|
-
output.with_block(def():
|
|
45
|
+
output.with_block(def ():
|
|
43
46
|
output.indent()
|
|
44
47
|
stmt.print(output)
|
|
45
48
|
output.newline()
|
|
46
49
|
)
|
|
47
50
|
|
|
51
|
+
|
|
48
52
|
def create_doctring(docstrings):
|
|
49
53
|
ans = v'[]'
|
|
50
54
|
for ds in docstrings:
|