Implement Array.splice method
[vadmium-streams.git] / javascript / dump.py
blobd2310f294a883e863a88b405e92407f73537e7c6
1 from . import parse
2 from . import OP_PRECEDENCE, UNARY_PRECEDENCE, is_identifier, RESERVED_WORDS
3 from math import inf, ceil, log10
5 def dump(reader):
6 dump_block(parse(reader))
8 def dump_block(block, level=0):
9 for stmt in block:
10 if stmt[0] or not isinstance(stmt[1], tuple) \
11 or stmt[1][0] != 'block' or stmt[1][1]:
12 dump_stmt(stmt, level)
14 def dump_stmt(stmt, level):
15 [labels, stmt] = stmt
16 for label in labels:
17 print(f'{(level - 1) * " "}{label}:')
18 print(end=level * ' ')
19 if isinstance(stmt, tuple):
20 if stmt[0] == 'var':
21 dump_var(stmt, level)
22 elif stmt[0] in {'return', 'throw'}:
23 [stmt, expr] = stmt
24 print(end=stmt)
25 if expr != ('undefined',):
26 print(end=' ')
27 dump_expr(expr, level=level)
28 elif stmt[0] == 'for':
29 [init, test, final, stmt] = stmt[1:]
30 if init == final == ('undefined',) and test is not True:
31 print(end='while (')
32 dump_expr(test, level=level)
33 else:
34 dump_for(init, level)
35 print(end='; ')
36 if test is not True:
37 dump_expr(test, level=level)
38 print(end='; ')
39 if final != ('undefined',):
40 dump_expr(final, level=level)
41 dump_substmt(')', stmt, level)
42 return
43 elif stmt[0] == 'block':
44 print('{')
45 [stmt] = stmt[1:]
46 dump_block(stmt, level + 1)
47 print(f'{level * " "}}}')
48 return
49 elif stmt[0] == 'if':
50 print(end='if (')
51 [cond, true, false] = stmt[1:]
52 dump_expr(cond, level=level)
53 dump_substmt(')', true, level)
54 if false[0] or false[1][0] != 'block' or false[1][1]:
55 dump_substmt(f'{level * " "}else', false, level)
56 return
57 elif stmt[0] in {'break', 'continue'}:
58 [stmt, label] = stmt
59 print(end=stmt)
60 if label is not None:
61 print(end=f' {label}')
62 elif stmt[0] == 'for in':
63 [var, iter, stmt] = stmt[1:]
64 dump_for(var, level)
65 print(end=' in ')
66 dump_expr(iter, level=level)
67 dump_substmt(')', stmt, level)
68 return
69 elif stmt[0] == 'try':
70 print('try {')
71 [block, exc, catch, finally_block] = stmt[1:]
72 dump_block(block, level + 1)
73 if exc is not None:
74 print(f'{level * " "}}} catch ({exc}) {{')
75 dump_block(catch, level + 1)
76 if finally_block or exc is None:
77 print(f'{level * " "}}} finally {{')
78 dump_block(finally_block, level + 1)
79 print(f'{level * " "}}}')
80 return
81 elif stmt[0] == 'function':
82 dump_function(stmt, level)
83 print()
84 return
85 elif stmt[0] == 'do':
86 [stmt, expr] = stmt[1:]
87 dump_substmt('do', stmt, level)
88 print(end=f'{level * " "}while (')
89 dump_expr(expr, level=level)
90 print(end=')')
91 elif stmt[0] == 'switch':
92 [expr, cases] = stmt[1:]
93 print(end='switch (')
94 dump_expr(expr, level=level)
95 print(') {')
96 for [case, stmts] in cases:
97 if case == ('undefined',):
98 print(end=f'{level * " "}default')
99 else:
100 print(end=f'{level * " "}case ')
101 dump_expr(case, level=level)
102 print(':')
103 dump_block(stmts, level + 1)
104 print(f'{level * " "}}}')
105 return
106 else:
107 dump_expr(stmt, disallow={'function', 'object'}, level=level)
108 else:
109 dump_expr(stmt, disallow={'function', 'object'}, level=level)
110 print(';')
112 def dump_substmt(code, stmt, level):
113 print(end=code)
114 [labels, instruct] = stmt
115 if instruct[0] != 'block':
116 print()
117 dump_stmt(stmt, level + 1)
118 elif labels:
119 print()
120 dump_stmt(stmt, level)
121 else:
122 print(' {')
123 [stmt] = instruct[1:]
124 dump_block(stmt, level + 1)
125 print(f'{level * " "}}}')
127 def dump_for(init, level):
128 print(end='for (')
129 if isinstance(init, tuple) and init[:1] == ('var',):
130 dump_var(init, level, disallow={'in'})
131 elif init != ('undefined',):
132 dump_expr(init, level=level, disallow={'in'})
134 def dump_var(stmt, level, *, disallow=frozenset()):
135 print(end='var ')
136 [vars] = stmt[1:]
137 for [i, [name, expr]] in enumerate(vars):
138 if i > 0:
139 print(end=', ')
140 print(end=name)
141 if expr != ('undefined',):
142 print(end=' = ')
143 dump_expr(expr, OP_PRECEDENCE[','], level=level)
145 def dump_expr(expr, precedence=-inf, *,
146 disallow=frozenset(), level, disallow_nullary_new=False):
147 if isinstance(expr, float):
148 print(end=format(expr, f'.{ceil(log10(2) * 52) + 1}g'))
149 elif isinstance(expr, str):
150 print(end=repr(expr))
151 elif isinstance(expr, list):
152 print(end='[')
153 for [i, elem] in enumerate(expr):
154 if elem == ('undefined',):
155 if i == 0:
156 print(end=' ')
157 else:
158 dump_expr(elem, OP_PRECEDENCE[','], level=level)
159 if i < len(expr) - 1 or elem == ('undefined',):
160 print(end=',')
161 if i < len(expr) - 1:
162 print(end=' ')
163 print(end=']')
164 elif isinstance(expr, tuple):
165 if expr[0].startswith('prefix '):
166 p = UNARY_PRECEDENCE
167 else:
168 p = OP_PRECEDENCE.get(expr[0], +inf)
169 if p <= precedence or expr[0] in disallow \
170 or disallow_nullary_new and expr[0] == 'new' and not expr[2]:
171 print(end='(')
172 precedence = -inf
173 disallow = frozenset()
174 end = ')'
175 else:
176 end = ''
177 if expr[0] == 'call':
178 [expr, args] = expr[1:]
179 dump_expr(expr, UNARY_PRECEDENCE, disallow=disallow, level=level,
180 disallow_nullary_new=True)
181 dump_args(args, level)
182 elif expr[0] == 'function':
183 dump_function(expr, level)
184 elif expr[0] == 'object':
185 [items] = expr[1:]
186 print(end='{')
187 for [i, [name, expr]] in enumerate(items):
188 if i > 0:
189 print(end=', ')
190 if is_unreserved_ident(name):
191 print(end=name)
192 else:
193 dump_expr(name, level=level)
194 print(end=': ')
195 dump_expr(expr, OP_PRECEDENCE[','], level=level)
196 print(end='}')
197 elif expr[0] == 'this':
198 print(end='this')
199 elif expr[0] in OP_PRECEDENCE:
200 rhs = OP_PRECEDENCE[expr[0]]
201 if rhs == OP_PRECEDENCE['=']:
202 lhs = rhs
203 rhs = lhs - 1
204 else:
205 lhs = rhs - 1
206 dump_expr(expr[1], precedence=lhs, disallow=disallow, level=level)
207 if expr[0] != ',':
208 print(end=' ')
209 print(end=f'{expr[0]} ')
210 disallow = disallow - {'function', 'object'}
211 dump_expr(expr[2], precedence=rhs, disallow=disallow, level=level)
212 elif expr[0] == 'identifier':
213 [name] = expr[1:]
214 print(end=name)
215 elif expr[0] == 'property':
216 dump_expr(expr[1], UNARY_PRECEDENCE, level=level,
217 disallow_nullary_new=True)
218 if is_unreserved_ident(expr[2]):
219 print(end=f'.{expr[2]}')
220 else:
221 print(end='[')
222 dump_expr(expr[2], level=level)
223 print(end=']')
224 elif expr[0] == '?':
225 dump_expr(expr[1], OP_PRECEDENCE['='],
226 disallow=disallow, level=level)
227 print(end='? ')
228 dump_expr(expr[2], OP_PRECEDENCE[','], level=level)
229 print(end=' : ')
230 dump_expr(expr[3], OP_PRECEDENCE[','],
231 disallow=disallow - {'function', 'object'}, level=level)
232 elif expr[0].startswith('prefix '):
233 [op, expr] = expr
234 if op == 'prefix !' and isinstance(expr, (float, str, bool)):
235 print(end=repr(not expr).lower())
236 else:
237 print(end=op[len('prefix '):])
238 if op[len('prefix '):].isalnum():
239 print(end=' ')
240 dump_expr(expr, UNARY_PRECEDENCE, level=level)
241 elif expr[0].startswith('postfix '):
242 dump_expr(expr[1], UNARY_PRECEDENCE, level=level)
243 print(end=expr[0][len('postfix '):])
244 elif expr[0] == 'new':
245 print(end='new ')
246 [expr, args] = expr[1:]
247 if isinstance(expr, tuple) and expr[0].startswith('postfix '):
248 print(end='(')
249 dump_expr(expr, UNARY_PRECEDENCE, disallow={'call'}, level=level,
250 disallow_nullary_new=args)
251 if isinstance(expr, tuple) and expr[0].startswith('postfix '):
252 print(end=')')
253 if args:
254 dump_args(args, level)
255 elif expr[0] == 'regex':
256 [pattern, flags] = expr[1:]
257 print(end=f'/{pattern}/{flags}')
258 else:
259 raise NotImplementedError(expr)
260 print(end=end)
261 else:
262 LITERALS = {None: 'null', True: 'true', False: 'false'}
263 print(end=LITERALS[expr])
265 def dump_args(args, level):
266 print(end='(')
267 for [i, expr] in enumerate(args):
268 if i > 0:
269 print(end=', ')
270 dump_expr(expr, OP_PRECEDENCE[','], level=level)
271 print(end=')')
273 def dump_function(f, level):
274 [name, params, body] = f[1:]
275 if name is None:
276 name = ''
277 print(end=f'function {name}(')
278 for [i, name] in enumerate(params):
279 if i > 0:
280 print(end=', ')
281 print(end=name)
282 print(') {')
283 dump_block(body, level=level + 1)
284 print(end=f'{level * " "}}}')
286 def is_unreserved_ident(name):
287 return isinstance(name, str) and is_identifier(name) \
288 and name not in RESERVED_WORDS
290 if __name__ == '__main__':
291 from sys import stdin
292 dump(stdin)