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