xref: /inferno-os/appl/lib/ecmascript/pprint.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1PPrint: adt
2{
3	ex:	ref Exec;
4	code:	ref Code;
5	stack:	array of string;
6	sp:	int;
7};
8
9mkpprint(ex: ref Exec, code: ref Code): ref PPrint
10{
11	return ref PPrint(ex, code, array[4] of string, 0);
12}
13
14funcprint(ex: ref Exec, func: ref Ecmascript->Obj): string
15{
16	params := func.call.params;
17	(nil, name) := str->splitr(func.val.str, ".");
18	s := "function " + name + "(";
19	sep := "";
20	for(i := 0; i < len params; i++){
21		s += sep + params[i];
22		sep = ", ";
23	}
24	s += "){";
25	if(func.host != nil)
26		s += "[host code]";
27	else
28		s += "\n" + pprint(ex, func.call.code, "	");
29	s += "}";
30	return s;
31}
32
33pprint(ex: ref Exec, code: ref Code, indent: string): string
34{
35	pp := ref PPrint(ex, code, array[4] of string, 0);
36#for(i:=0; i < code.npc; i++) sys->print("%d: %d\n", i, int code.ops[i]);
37	s := pstmt(pp, 0, code.npc, indent);
38
39	if(pp.sp != 0)
40		fatal(ex, "pprint stack not balanced");
41
42	return s;
43}
44
45pstmt(pp: ref PPrint, pc, epc: int, indent: string): string
46{
47	e, e1, e2: string;
48	c, apc: int;
49
50	code := pp.code;
51	s := "";
52	while(pc < epc){
53		op := int code.ops[pc++];
54		while(op == Llabel){
55			(pc, c) = getconst(code.ops, pc);
56			s += code.strs[c] + ":\n";
57			op = int code.ops[pc++];
58		}
59		s += indent;
60		case op{
61		Lbreak or
62		Lcontinue or
63		Lreturn =>
64			s += tokname(op);
65			if(op == Lreturn){
66				(pc, e) = pexp(pp, pc, code.npc);
67				s += " " + e;
68			}
69			s += ";\n";
70		Lbreaklab or
71		Lcontinuelab =>
72			s += tokname(op);
73			(pc, c) = getconst(code.ops, pc);
74			s += " " + code.strs[c] + ";\n";
75		'{' =>
76			(pc, apc) = getjmp(code.ops, pc);
77			s += "{\n" + pstmt(pp, pc, apc, indent+"	") + indent + "}\n";
78			pc = apc;
79		Lif or
80		Lwith or
81		Lwhile =>
82			(pc, apc) = getjmp(code.ops, pc);
83			(pc, e) = pexp(pp, pc, apc);
84			(pc, apc) = getjmp(code.ops, pc);
85			s += tokname(op) + "(" + e + "){\n";
86			s += pstmt(pp, pc, apc, indent+"	");
87			if(op == Lif){
88				(pc, apc) = getjmp(code.ops, apc);
89				if(pc != apc)
90					s += indent + "}else{\n";
91				s += pstmt(pp, pc, apc, indent+"	");
92			}
93			s += indent + "}\n";
94			pc = apc;
95		Ldo =>
96			(pc, apc) = getjmp(code.ops, pc);
97			e = pstmt(pp, pc, apc, indent+"	");
98			(pc, apc) = getjmp(code.ops, apc);
99			(pc, e1) = pexp(pp, pc, apc);
100			s += "do{\n" + e + indent + "}(while(" + e1 + ");\n";
101			pc = apc;
102		Lfor or
103		Lforvar or
104		Lforin or
105		Lforvarin =>
106			(pc, apc) = getjmp(code.ops, pc);
107			(pc, e) = pexp(pp, pc, apc);
108			(pc, apc) = getjmp(code.ops, pc);
109			(pc, e1) = pexp(pp, pc, apc);
110			s += "for(";
111			if(op == Lforvar || op == Lforvarin)
112				s += "var ";
113			s += e;
114			if(op == Lfor || op == Lforvar){
115				(pc, apc) = getjmp(code.ops, pc);
116				(pc, e2) = pexp(pp, pc, apc);
117				s += "; " + e1 + "; " + e2;
118			}else
119				s += " in " + e1;
120			s += "){\n";
121			(pc, apc) = getjmp(code.ops, pc);
122			s += pstmt(pp, pc, apc, indent+"	");
123			s += indent + "}\n";
124			pc = apc;
125		';' =>
126			s += ";\n";
127		Lvar =>
128			(pc, apc) = getjmp(code.ops, pc);
129			(pc, e) = pexp(pp, pc, apc);
130			s += "var " + e + ";\n";
131		Lswitch =>
132			(pc, apc) = getjmp(code.ops, pc);
133			(pc, e) = pexp(pp, pc, apc);
134			s += "switch (" + e + ") {\n";
135			(pc, apc) = getjmp(code.ops, pc);
136			(pc, e) = pcaseblk(pp, pc, apc, indent);
137			s  += e + indent + "}\n";
138			pc = apc;
139		Lthrow =>
140			(pc, e) = pexp(pp, pc, code.npc);
141			s += "throw " + e + "\n";
142		Ltry =>
143			s += "try\n";
144			(pc, apc) = getjmp(code.ops, pc);
145			s += pstmt(pp, pc, apc, indent+"	");
146			(pc, apc) = getjmp(code.ops, apc);
147			if(pc != apc){
148				(pc, c) = getconst(code.ops, ++pc);
149				s += "catch(" + code.strs[c] + ")\n";
150				s += pstmt(pp, pc, apc, indent+"	");
151			}
152			(pc, apc) = getjmp(code.ops, apc);
153			if(pc != apc){
154				s += "finally\n";
155				s += pstmt(pp, pc, apc, indent+"	");
156			}
157			pc = apc;
158		* =>
159			(pc, e) = pexp(pp, pc-1, code.npc);
160			s += e + ";\n";
161		}
162	}
163	return s;
164}
165
166pexp(pp: ref PPrint, pc, epc: int): (int, string)
167{
168	c, apc: int;
169	s, f, a, a1, a2: string;
170
171	code := pp.code;
172	savesp := pp.sp;
173out:	while(pc < epc){
174		case op := int code.ops[pc++]{
175		Lthis =>
176			s = "this";
177		Lid or
178		Lnum or
179		Lstr or
180		Lregexp =>
181			(pc, c) = getconst(code.ops, pc);
182			if(op == Lnum)
183				s = string code.nums[c];
184			else{
185				s = code.strs[c];
186				if(op == Lstr)
187					s = "\""+escstr(code.strs[c])+"\"";
188			}
189		'*' or
190		'/' or
191		'%' or
192		'+' or
193		'-' or
194		Llsh or
195		Lrsh or
196		Lrshu or
197		'<' or
198		'>' or
199		Lleq or
200		Lgeq or
201		Lin or
202		Linstanceof or
203		Leq or
204		Lneq or
205		Lseq or
206		Lsne or
207		'&' or
208		'^' or
209		'|' or
210		'=' or
211		'.' or
212		',' or
213		'[' =>
214			a2 = ppop(pp);
215			a1 = ppop(pp);
216			s = tokname(op);
217			if(a1[0] == '='){
218				s += "=";
219				a1 = a1[1:];
220			}
221			if(op == '[')
222				s = a1 + "[" + a2 + "]";
223			else{
224				if(op != '.'){
225					if(op != ',')
226						s = " " + s;
227					s = s + " ";
228				}
229				s = a1 + s + a2;
230			}
231		Ltypeof or
232		Ldelete or
233		Lvoid or
234		Lnew or
235		Linc or
236		Ldec or
237		Lpreadd or
238		Lpresub or
239		'~' or
240		'!' or
241		Lpostinc or
242		Lpostdec =>
243			a = ppop(pp);
244			s = tokname(op);
245			if(op == Lpostinc || op == Lpostdec)
246				s = a + s;
247			else{
248				if(op == Ltypeof || op == Ldelete || op == Lvoid || op == Lnew)
249					s += " ";
250				s += a;
251			}
252		'(' =>
253			s = "(";
254		')' =>
255			s = ppop(pp);
256			if(ppop(pp) != "(")
257				fatal(pp.ex, "unbalanced () in pexp");
258			s = "(" + s + ")";
259		Lgetval or
260		Las =>
261			continue;
262		Lasop =>
263			s = "=" + ppop(pp);
264		Lcall or
265		Lnewcall =>
266			(pc, c) = getconst(code.ops, pc);
267			a = "";
268			sep := "";
269			for(sp := pp.sp-c; sp < pp.sp; sp++){
270				a += sep + pp.stack[sp];
271				sep = ", ";
272			}
273			pp.sp -= c;
274			f = ppop(pp);
275			if(op == Lnewcall)
276				f = "new " + f;
277			s = f + "(" + a + ")";
278		';' =>
279			break out;
280		Landand or
281		Loror or
282		'?' =>
283			s = ppop(pp);
284			(pc, apc) = getjmp(code.ops, pc);
285			(pc, a1) = pexp(pp, pc, apc);
286			s += " " + tokname(op) + " " + a1;
287			if(op == '?'){
288				(pc, apc) = getjmp(code.ops, pc);
289				(pc, a2) = pexp(pp, pc, apc);
290				s += " : "+ a2;
291			}
292		* =>
293			fatal(pp.ex, "pexp: unknown op " + tokname(op));
294		}
295		ppush(pp, s);
296	}
297
298	if(savesp == pp.sp)
299		return (pc, "");
300
301	if(savesp != pp.sp-1)
302		fatal(pp.ex, "unbalanced stack in pexp");
303	return (pc, ppop(pp));
304}
305
306pcaseblk(pp: ref PPrint, pc, epc: int, indent: string): (int, string)
307{
308	code := pp.code;
309	defpc, clausepc, nextpc, apc: int;
310	s, a: string;
311
312	(pc, defpc) = getjmp(code.ops, pc);
313	clausepc = pc;
314	(pc, nextpc) = getjmp(code.ops, pc);
315	for (; pc < epc; (clausepc, (pc, nextpc)) = (nextpc, getjmp(code.ops, nextpc))) {
316		if (clausepc == defpc) {
317			s += indent + "default:\n";
318		} else {
319			(pc, apc) = getjmp(code.ops, pc);
320			(pc, a) = pexp(pp, pc, apc);
321			s += indent + "case " + a + ":\n";
322		}
323		s += pstmt(pp, pc, nextpc, indent+"\t");
324	}
325	return (epc, s);
326}
327
328ppush(pp: ref PPrint, s: string)
329{
330	if(pp.sp >= len pp.stack){
331		st := array[2 * len pp.stack] of string;
332		st[:] = pp.stack;
333		pp.stack = st;
334	}
335	pp.stack[pp.sp++] = s;
336}
337
338ppop(pp: ref PPrint): string
339{
340	if(pp.sp == 0)
341		fatal(pp.ex, "popping too far off the pstack");
342	return pp.stack[--pp.sp];
343}
344
345unescmap :=	array[128] of
346{
347	'\'' =>		byte '\'',
348	'"' =>		byte '"',
349	'\\' =>		byte '\\',
350	'\b' =>		byte 'b',
351	'\u000c' =>	byte 'f',
352	'\n' =>		byte 'n',
353	'\r' =>		byte 'r',
354	'\t' =>		byte 't',
355
356	* =>		byte 0
357};
358
359escstr(s: string): string
360{
361	n := len s;
362	sb := "";
363	for(i := 0; i < n; i++){
364		c := s[i];
365		if(c < 128 && (e := int unescmap[c])){
366			sb[len sb] = '\\';
367			sb[len sb] = e;
368		}else if(c > 128 || c < 32){
369			sb += "\\u0000";
370			for(j := 1; j <= 4; j++){
371				sb[len sb - j] = "0123456789abcdef"[c & 16rf];
372				c >>= 4;
373			}
374		}else
375			sb[len sb] = c;
376	}
377	return sb;
378}
379