migrate substitution keywords to SVN
[reactos.git] / reactos / lib / kjs / jsc / compiler.js
1 /*
2 * Internal definitions.
3 * Copyright (c) 1998 New Generation Software (NGS) Oy
4 *
5 * Author: Markku Rossi <mtr@ngs.fi>
6 */
7
8 /*
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the Free
21 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22 * MA 02111-1307, USA
23 */
24
25 /*
26 * $Source: /cygdrive/c/RCVS/CVS/ReactOS/reactos/lib/kjs/jsc/compiler.js,v $
27 * $Id$
28 */
29
30 /*
31 * Constants.
32 */
33
34 /* Tokens. */
35
36 JSC$tEOF = 128;
37 JSC$tINTEGER = 129;
38 JSC$tFLOAT = 130;
39 JSC$tSTRING = 131;
40 JSC$tIDENTIFIER = 132;
41
42 JSC$tBREAK = 133;
43 JSC$tCONTINUE = 134;
44 JSC$tDELETE = 135;
45 JSC$tELSE = 136;
46 JSC$tFOR = 137;
47 JSC$tFUNCTION = 138;
48 JSC$tIF = 139;
49 JSC$tIN = 140;
50 JSC$tNEW = 141;
51 JSC$tRETURN = 142;
52 JSC$tTHIS = 143;
53 JSC$tTYPEOF = 144;
54 JSC$tVAR = 145;
55 JSC$tVOID = 146;
56 JSC$tWHILE = 147;
57 JSC$tWITH = 148;
58
59 JSC$tCASE = 149;
60 JSC$tCATCH = 150;
61 JSC$tCLASS = 151;
62 JSC$tCONST = 152;
63 JSC$tDEBUGGER = 153;
64 JSC$tDEFAULT = 154;
65 JSC$tDO = 155;
66 JSC$tENUM = 156;
67 JSC$tEXPORT = 157;
68 JSC$tEXTENDS = 158;
69 JSC$tFINALLY = 159;
70 JSC$tIMPORT = 160;
71 JSC$tSUPER = 161;
72 JSC$tSWITCH = 162;
73 JSC$tTHROW = 163;
74 JSC$tTRY = 164;
75
76 JSC$tNULL = 165;
77 JSC$tTRUE = 166;
78 JSC$tFALSE = 167;
79
80 JSC$tEQUAL = 168;
81 JSC$tNEQUAL = 169;
82 JSC$tLE = 170;
83 JSC$tGE = 171;
84 JSC$tAND = 172;
85 JSC$tOR = 173;
86 JSC$tPLUSPLUS = 174;
87 JSC$tMINUSMINUS = 175;
88 JSC$tMULA = 176;
89 JSC$tDIVA = 177;
90 JSC$tMODA = 178;
91 JSC$tADDA = 179;
92 JSC$tSUBA = 180;
93 JSC$tANDA = 181;
94 JSC$tXORA = 182;
95 JSC$tORA = 183;
96 JSC$tLSIA = 184;
97 JSC$tLSHIFT = 185;
98 JSC$tRSHIFT = 186;
99 JSC$tRRSHIFT = 187;
100 JSC$tRSIA = 188;
101 JSC$tRRSA = 189;
102 JSC$tSEQUAL = 190;
103 JSC$tSNEQUAL = 191;
104
105
106 /* Expressions. */
107
108 JSC$EXPR_COMMA = 0;
109 JSC$EXPR_ASSIGNMENT = 1;
110 JSC$EXPR_QUEST_COLON = 2;
111 JSC$EXPR_LOGICAL = 3;
112 JSC$EXPR_BITWISE = 4;
113 JSC$EXPR_EQUALITY = 5;
114 JSC$EXPR_RELATIONAL = 6;
115 JSC$EXPR_SHIFT = 7;
116 JSC$EXPR_MULTIPLICATIVE = 8;
117 JSC$EXPR_ADDITIVE = 9;
118 JSC$EXPR_THIS = 10;
119 JSC$EXPR_NULL = 11;
120 JSC$EXPR_TRUE = 12;
121 JSC$EXPR_FALSE = 13;
122 JSC$EXPR_IDENTIFIER = 14;
123 JSC$EXPR_FLOAT = 15;
124 JSC$EXPR_INTEGER = 16;
125 JSC$EXPR_STRING = 17;
126 JSC$EXPR_CALL = 18;
127 JSC$EXPR_OBJECT_PROPERTY = 19;
128 JSC$EXPR_OBJECT_ARRAY = 20;
129 JSC$EXPR_NEW = 21;
130 JSC$EXPR_DELETE = 22;
131 JSC$EXPR_VOID = 23;
132 JSC$EXPR_TYPEOF = 24;
133 JSC$EXPR_PREFIX = 25;
134 JSC$EXPR_POSTFIX = 26;
135 JSC$EXPR_UNARY = 27;
136 JSC$EXPR_REGEXP = 28;
137 JSC$EXPR_ARRAY_INITIALIZER = 29;
138 JSC$EXPR_OBJECT_INITIALIZER = 30;
139
140 /* Statements */
141
142 JSC$STMT_BLOCK = 0;
143 JSC$STMT_FUNCTION_DECLARATION = 1;
144 JSC$STMT_VARIABLE = 2;
145 JSC$STMT_EMPTY = 3;
146 JSC$STMT_EXPR = 4;
147 JSC$STMT_IF = 5;
148 JSC$STMT_WHILE = 6;
149 JSC$STMT_FOR = 7;
150 JSC$STMT_FOR_IN = 8;
151 JSC$STMT_CONTINUE = 9;
152 JSC$STMT_BREAK = 10;
153 JSC$STMT_RETURN = 11;
154 JSC$STMT_WITH = 12;
155 JSC$STMT_TRY = 13;
156 JSC$STMT_THROW = 14;
157 JSC$STMT_DO_WHILE = 15;
158 JSC$STMT_SWITCH = 16;
159 JSC$STMT_LABELED_STMT = 17;
160
161 /* JavaScript types. */
162
163 JSC$JS_UNDEFINED = 0;
164 JSC$JS_NULL = 1;
165 JSC$JS_BOOLEAN = 2;
166 JSC$JS_INTEGER = 3;
167 JSC$JS_STRING = 4;
168 JSC$JS_FLOAT = 5;
169 JSC$JS_ARRAY = 6;
170 JSC$JS_OBJECT = 7;
171 JSC$JS_BUILTIN = 11;
172
173 \f
174 /*
175 Local variables:
176 mode: c
177 End:
178 */
179 /*
180 * Lexer.
181 * Copyright (c) 1998-1999 New Generation Software (NGS) Oy
182 *
183 * Author: Markku Rossi <mtr@ngs.fi>
184 */
185
186 /*
187 * This library is free software; you can redistribute it and/or
188 * modify it under the terms of the GNU Library General Public
189 * License as published by the Free Software Foundation; either
190 * version 2 of the License, or (at your option) any later version.
191 *
192 * This library is distributed in the hope that it will be useful,
193 * but WITHOUT ANY WARRANTY; without even the implied warranty of
194 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
195 * Library General Public License for more details.
196 *
197 * You should have received a copy of the GNU Library General Public
198 * License along with this library; if not, write to the Free
199 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
200 * MA 02111-1307, USA
201 */
202
203 /*
204 * $Source: /cygdrive/c/RCVS/CVS/ReactOS/reactos/lib/kjs/jsc/compiler.js,v $
205 * $Id$
206 */
207
208 /*
209 * Global functions.
210 */
211
212 function JSC$lexer (stream)
213 {
214 var ch, ch2;
215
216 JSC$token_value = null;
217
218 while ((ch = stream.readByte ()) != -1)
219 {
220 if (ch == #'\n')
221 {
222 JSC$linenum++;
223 continue;
224 }
225
226 if (JSC$lexer_is_white_space (ch))
227 continue;
228
229 JSC$token_linenum = JSC$linenum;
230
231 if (ch == #'/' && JSC$lexer_peek_char (stream) == #'*')
232 {
233 /* Multi line comment. */
234 stream.readByte ();
235 while ((ch = stream.readByte ()) != -1
236 && (ch != #'*' || JSC$lexer_peek_char (stream) != #'/'))
237 if (ch == #'\n')
238 JSC$linenum++;
239
240 /* Consume the peeked #'/' character. */
241 stream.readByte ();
242 }
243 else if ((ch == #'/' && JSC$lexer_peek_char (stream) == #'/')
244 || (ch == #'#' && JSC$lexer_peek_char (stream) == #'!'))
245 {
246 /* Single line comment. */
247 while ((ch = stream.readByte ()) != -1 && ch != #'\n')
248 ;
249 if (ch == #'\n')
250 JSC$linenum++;
251 }
252 else if (ch == #'"' || ch == #'\'')
253 {
254 /* String constant. */
255 JSC$token_value = JSC$lexer_read_string (stream, "string", ch);
256 return JSC$tSTRING;
257 }
258
259 /* Literals. */
260 else if (ch == #'=' && JSC$lexer_peek_char (stream) == #'=')
261 {
262 stream.readByte ();
263 if (JSC$lexer_peek_char (stream) == #'=')
264 {
265 stream.readByte ();
266 return JSC$tSEQUAL;
267 }
268 return JSC$tEQUAL;
269 }
270 else if (ch == #'!' && JSC$lexer_peek_char (stream) == #'=')
271 {
272 stream.readByte ();
273 if (JSC$lexer_peek_char (stream) == #'=')
274 {
275 stream.readByte ();
276 return JSC$tSNEQUAL;
277 }
278 return JSC$tNEQUAL;
279 }
280 else if (ch == #'<' && JSC$lexer_peek_char (stream) == #'=')
281 {
282 stream.readByte ();
283 return JSC$tLE;
284 }
285 else if (ch == #'>' && JSC$lexer_peek_char (stream) == #'=')
286 {
287 stream.readByte ();
288 return JSC$tGE;
289 }
290 else if (ch == #'&' && JSC$lexer_peek_char (stream) == #'&')
291 {
292 stream.readByte ();
293 return JSC$tAND;
294 }
295 else if (ch == #'|' && JSC$lexer_peek_char (stream) == #'|')
296 {
297 stream.readByte ();
298 return JSC$tOR;
299 }
300 else if (ch == #'+' && JSC$lexer_peek_char (stream) == #'+')
301 {
302 stream.readByte ();
303 return JSC$tPLUSPLUS;
304 }
305 else if (ch == #'-' && JSC$lexer_peek_char (stream) == #'-')
306 {
307 stream.readByte ();
308 return JSC$tMINUSMINUS;
309 }
310 else if (ch == #'*' && JSC$lexer_peek_char (stream) == #'=')
311 {
312 stream.readByte ();
313 return JSC$tMULA;
314 }
315 else if (ch == #'/' && JSC$lexer_peek_char (stream) == #'=')
316 {
317 stream.readByte ();
318 return JSC$tDIVA;
319 }
320 else if (ch == #'%' && JSC$lexer_peek_char (stream) == #'=')
321 {
322 stream.readByte ();
323 return JSC$tMODA;
324 }
325 else if (ch == #'+' && JSC$lexer_peek_char (stream) == #'=')
326 {
327 stream.readByte ();
328 return JSC$tADDA;
329 }
330 else if (ch == #'-' && JSC$lexer_peek_char (stream) == #'=')
331 {
332 stream.readByte ();
333 return JSC$tSUBA;
334 }
335 else if (ch == #'&' && JSC$lexer_peek_char (stream) == #'=')
336 {
337 stream.readByte ();
338 return JSC$tANDA;
339 }
340 else if (ch == #'^' && JSC$lexer_peek_char (stream) == #'=')
341 {
342 stream.readByte ();
343 return JSC$tXORA;
344 }
345 else if (ch == #'|' && JSC$lexer_peek_char (stream) == #'=')
346 {
347 stream.readByte ();
348 return JSC$tORA;
349 }
350 else if (ch == #'<' && JSC$lexer_peek_char (stream) == #'<')
351 {
352 stream.readByte ();
353 if (JSC$lexer_peek_char (stream) == #'=')
354 {
355 stream.readByte ();
356 return JSC$tLSIA;
357 }
358 else
359 return JSC$tLSHIFT;
360 }
361 else if (ch == #'>' && JSC$lexer_peek_char (stream) == #'>')
362 {
363 stream.readByte ();
364 ch2 = JSC$lexer_peek_char (stream);
365 if (ch2 == #'=')
366 {
367 stream.readByte ();
368 return JSC$tRSIA;
369 }
370 else if (ch2 == #'>')
371 {
372 stream.readByte ();
373 if (JSC$lexer_peek_char (stream) == #'=')
374 {
375 stream.readByte ();
376 return JSC$tRRSA;
377 }
378 else
379 return JSC$tRRSHIFT;
380 }
381 else
382 return JSC$tRSHIFT;
383 }
384
385 /* Identifiers and keywords. */
386 else if (JSC$lexer_is_identifier_letter (ch))
387 {
388 /* An identifier. */
389 var id = String.fromCharCode (ch);
390
391 while ((ch = stream.readByte ()) != -1
392 && (JSC$lexer_is_identifier_letter (ch)
393 || JSC$lexer_is_decimal_digit (ch)))
394 id.append (File.byteToString (ch));
395 stream.ungetByte (ch);
396
397 /* Keywords. */
398 if (id == "break")
399 return JSC$tBREAK;
400 else if (id == "continue")
401 return JSC$tCONTINUE;
402 else if (id == "delete")
403 return JSC$tDELETE;
404 else if (id == "else")
405 return JSC$tELSE;
406 else if (id == "for")
407 return JSC$tFOR;
408 else if (id == "function")
409 return JSC$tFUNCTION;
410 else if (id == "if")
411 return JSC$tIF;
412 else if (id == "in")
413 return JSC$tIN;
414 else if (id == "new")
415 return JSC$tNEW;
416 else if (id == "return")
417 return JSC$tRETURN;
418 else if (id == "this")
419 return JSC$tTHIS;
420 else if (id == "typeof")
421 return JSC$tTYPEOF;
422 else if (id == "var")
423 return JSC$tVAR;
424 else if (id == "void")
425 return JSC$tVOID;
426 else if (id == "while")
427 return JSC$tWHILE;
428 else if (id == "with")
429 return JSC$tWITH;
430
431 /*
432 * Future reserved keywords (some of these is already in use
433 * in this implementation).
434 */
435 else if (id == "case")
436 return JSC$tCASE;
437 else if (id == "catch")
438 return JSC$tCATCH;
439 else if (id == "class")
440 return JSC$tCLASS;
441 else if (id == "const")
442 return JSC$tCONST;
443 else if (id == "debugger")
444 return JSC$tDEBUGGER;
445 else if (id == "default")
446 return JSC$tDEFAULT;
447 else if (id == "do")
448 return JSC$tDO;
449 else if (id == "enum")
450 return JSC$tENUM;
451 else if (id == "export")
452 return JSC$tEXPORT;
453 else if (id == "extends")
454 return JSC$tEXTENDS;
455 else if (id == "finally")
456 return JSC$tFINALLY;
457 else if (id == "import")
458 return JSC$tIMPORT;
459 else if (id == "super")
460 return JSC$tSUPER;
461 else if (id == "switch")
462 return JSC$tSWITCH;
463 else if (id == "throw")
464 return JSC$tTHROW;
465 else if (id == "try")
466 return JSC$tTRY;
467
468 /* Null and boolean literals. */
469 else if (id == "null")
470 return JSC$tNULL;
471 else if (id == "true")
472 return JSC$tTRUE;
473 else if (id == "false")
474 return JSC$tFALSE;
475 else
476 {
477 /* It really is an identifier. */
478 JSC$token_value = id;
479 return JSC$tIDENTIFIER;
480 }
481 }
482
483 /* Character constants. */
484 else if (ch == #'#' && JSC$lexer_peek_char (stream) == #'\'')
485 {
486 /* Skip the starting #'\'' and read more. */
487 stream.readByte ();
488
489 ch = stream.readByte ();
490 if (ch == #'\\')
491 {
492 JSC$token_value
493 = JSC$lexer_read_backslash_escape (stream, 0, "character");
494
495 if (stream.readByte () != #'\'')
496 error (JSC$filename + ":" + JSC$linenum.toString ()
497 + ": malformed character constant");
498 }
499 else if (JSC$lexer_peek_char (stream) == #'\'')
500 {
501 stream.readByte ();
502 JSC$token_value = ch;
503 }
504 else
505 error (JSC$filename + ":" + JSC$linenum.toString ()
506 + ": malformed character constant");
507
508 return JSC$tINTEGER;
509 }
510
511 /* Octal and hex numbers. */
512 else if (ch == #'0'
513 && JSC$lexer_peek_char (stream) != #'.'
514 && JSC$lexer_peek_char (stream) != #'e'
515 && JSC$lexer_peek_char (stream) != #'E')
516 {
517 JSC$token_value = 0;
518 ch = stream.readByte ();
519 if (ch == #'x' || ch == #'X')
520 {
521 ch = stream.readByte ();
522 while (JSC$lexer_is_hex_digit (ch))
523 {
524 JSC$token_value *= 16;
525 JSC$token_value += JSC$lexer_hex_to_dec (ch);
526 ch = stream.readByte ();
527 }
528 stream.ungetByte (ch);
529 }
530 else
531 {
532 while (JSC$lexer_is_octal_digit (ch))
533 {
534 JSC$token_value *= 8;
535 JSC$token_value += ch - #'0';
536 ch = stream.readByte ();
537 }
538 stream.ungetByte (ch);
539 }
540
541 return JSC$tINTEGER;
542 }
543
544 /* Decimal numbers. */
545 else if (JSC$lexer_is_decimal_digit (ch)
546 || (ch == #'.'
547 && JSC$lexer_is_decimal_digit (
548 JSC$lexer_peek_char (stream))))
549 {
550 var is_float = false;
551 var buf = new String (File.byteToString (ch));
552 var accept_dot = true;
553
554 if (ch == #'.')
555 {
556 /*
557 * We started with #'.' and we know that the next character
558 * is a decimal digit (we peeked it).
559 */
560 is_float = true;
561
562 ch = stream.readByte ();
563 while (JSC$lexer_is_decimal_digit (ch))
564 {
565 buf.append (File.byteToString (ch));
566 ch = stream.readByte ();
567 }
568 accept_dot = false;
569 }
570 else
571 {
572 /* We did start with a decimal digit. */
573 ch = stream.readByte ();
574 while (JSC$lexer_is_decimal_digit (ch))
575 {
576 buf.append (File.byteToString (ch));
577 ch = stream.readByte ();
578 }
579 }
580
581 if ((accept_dot && ch == #'.')
582 || ch == #'e' || ch == #'E')
583 {
584 is_float = true;
585
586 if (ch == #'.')
587 {
588 buf.append (File.byteToString (ch));
589 ch = stream.readByte ();
590 while (JSC$lexer_is_decimal_digit (ch))
591 {
592 buf.append (File.byteToString (ch));
593 ch = stream.readByte ();
594 }
595 }
596
597 if (ch == #'e' || ch == #'E')
598 {
599 buf.append (File.byteToString (ch));
600 ch = stream.readByte ();
601 if (ch == #'+' || ch == #'-')
602 {
603 buf.append (File.byteToString (ch));
604 ch = stream.readByte ();
605 }
606 if (!JSC$lexer_is_decimal_digit (ch))
607 error (JSC$filename + ":" + JSC$linenum.toString ()
608 + ": malformed exponent part in a decimal literal");
609
610 while (JSC$lexer_is_decimal_digit (ch))
611 {
612 buf.append (File.byteToString (ch));
613 ch = stream.readByte ();
614 }
615 }
616 }
617
618 /* Finally, we put the last character pack to the stream. */
619 stream.ungetByte (ch);
620
621 if (is_float)
622 {
623 JSC$token_value = parseFloat (buf);
624 return JSC$tFLOAT;
625 }
626
627 JSC$token_value = parseInt (buf);
628 return JSC$tINTEGER;
629 }
630
631 /* Just return the character as-is. */
632 else
633 return ch;
634 }
635
636 /* EOF reached. */
637 return JSC$tEOF;
638 }
639
640
641 /*
642 * Help functions.
643 */
644
645 function JSC$lexer_peek_char (stream)
646 {
647 var ch2 = stream.readByte ();
648 stream.ungetByte (ch2);
649
650 return ch2;
651 }
652
653
654 function JSC$lexer_is_identifier_letter (ch)
655 {
656 return ((#'a' <= ch && ch <= #'z') || (#'A' <= ch && ch <= #'Z')
657 || ch == #'$' || ch == #'_');
658 }
659
660
661 function JSC$lexer_is_octal_digit (ch)
662 {
663 return (#'0' <= ch && ch <= #'7');
664 }
665
666
667 function JSC$lexer_is_decimal_digit (ch)
668 {
669 return #'0' <= ch && ch <= #'9';
670 }
671
672
673 function JSC$lexer_is_hex_digit (ch)
674 {
675 return ((#'0' <= ch && ch <= #'9')
676 || (#'a' <= ch && ch <= #'f')
677 || (#'A' <= ch && ch <= #'F'));
678 }
679
680
681 function JSC$lexer_is_white_space (ch)
682 {
683 return (ch == #' ' || ch == #'\t' || ch == #'\v' || ch == #'\r'
684 || ch == #'\f' || ch == #'\n');
685 }
686
687
688 function JSC$lexer_hex_to_dec (ch)
689 {
690 return ((#'0' <= ch && ch <= #'9')
691 ? ch - #'0'
692 : ((#'a' <= ch && ch <= #'f')
693 ? 10 + ch - #'a'
694 : 10 + ch - #'A'));
695 }
696
697
698 function JSC$lexer_read_backslash_escape (stream, possible_start, name)
699 {
700 var ch = stream.readByte ();
701
702 if (ch == #'n')
703 ch = #'\n';
704 else if (ch == #'t')
705 ch = #'\t';
706 else if (ch == #'v')
707 ch = #'\v';
708 else if (ch == #'b')
709 ch = #'\b';
710 else if (ch == #'r')
711 ch = #'\r';
712 else if (ch == #'f')
713 ch = #'\f';
714 else if (ch == #'a')
715 ch = #'\a';
716 else if (ch == #'\\')
717 ch = #'\\';
718 else if (ch == #'?')
719 ch = #'?';
720 else if (ch == #'\'')
721 ch = #'\'';
722 else if (ch == #'"')
723 ch = #'"';
724 else if (ch == #'x')
725 {
726 /* HexEscapeSequence. */
727 var c1, c2;
728
729 c1 = stream.readByte ();
730 c2 = stream.readByte ();
731
732 if (c1 == -1 || c2 == -1)
733 JSC$lexer_eof_in_constant (possible_start, name);
734
735 if (!JSC$lexer_is_hex_digit (c1) || !JSC$lexer_is_hex_digit (c2))
736 error (JSC$filename + ":" + JSC$linenum.toString ()
737 + ": \\x used with no following hex digits");
738
739 ch = (JSC$lexer_hex_to_dec (c1) << 4) + JSC$lexer_hex_to_dec (c2);
740 }
741 else if (ch == #'u')
742 {
743 /* UnicodeEscapeSequence. */
744 var c1, c2, c3, c4;
745
746 c1 = stream.readByte ();
747 c2 = stream.readByte ();
748 c3 = stream.readByte ();
749 c4 = stream.readByte ();
750
751 if (c1 == -1 || c2 == -1 || c3 == -1 || c4 == -1)
752 JSC$lexer_eof_in_constant (possible_start, name);
753
754 if (!JSC$lexer_is_hex_digit (c1) || !JSC$lexer_is_hex_digit (c2)
755 || !JSC$lexer_is_hex_digit (c3) || !JSC$lexer_is_hex_digit (c4))
756 error (JSC$filename + ":" + JSC$linenum.toString ()
757 + ": \\u used with no following hex digits");
758
759 ch = ((JSC$lexer_hex_to_dec (c1) << 12)
760 + (JSC$lexer_hex_to_dec (c2) << 8)
761 + (JSC$lexer_hex_to_dec (c3) << 4)
762 + JSC$lexer_hex_to_dec (c4));
763 }
764 else if (JSC$lexer_is_octal_digit (ch))
765 {
766 var result = ch - #'0';
767 var i = 1;
768
769 if (ch == #'0')
770 /* Allow three octal digits after '0'. */
771 i = 0;
772
773 ch = stream.readByte ();
774 while (i < 3 && JSC$lexer_is_octal_digit (ch))
775 {
776 result *= 8;
777 result += ch - #'0';
778 ch = stream.readByte ();
779 i++;
780 }
781 stream.ungetByte (ch);
782 ch = result;
783 }
784 else
785 {
786 if (ch == -1)
787 error (JSC$filename + ":" + JSC$linenum.toString ()
788 + ": unterminated " + name);
789
790 JSC$warning (JSC$filename + ":" + JSC$linenum.toString ()
791 + ": warning: unknown escape sequence `\\"
792 + File.byteToString (ch) + "'");
793 }
794
795 return ch;
796 }
797
798
799 function JSC$lexer_read_string (stream, name, ender)
800 {
801 var str = new String ("");
802 var done = false, ch;
803 var possible_start_ln = JSC$linenum;
804 var warned_line_terminator = false;
805
806 while (!done)
807 {
808 ch = stream.readByte ();
809 if (ch == #'\n')
810 {
811 if (JSC$warn_strict_ecma && !warned_line_terminator)
812 {
813 JSC$warning (JSC$filename + ":" + JSC$linenum.toString ()
814 + ": warning: ECMAScript don't allow line terminators in "
815 + name + " constants");
816 warned_line_terminator = true;
817 }
818 JSC$linenum++;
819 }
820
821 if (ch == -1)
822 JSC$lexer_eof_in_constant (possible_start_ln, name);
823
824 else if (ch == ender)
825 done = true;
826 else
827 {
828 if (ch == #'\\')
829 {
830 if (JSC$lexer_peek_char (stream) == #'\n')
831 {
832 /*
833 * Backslash followed by a newline character. Ignore
834 * them both.
835 */
836 stream.readByte ();
837 JSC$linenum++;
838 continue;
839 }
840 ch = JSC$lexer_read_backslash_escape (stream, possible_start_ln,
841 name);
842 }
843 str.append (ch);
844 }
845 }
846
847 return str;
848 }
849
850
851 function JSC$lexer_read_regexp_constant (stream)
852 {
853 /* Regexp literal. */
854 var source = JSC$lexer_read_regexp_source (stream);
855
856 /* Check the possible flags. */
857 var flags = new String ("");
858 while ((ch = JSC$lexer_peek_char (stream)) == #'g' || ch == #'i')
859 {
860 stream.readByte ();
861 flags.append (File.byteToString (ch));
862 }
863
864 /* Try to compile it. */
865 var msg = false;
866 var result;
867 try
868 {
869 result = new RegExp (source, flags);
870 }
871 catch (msg)
872 {
873 var start = msg.lastIndexOf (":");
874 msg = (JSC$filename + ":" + JSC$token_linenum.toString ()
875 + ": malformed regular expression constant:"
876 + msg.substr (start + 1));
877 }
878 if (msg)
879 error (msg);
880
881 /* Success. */
882
883 return result;
884 }
885
886
887 function JSC$lexer_read_regexp_source (stream)
888 {
889 var str = new String ("");
890 var done = false, ch;
891 var possible_start_ln = JSC$linenum;
892 var warned_line_terminator = false;
893 var name = "regular expression";
894
895 while (!done)
896 {
897 ch = stream.readByte ();
898 if (ch == #'\n')
899 {
900 if (JSC$warn_strict_ecma && !warned_line_terminator)
901 {
902 JSC$warning (JSC$filename + ":" + JSC$linenum.toString ()
903 + ": warning: ECMAScript don't allow line "
904 + "terminators in " + name + " constants");
905 warned_line_terminator = true;
906 }
907 JSC$linenum++;
908 }
909
910 if (ch == -1)
911 JSC$lexer_eof_in_constant (possible_start_ln, name);
912
913 else if (ch == #'/')
914 done = true;
915 else
916 {
917 if (ch == #'\\')
918 {
919 ch = stream.readByte ();
920 if (ch == #'\n')
921 {
922 /*
923 * Backslash followed by a newline character. Ignore
924 * them both.
925 */
926 JSC$linenum++;
927 continue;
928 }
929 if (ch == -1)
930 JSC$lexer_eof_in_constant (possible_start_ln, name);
931
932 /* Handle the backslash escapes. */
933 if (ch == #'f')
934 ch = #'\f';
935 else if (ch == #'n')
936 ch = #'\n';
937 else if (ch == #'r')
938 ch = #'\r';
939 else if (ch == #'t')
940 ch = #'\t';
941 else if (ch == #'v')
942 ch == #'\v';
943 else if (ch == #'c')
944 {
945 /* SourceCharacter. */
946 ch = stream.readByte ();
947 if (ch == -1)
948 JSC$lexer_eof_in_constant (possible_start_ln, name);
949
950 if (ch == #'\n' && JSC$warn_strict_ecma)
951 JSC$warning (JSC$filename + ":" + JSC$linenum.toString ()
952 + ": warning: ECMAScript don't allow line termiantor after \\c in regular expression constants");
953
954 /*
955 * Append the source-character escape start. The ch
956 * will be appended later.
957 */
958 str.append ("\\c");
959 }
960 else if (ch == #'u' || ch == #'x' || ch == #'0')
961 {
962 /* These can be handled with the read_backslash_escape(). */
963 stream.ungetByte (ch);
964 ch = JSC$lexer_read_backslash_escape (stream);
965 }
966 else
967 {
968 /*
969 * Nothing special. Leave it to the result as-is.
970 * The regular expression backage will handle it.
971 */
972 stream.ungetByte (ch);
973 ch = #'\\';
974 }
975 }
976 str.append (File.byteToString (ch));
977 }
978 }
979
980 return str;
981 }
982
983
984 function JSC$lexer_eof_in_constant (possible_start, name)
985 {
986 var msg = (JSC$filename + ":" + JSC$linenum.toString ()
987 + ": unterminated " + name + " constant");
988
989 if (possible_start > 0)
990 msg += (System.lineBreakSequence
991 + JSC$filename + ":" + possible_start.toString ()
992 + ": possible real start of unterminated " + name + " constant");
993
994 error (msg);
995 }
996
997 \f
998 /*
999 Local variables:
1000 mode: c
1001 End:
1002 */
1003 /*
1004 * Parser.
1005 * Copyright (c) 1998 New Generation Software (NGS) Oy
1006 *
1007 * Author: Markku Rossi <mtr@ngs.fi>
1008 */
1009
1010 /*
1011 * This library is free software; you can redistribute it and/or
1012 * modify it under the terms of the GNU Library General Public
1013 * License as published by the Free Software Foundation; either
1014 * version 2 of the License, or (at your option) any later version.
1015 *
1016 * This library is distributed in the hope that it will be useful,
1017 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1019 * Library General Public License for more details.
1020 *
1021 * You should have received a copy of the GNU Library General Public
1022 * License along with this library; if not, write to the Free
1023 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
1024 * MA 02111-1307, USA
1025 */
1026
1027 /*
1028 * $Source: /cygdrive/c/RCVS/CVS/ReactOS/reactos/lib/kjs/jsc/compiler.js,v $
1029 * $Id$
1030 */
1031
1032 /*
1033 * Global functions.
1034 */
1035
1036 function JSC$parser_reset ()
1037 {
1038 JSC$function = null;
1039 JSC$global_stmts = null;
1040 JSC$nested_function_declarations = null;
1041 }
1042
1043
1044 function JSC$parser_parse (stream)
1045 {
1046 JSC$linenum = 1;
1047 JSC$filename = stream.name;
1048 JSC$functions = new Array ();
1049 JSC$global_stmts = new Array ();
1050 JSC$nested_function_declarations = new Array ();
1051 JSC$anonymous_function_count = 0;
1052 JSC$parser_peek_token_valid = false;
1053 JSC$num_tokens = 0;
1054 JSC$num_arguments_identifiers = 0;
1055 JSC$num_missing_semicolons = 0;
1056
1057 if (JSC$verbose)
1058 JSC$message ("jsc: parsing");
1059
1060 while (JSC$parser_peek_token (stream) != JSC$tEOF)
1061 if (!JSC$parser_parse_source_element (stream))
1062 JSC$parser_syntax_error ();
1063
1064 if (JSC$verbose)
1065 {
1066 var msg = ("jsc: input stream had " + (JSC$linenum - 1).toString ()
1067 + " lines, " + JSC$num_tokens.toString () + " tokens");
1068
1069 if (JSC$num_missing_semicolons > 0)
1070 msg += (", " + JSC$num_missing_semicolons.toString ()
1071 + " missing semicolons");
1072
1073 JSC$message (msg);
1074 }
1075 }
1076
1077
1078 /*
1079 * General help functions.
1080 */
1081
1082 function JSC$parser_syntax_error ()
1083 {
1084 error (JSC$filename + ":" + JSC$linenum.toString () + ": syntax error");
1085 }
1086
1087 /* All warnings are reported through this function. */
1088 function JSC$warning (line)
1089 {
1090 System.stderr.writeln (line);
1091 }
1092
1093 /* All messages are reported throught this function. */
1094 function JSC$message (line)
1095 {
1096 System.stderr.writeln (line);
1097 }
1098
1099
1100 function JSC$parser_get_token (stream)
1101 {
1102 JSC$num_tokens++;
1103
1104 var token;
1105 if (JSC$parser_peek_token_valid)
1106 {
1107 JSC$parser_peek_token_valid = false;
1108 JSC$parser_token_value = JSC$parser_peek_token_value;
1109 JSC$parser_token_linenum = JSC$parser_peek_token_linenum;
1110 token = JSC$parser_peek_token_token;
1111 }
1112 else
1113 {
1114 token = JSC$lexer (stream);
1115 JSC$parser_token_value = JSC$token_value;
1116 JSC$parser_token_linenum = JSC$token_linenum;
1117 }
1118
1119 if (token == JSC$tIDENTIFIER && JSC$parser_token_value == "arguments")
1120 JSC$num_arguments_identifiers++;
1121
1122 return token;
1123 }
1124
1125
1126 function JSC$parser_peek_token (stream)
1127 {
1128 if (JSC$parser_peek_token_valid)
1129 return JSC$parser_peek_token_token;
1130 else
1131 {
1132 JSC$parser_peek_token_token = JSC$lexer (stream);
1133 JSC$parser_peek_token_value = JSC$token_value;
1134 JSC$parser_peek_token_linenum = JSC$token_linenum;
1135 JSC$parser_peek_token_valid = true;
1136 return JSC$parser_peek_token_token;
1137 }
1138 }
1139
1140
1141 function JSC$parser_get_semicolon_asci (stream)
1142 {
1143 var token = JSC$parser_peek_token (stream);
1144
1145 if (token == #';')
1146 {
1147 /* Everything ok. It was there. */
1148 return JSC$parser_get_token (stream);
1149 }
1150
1151 /* No semicolon. Let's see if we can insert it there. */
1152 if (token == #'}'
1153 || JSC$parser_token_linenum < JSC$parser_peek_token_linenum
1154 || token == JSC$tEOF)
1155 {
1156 /* Ok, do the automatic semicolon insertion. */
1157 if (JSC$warn_missing_semicolon)
1158 JSC$warning (JSC$filename + ":" + JSC$parser_token_linenum.toString ()
1159 + ": warning: missing semicolon");
1160 JSC$num_missing_semicolons++;
1161 return #';';
1162 }
1163
1164 /* Sorry, no can do. */
1165 JSC$parser_syntax_error ();
1166 }
1167
1168
1169 function JSC$parser_expr_is_left_hand_side (expr)
1170 {
1171 return (expr.etype == JSC$EXPR_CALL
1172 || expr.etype == JSC$EXPR_OBJECT_PROPERTY
1173 || expr.etype == JSC$EXPR_OBJECT_ARRAY
1174 || expr.etype == JSC$EXPR_NEW
1175 || expr.etype == JSC$EXPR_THIS
1176 || expr.etype == JSC$EXPR_IDENTIFIER
1177 || expr.etype == JSC$EXPR_FLOAT
1178 || expr.etype == JSC$EXPR_INTEGER
1179 || expr.etype == JSC$EXPR_STRING
1180 || expr.etype == JSC$EXPR_REGEXP
1181 || expr.etype == JSC$EXPR_ARRAY_INITIALIZER
1182 || expr.etype == JSC$EXPR_NULL
1183 || expr.etype == JSC$EXPR_TRUE
1184 || expr.etype == JSC$EXPR_FALSE);
1185 }
1186
1187
1188 function JSC$parser_parse_source_element (stream)
1189 {
1190 if (JSC$parser_parse_function_declaration (stream))
1191 return true;
1192
1193 var stmt = JSC$parser_parse_stmt (stream);
1194 if (!stmt)
1195 return false;
1196
1197 if (stmt.stype == JSC$STMT_VARIABLE)
1198 /*
1199 * This is a variable declaration at the global level. These
1200 * are actually global variables.
1201 */
1202 stmt.global_level = true;
1203
1204 JSC$global_stmts.push (stmt);
1205
1206 return true;
1207 }
1208
1209
1210 function JSC$parser_parse_function_declaration (stream)
1211 {
1212 var id, args, block;
1213
1214 if (JSC$parser_peek_token (stream) != JSC$tFUNCTION)
1215 return false;
1216
1217 /* Record how many `arguments' identifiers have been seen so far. */
1218 var num_arguments_identifiers = JSC$num_arguments_identifiers;
1219
1220 JSC$parser_get_token (stream);
1221 if (JSC$parser_get_token (stream) != JSC$tIDENTIFIER)
1222 JSC$parser_syntax_error ();
1223
1224 id = JSC$parser_token_value;
1225 var ln = JSC$parser_token_linenum;
1226 var id_given = id;
1227
1228 if (JSC$nested_function_declarations.length > 0)
1229 {
1230 /* This is a nested function declaration. */
1231 id = ".F:" + (JSC$anonymous_function_count++).toString ();
1232 }
1233 JSC$nested_function_declarations.push (id);
1234
1235 if (JSC$parser_get_token (stream) != #'(')
1236 JSC$parser_syntax_error ();
1237
1238 /* Formal parameter list opt. */
1239 args = new Array ();
1240 while (JSC$parser_peek_token (stream) != #')')
1241 {
1242 if (JSC$parser_get_token (stream) != JSC$tIDENTIFIER)
1243 JSC$parser_syntax_error ();
1244 args.push (JSC$parser_token_value);
1245
1246 var token = JSC$parser_peek_token (stream);
1247 if (token == #',')
1248 {
1249 JSC$parser_get_token (stream);
1250 if (JSC$parser_peek_token (stream) != JSC$tIDENTIFIER)
1251 JSC$parser_syntax_error ();
1252 }
1253 else if (token != #')')
1254 JSC$parser_syntax_error ();
1255 }
1256
1257 if (JSC$parser_get_token (stream) != #')')
1258 JSC$parser_syntax_error ();
1259
1260 JSC$parser_peek_token (stream);
1261 var lbrace_ln = JSC$parser_peek_token_linenum;
1262
1263 block = JSC$parser_parse_block (stream);
1264 if (typeof block == "boolean")
1265 JSC$parser_syntax_error ();
1266
1267 /* Did the function use the `arguments' identifier? */
1268 var use_arguments = false;
1269 if (JSC$num_arguments_identifiers > num_arguments_identifiers)
1270 {
1271 use_arguments = true;
1272 if (JSC$warn_deprecated)
1273 JSC$warning (JSC$filename + ":" + ln.toString ()
1274 + ": warning: the `arguments' property of Function "
1275 + "instance is deprecated");
1276 }
1277
1278 JSC$functions.push (new JSC$function_declaration (ln, lbrace_ln, id,
1279 id_given, args,
1280 block, use_arguments));
1281
1282 JSC$nested_function_declarations.pop ();
1283
1284 return true;
1285 }
1286
1287
1288 function JSC$parser_parse_block (stream)
1289 {
1290 var block;
1291
1292 if (JSC$parser_peek_token (stream) != #'{')
1293 return false;
1294
1295 JSC$parser_get_token (stream) != #'{';
1296 var ln = JSC$parser_peek_token_linenum;
1297
1298 /* Do we have a statement list? */
1299 if (JSC$parser_peek_token (stream) != #'}')
1300 /* Yes we have. */
1301 block = JSC$parser_parse_stmt_list (stream);
1302 else
1303 /* Do we don't */
1304 block = new Array ();
1305
1306 if (JSC$parser_get_token (stream) != #'}')
1307 JSC$parser_syntax_error ();
1308
1309 block.linenum = ln;
1310
1311 return block;
1312 }
1313
1314
1315 function JSC$parser_parse_stmt_list (stream)
1316 {
1317 var list, done, item;
1318
1319 list = new Array ();
1320 done = false;
1321
1322 while (!done)
1323 {
1324 item = JSC$parser_parse_stmt (stream);
1325 if (typeof item == "boolean")
1326 {
1327 /* Can't parse more statements. We'r done. */
1328 done = true;
1329 }
1330 else
1331 list.push (item);
1332 }
1333
1334 return list;
1335 }
1336
1337
1338 function JSC$parser_parse_stmt (stream)
1339 {
1340 var item, token;
1341
1342 if (typeof (item = JSC$parser_parse_block (stream)) != "boolean")
1343 return new JSC$stmt_block (item.linenum, item);
1344 else if (JSC$parser_parse_function_declaration (stream))
1345 {
1346 /* XXX The function declaration as statement might be incomplete. */
1347
1348 if (JSC$nested_function_declarations.length == 0)
1349 /* Function declaration at top-level statements. */
1350 return new JSC$stmt_empty (JSC$parser_token_linenum);
1351
1352 /* Function declaration inside another function. */
1353
1354 var container_id = JSC$nested_function_declarations.pop ();
1355 JSC$nested_function_declarations.push (container_id);
1356
1357 var f = JSC$functions[JSC$functions.length - 1];
1358 var function_id = f.name;
1359 var given_id = f.name_given;
1360
1361 return new JSC$stmt_function_declaration (JSC$parser_token_linenum,
1362 container_id, function_id,
1363 given_id);
1364 }
1365 else if (typeof (item = JSC$parser_parse_variable_stmt (stream))
1366 != "boolean")
1367 return item;
1368 else if (typeof (item = JSC$parser_parse_if_stmt (stream))
1369 != "boolean")
1370 return item;
1371 else if (typeof (item = JSC$parser_parse_iteration_stmt (stream))
1372 != "boolean")
1373 return item;
1374 else if (typeof (item = JSC$parser_parse_expr (stream))
1375 != "boolean")
1376 {
1377 if (item.etype == JSC$EXPR_IDENTIFIER)
1378 {
1379 /* Possible `Labeled Statement'. */
1380 token = JSC$parser_peek_token (stream);
1381 if (token == #':' && item.linenum == JSC$parser_peek_token_linenum)
1382 {
1383 /* Yes it is. */
1384 JSC$parser_get_token (stream);
1385 var stmt = JSC$parser_parse_stmt (stream);
1386 if (!stmt)
1387 JSC$parser_syntax_error;
1388
1389 return new JSC$stmt_labeled_stmt (item.linenum, item.value,
1390 stmt);
1391 }
1392 /* FALLTHROUGH */
1393 }
1394
1395 JSC$parser_get_semicolon_asci (stream);
1396 return new JSC$stmt_expr (item);
1397 }
1398 else
1399 {
1400 token = JSC$parser_peek_token (stream);
1401 if (token == #';')
1402 {
1403 JSC$parser_get_token (stream);
1404 return new JSC$stmt_empty (JSC$parser_token_linenum);
1405 }
1406 else if (token == JSC$tCONTINUE)
1407 {
1408 JSC$parser_get_token (stream);
1409
1410 /* Check the possible label. */
1411 var label = null;
1412 token = JSC$parser_peek_token (stream);
1413 if (token == JSC$tIDENTIFIER
1414 && JSC$parser_token_linenum == JSC$parser_peek_token_linenum)
1415 {
1416 JSC$parser_get_token (stream);
1417 label = JSC$parser_token_value;
1418 }
1419
1420 item = new JSC$stmt_continue (JSC$parser_token_linenum, label);
1421
1422 JSC$parser_get_semicolon_asci (stream);
1423
1424 return item;
1425 }
1426 else if (token == JSC$tBREAK)
1427 {
1428 JSC$parser_get_token (stream);
1429
1430 /* Check the possible label. */
1431 var label = null;
1432 token = JSC$parser_peek_token (stream);
1433 if (token == JSC$tIDENTIFIER
1434 && JSC$parser_token_linenum == JSC$parser_peek_token_linenum)
1435 {
1436 JSC$parser_get_token (stream);
1437 label = JSC$parser_token_value;
1438 }
1439
1440 item = new JSC$stmt_break (JSC$parser_token_linenum, label);
1441
1442 JSC$parser_get_semicolon_asci (stream);
1443
1444 return item;
1445 }
1446 else if (token == JSC$tRETURN)
1447 {
1448 JSC$parser_get_token (stream);
1449 var linenum = JSC$parser_token_linenum;
1450
1451 if (JSC$parser_peek_token (stream) == #';')
1452 {
1453 /* Consume the semicolon. */
1454 JSC$parser_get_token (stream);
1455 item = null;
1456 }
1457 else
1458 {
1459 if (JSC$parser_peek_token_linenum > linenum)
1460 {
1461 /*
1462 * A line terminator between tRETURN and the next
1463 * token that is not a semicolon. ASCI here.
1464 */
1465 if (JSC$warn_missing_semicolon)
1466 JSC$warning (JSC$filename + ":" + linenum.toString ()
1467 + ": warning: missing semicolon");
1468
1469 JSC$num_missing_semicolons++;
1470 item = null;
1471 }
1472 else
1473 {
1474 item = JSC$parser_parse_expr (stream);
1475 if (typeof item == "boolean")
1476 JSC$parser_syntax_error ();
1477
1478 JSC$parser_get_semicolon_asci (stream);
1479 }
1480 }
1481
1482 return new JSC$stmt_return (linenum, item);
1483 }
1484 else if (token == JSC$tSWITCH)
1485 {
1486 JSC$parser_get_token (stream);
1487 return JSC$parser_parse_switch (stream);
1488 }
1489 else if (token == JSC$tWITH)
1490 {
1491 JSC$parser_get_token (stream);
1492 var linenum = JSC$parser_token_linenum;
1493
1494 if (JSC$parser_get_token (stream) != #'(')
1495 JSC$parser_syntax_error ();
1496
1497 var expr = JSC$parser_parse_expr (stream);
1498 if (typeof expr == "boolean")
1499 JSC$parser_syntax_error ();
1500
1501 if (JSC$parser_get_token (stream) != #')')
1502 JSC$parser_syntax_error ();
1503
1504 var stmt = JSC$parser_parse_stmt (stream);
1505 if (typeof stmt == "boolean")
1506 JSC$parser_syntax_error ();
1507
1508 return new JSC$stmt_with (linenum, expr, stmt);
1509 }
1510 else if (token == JSC$tTRY)
1511 {
1512 JSC$parser_get_token (stream);
1513 return JSC$parser_parse_try (stream);
1514 }
1515 else if (token == JSC$tTHROW)
1516 {
1517 JSC$parser_get_token (stream);
1518 var linenum = JSC$parser_token_linenum;
1519
1520 /*
1521 * Get the next token's linenum. We need it for strict_ecma
1522 * warning.
1523 */
1524 JSC$parser_peek_token (stream);
1525 var peek_linenum = JSC$parser_peek_token_linenum;
1526
1527 /* The expression to throw. */
1528 var expr = JSC$parser_parse_expr (stream);
1529 if (typeof expr == "boolean")
1530 JSC$parser_syntax_error ();
1531
1532 if (JSC$warn_strict_ecma && peek_linenum > linenum)
1533 JSC$warning (JSC$filename + ":" + JSC$linenum.toString ()
1534 + ": warning: ECMAScript don't allow line terminators"
1535 + " between `throw' and expression");
1536
1537 JSC$parser_get_semicolon_asci (stream);
1538
1539 return new JSC$stmt_throw (linenum, expr);
1540 }
1541 else
1542 /* Can't parse more. We'r done. */
1543 return false;
1544 }
1545 }
1546
1547
1548 function JSC$parser_parse_switch (stream)
1549 {
1550 var linenum = JSC$parser_token_linenum;
1551
1552 if (JSC$parser_get_token (stream) != #'(')
1553 JSC$parser_syntax_error ();
1554
1555 var expr = JSC$parser_parse_expr (stream);
1556 if (!expr)
1557 JSC$parser_syntax_error ();
1558
1559 if (JSC$parser_get_token (stream) != #')')
1560 JSC$parser_syntax_error ();
1561
1562 if (JSC$parser_get_token (stream) != #'{')
1563 JSC$parser_syntax_error ();
1564
1565 /* Parse case clauses. */
1566 var clauses = new Array ();
1567 while (true)
1568 {
1569 var token = JSC$parser_get_token (stream);
1570
1571 if (token == #'}')
1572 break;
1573 else if (token == JSC$tCASE || token == JSC$tDEFAULT)
1574 {
1575 var stmts = new Array ();
1576 stmts.expr = null;
1577
1578 if (token == JSC$tCASE)
1579 {
1580 stmts.expr = JSC$parser_parse_expr (stream);
1581 if (!stmts.expr)
1582 JSC$parser_syntax_error ();
1583 }
1584 if (JSC$parser_get_token (stream) != #':')
1585 JSC$parser_syntax_error ();
1586
1587 stmts.linenum = JSC$parser_token_linenum;
1588
1589 /* Read the statement list. */
1590 while (true)
1591 {
1592 token = JSC$parser_peek_token (stream);
1593 if (token == #'}' || token == JSC$tCASE || token == JSC$tDEFAULT)
1594 /* Done with this branch. */
1595 break;
1596
1597 var stmt = JSC$parser_parse_stmt (stream);
1598 if (!stmt)
1599 JSC$parser_syntax_error ();
1600
1601 stmts.push (stmt);
1602 }
1603
1604 stmts.last_linenum = JSC$parser_token_linenum;
1605
1606 /* One clause parsed. */
1607 clauses.push (stmts);
1608 }
1609 else
1610 JSC$parser_syntax_error ();
1611 }
1612
1613 return new JSC$stmt_switch (linenum, JSC$parser_token_linenum, expr,
1614 clauses);
1615 }
1616
1617
1618 function JSC$parser_parse_try (stream)
1619 {
1620 var linenum = JSC$parser_token_linenum;
1621
1622 var block = JSC$parser_parse_stmt (stream);
1623 if (!block)
1624 JSC$parser_syntax_error ();
1625
1626 var try_block_last_linenum = JSC$parser_token_linenum;
1627
1628 /* Now we must see `catch' or `finally'. */
1629 var token = JSC$parser_peek_token (stream);
1630 if (token != JSC$tCATCH && token != JSC$tFINALLY)
1631 JSC$parser_syntax_error ();
1632
1633 var catch_list = false;
1634 if (token == JSC$tCATCH)
1635 {
1636 /* Parse catch list. */
1637
1638 catch_list = new Array ();
1639 catch_list.linenum = JSC$parser_peek_token_linenum;
1640
1641 while (token == JSC$tCATCH)
1642 {
1643 JSC$parser_get_token (stream);
1644 var c = new Object ();
1645 c.linenum = JSC$parser_token_linenum;
1646
1647 if (JSC$parser_get_token (stream) != #'(')
1648 JSC$parser_syntax_error ();
1649
1650 if (JSC$parser_get_token (stream) != JSC$tIDENTIFIER)
1651 JSC$parser_syntax_error ();
1652 c.id = JSC$parser_token_value;
1653
1654 c.guard = false;
1655 if (JSC$parser_peek_token (stream) == JSC$tIF)
1656 {
1657 JSC$parser_get_token (stream);
1658 c.guard = JSC$parser_parse_expr (stream);
1659 if (!c.guard)
1660 JSC$parser_syntax_error ();
1661 }
1662
1663 if (JSC$parser_get_token (stream) != #')')
1664 JSC$parser_syntax_error ();
1665
1666 c.stmt = JSC$parser_parse_stmt (stream);
1667 if (!c.stmt)
1668 JSC$parser_syntax_error ();
1669
1670 catch_list.push (c);
1671
1672 token = JSC$parser_peek_token (stream);
1673 }
1674
1675 catch_list.last_linenum = JSC$parser_token_linenum;
1676 }
1677
1678 var fin = false;
1679 if (token == JSC$tFINALLY)
1680 {
1681 /* Parse the finally. */
1682 JSC$parser_get_token (stream);
1683
1684 fin = JSC$parser_parse_stmt (stream);
1685 if (!fin)
1686 JSC$parser_syntax_error ();
1687 }
1688
1689 return new JSC$stmt_try (linenum, try_block_last_linenum,
1690 JSC$parser_token_linenum, block, catch_list,
1691 fin);
1692 }
1693
1694
1695 function JSC$parser_parse_variable_stmt (stream)
1696 {
1697 var list, id, expr, token;
1698
1699 if (JSC$parser_peek_token (stream) != JSC$tVAR)
1700 return false;
1701 JSC$parser_get_token (stream);
1702 var ln = JSC$parser_token_linenum;
1703
1704 list = new Array ();
1705
1706 while (true)
1707 {
1708 token = JSC$parser_peek_token (stream);
1709 if (token == JSC$tIDENTIFIER)
1710 {
1711 JSC$parser_get_token ();
1712 id = JSC$parser_token_value;
1713
1714 if (JSC$parser_peek_token (stream) == #'=')
1715 {
1716 JSC$parser_get_token (stream);
1717 expr = JSC$parser_parse_assignment_expr (stream);
1718 if (typeof expr == "boolean")
1719 JSC$parser_syntax_error ();
1720 }
1721 else
1722 expr = null;
1723
1724 list.push (new JSC$var_declaration (id, expr));
1725
1726 /* Check if we have more input. */
1727 if (JSC$parser_peek_token (stream) == #',')
1728 {
1729 /* Yes we have. */
1730 JSC$parser_get_token (stream);
1731
1732 /* The next token must be tIDENTIFIER. */
1733 if (JSC$parser_peek_token (stream) != JSC$tIDENTIFIER)
1734 JSC$parser_syntax_error ();
1735 }
1736 else
1737 {
1738 /* No, we don't. */
1739 JSC$parser_get_semicolon_asci (stream);
1740 break;
1741 }
1742 }
1743 else
1744 {
1745 /* We'r done. */
1746 JSC$parser_get_semicolon_asci (stream);
1747 break;
1748 }
1749 }
1750
1751 /* There must be at least one variable declaration. */
1752 if (list.length == 0)
1753 JSC$parser_syntax_error ();
1754
1755 return new JSC$stmt_variable (ln, list);
1756 }
1757
1758
1759 function JSC$parser_parse_if_stmt (stream)
1760 {
1761 var expr, stmt, stmt2;
1762
1763 if (JSC$parser_peek_token (stream) != JSC$tIF)
1764 return false;
1765 JSC$parser_get_token (stream);
1766 var ln = JSC$parser_token_linenum;
1767
1768 if (JSC$parser_get_token (stream) != #'(')
1769 JSC$parser_syntax_error ();
1770
1771 expr = JSC$parser_parse_expr (stream);
1772 if (typeof expr == "boolean")
1773 JSC$parser_syntax_error ();
1774
1775 if (JSC$parser_get_token (stream) != #')')
1776 JSC$parser_syntax_error ();
1777
1778 stmt = JSC$parser_parse_stmt (stream);
1779 if (typeof stmt == "boolean")
1780 JSC$parser_syntax_error ();
1781
1782 if (JSC$parser_peek_token (stream) == JSC$tELSE)
1783 {
1784 JSC$parser_get_token (stream);
1785 stmt2 = JSC$parser_parse_stmt (stream);
1786 if (typeof stmt2 == "boolean")
1787 JSC$parser_syntax_error ();
1788 }
1789 else
1790 stmt2 = null;
1791
1792 return new JSC$stmt_if (ln, expr, stmt, stmt2);
1793 }
1794
1795
1796 function JSC$parser_parse_iteration_stmt (stream)
1797 {
1798 var token, expr1, expr2, expr3, stmt;
1799
1800 token = JSC$parser_peek_token (stream);
1801 if (token == JSC$tDO)
1802 {
1803 /* do Statement while (Expression); */
1804 JSC$parser_get_token (stream);
1805 var ln = JSC$parser_token_linenum;
1806
1807 stmt = JSC$parser_parse_stmt (stream);
1808 if (typeof stmt == "boolean")
1809 JSC$parser_syntax_error ();
1810
1811 if (JSC$parser_get_token (stream) != JSC$tWHILE)
1812 JSC$parser_syntax_error ();
1813
1814 if (JSC$parser_get_token (stream) != #'(')
1815 JSC$parser_syntax_error ();
1816
1817 expr1 = JSC$parser_parse_expr (stream);
1818 if (typeof expr1 == "boolean")
1819 JSC$parser_syntax_error ();
1820
1821 if (JSC$parser_get_token (stream) != #')')
1822 JSC$parser_syntax_error ();
1823
1824 JSC$parser_get_semicolon_asci (stream);
1825
1826 return new JSC$stmt_do_while (ln, expr1, stmt);
1827 }
1828 else if (token == JSC$tWHILE)
1829 {
1830 /* while (Expression) Statement */
1831 JSC$parser_get_token (stream);
1832 var ln = JSC$parser_token_linenum;
1833
1834 if (JSC$parser_get_token (stream) != #'(')
1835 JSC$parser_syntax_error ();
1836
1837 expr1 = JSC$parser_parse_expr (stream);
1838 if (typeof expr1 == "boolean")
1839 JSC$parser_syntax_error ();
1840
1841 if (JSC$parser_get_token (stream) != #')')
1842 JSC$parser_syntax_error ();
1843
1844 stmt = JSC$parser_parse_stmt (stream);
1845 if (typeof stmt == "boolean")
1846 JSC$parser_syntax_error ();
1847
1848 return new JSC$stmt_while (ln, expr1, stmt);
1849 }
1850 else if (token == JSC$tFOR)
1851 {
1852 JSC$parser_get_token (stream);
1853 var ln = JSC$parser_token_linenum;
1854
1855 if (JSC$parser_get_token (stream) != #'(')
1856 JSC$parser_syntax_error ();
1857
1858 /* Init */
1859
1860 var vars = null;
1861
1862 token = JSC$parser_peek_token (stream);
1863 if (token == JSC$tVAR)
1864 {
1865 JSC$parser_get_token (stream);
1866 vars = new Array ();
1867
1868 while (true)
1869 {
1870 /* The identifier. */
1871 token = JSC$parser_peek_token (stream);
1872 if (token != JSC$tIDENTIFIER)
1873 break;
1874
1875 JSC$parser_get_token (stream);
1876 var id = JSC$parser_token_value;
1877
1878 /* Possible initializer. */
1879 var expr = null;
1880 if (JSC$parser_peek_token (stream) == #'=')
1881 {
1882 JSC$parser_get_token (stream);
1883 expr = JSC$parser_parse_assignment_expr (stream);
1884 if (!expr)
1885 JSC$parser_syntax_error ();
1886 }
1887
1888 vars.push (new JSC$var_declaration (id, expr));
1889
1890 /* Check if we have more input. */
1891 if (JSC$parser_peek_token (stream) == #',')
1892 {
1893 /* Yes we have. */
1894 JSC$parser_get_token (stream);
1895
1896 /* The next token must be tIDENTIFIER. */
1897 if (JSC$parser_peek_token (stream) != JSC$tIDENTIFIER)
1898 JSC$parser_syntax_error ();
1899 }
1900 else
1901 /* No more input. */
1902 break;
1903 }
1904
1905 /* Must have at least one variable declaration. */
1906 if (vars.length == 0)
1907 JSC$parser_syntax_error ();
1908 }
1909 else if (token != #';')
1910 {
1911 expr1 = JSC$parser_parse_expr (stream);
1912 if (typeof expr1 == "boolean")
1913 JSC$parser_syntax_error ();
1914 }
1915 else
1916 expr1 = null;
1917
1918 token = JSC$parser_get_token (stream);
1919 var for_in = false;
1920
1921 if (token == #';')
1922 {
1923 /* Normal for-statement. */
1924
1925 /* Check */
1926 if (JSC$parser_peek_token (stream) != #';')
1927 {
1928 expr2 = JSC$parser_parse_expr (stream);
1929 if (typeof expr2 == "boolean")
1930 JSC$parser_syntax_error ();
1931 }
1932 else
1933 expr2 = null;
1934
1935 if (JSC$parser_get_token (stream) != #';')
1936 JSC$parser_syntax_error ();
1937
1938 /* Increment */
1939 if (JSC$parser_peek_token (stream) != #')')
1940 {
1941 expr3 = JSC$parser_parse_expr (stream);
1942 if (typeof expr3 == "boolean")
1943 JSC$parser_syntax_error ();
1944 }
1945 else
1946 expr3 = null;
1947 }
1948 else if (token == JSC$tIN)
1949 {
1950 /* The `for (VAR in EXPR)'-statement. */
1951
1952 for_in = true;
1953
1954 if (expr1)
1955 {
1956 /* The first expression must be an identifier. */
1957 if (expr1.etype != JSC$EXPR_IDENTIFIER)
1958 JSC$parser_syntax_error ();
1959 }
1960 else
1961 {
1962 /* We must have only one variable declaration. */
1963 if (vars.length != 1)
1964 JSC$parser_syntax_error ();
1965 }
1966
1967 /* The second expressions. */
1968 expr2 = JSC$parser_parse_expr (stream);
1969 if (typeof expr2 == "boolean")
1970 JSC$parser_syntax_error ();
1971 }
1972 else
1973 JSC$parser_syntax_error ();
1974
1975 if (JSC$parser_get_token (stream) != #')')
1976 JSC$parser_syntax_error ();
1977
1978 /* Stmt. */
1979 stmt = JSC$parser_parse_stmt (stream);
1980 if (typeof stmt == "boolean")
1981 JSC$parser_syntax_error ();
1982
1983 if (for_in)
1984 return new JSC$stmt_for_in (ln, vars, expr1, expr2, stmt);
1985
1986 return new JSC$stmt_for (ln, vars, expr1, expr2, expr3, stmt);
1987 }
1988 return false;
1989 }
1990
1991
1992 function JSC$parser_parse_expr (stream)
1993 {
1994 var expr, expr2;
1995
1996 if (typeof (expr = JSC$parser_parse_assignment_expr (stream))
1997 == "boolean")
1998 return false;
1999
2000 /* Check for the comma expression. */
2001 while (JSC$parser_peek_token (stream) == #',')
2002 {
2003 JSC$parser_get_token (stream);
2004 var ln = JSC$parser_token_linenum;
2005
2006 if (typeof (expr2 = JSC$parser_parse_assignment_expr (stream))
2007 == "boolean")
2008 JSC$parser_syntax_error ();
2009 expr = new JSC$expr_comma (ln, expr, expr2);
2010 }
2011
2012 return expr;
2013 }
2014
2015
2016 function JSC$parser_parse_assignment_expr (stream)
2017 {
2018 var expr, expr2, token;
2019
2020 if (typeof (expr = JSC$parser_parse_conditional_expr (stream))
2021 == "boolean")
2022 return false;
2023
2024 if (JSC$parser_expr_is_left_hand_side (expr))
2025 {
2026 token = JSC$parser_peek_token (stream);
2027 if (token == #'=' || token == JSC$tMULA
2028 || token == JSC$tDIVA || token == JSC$tMODA
2029 || token == JSC$tADDA || token == JSC$tSUBA
2030 || token == JSC$tLSIA || token == JSC$tRSIA
2031 || token == JSC$tRRSA || token == JSC$tANDA
2032 || token == JSC$tXORA || token == JSC$tORA)
2033 {
2034 JSC$parser_get_token (stream);
2035 var ln = JSC$parser_token_linenum;
2036
2037 expr2 = JSC$parser_parse_assignment_expr (stream);
2038 if (typeof expr2 == "boolean")
2039 JSC$parser_syntax_error ();
2040
2041 expr = new JSC$expr_assignment (ln, token, expr, expr2);
2042 }
2043 }
2044
2045 if (JSC$optimize_constant_folding && expr.constant_folding)
2046 return expr.constant_folding ();
2047
2048 return expr;
2049 }
2050
2051
2052 function JSC$parser_parse_conditional_expr (stream)
2053 {
2054 var expr, expr2, expr3, token;
2055
2056 if (typeof (expr = JSC$parser_parse_logical_or_expr (stream))
2057 == "boolean")
2058 return false;
2059
2060 token = JSC$parser_peek_token (stream);
2061 if (token == #'?')
2062 {
2063 JSC$parser_get_token (stream);
2064 var ln = JSC$parser_token_linenum;
2065
2066 expr2 = JSC$parser_parse_assignment_expr (stream);
2067 if (typeof expr2 == "boolean")
2068 JSC$parser_syntax_error ();
2069
2070 if (JSC$parser_get_token (stream) != #':')
2071 JSC$parser_syntax_error ();
2072 expr3 = JSC$parser_parse_assignment_expr (stream);
2073 if (typeof expr3 == "boolean")
2074 JSC$parser_syntax_error ();
2075
2076 expr = new JSC$expr_quest_colon (ln, expr, expr2, expr3);
2077 }
2078
2079 return expr;
2080 }
2081
2082
2083 function JSC$parser_parse_logical_or_expr (stream)
2084 {
2085 var expr, expr2;
2086
2087 if (typeof (expr = JSC$parser_parse_logical_and_expr (stream))
2088 == "boolean")
2089 return false;
2090
2091 while (JSC$parser_peek_token (stream) == JSC$tOR)
2092 {
2093 JSC$parser_get_token (stream);
2094 var ln = JSC$parser_token_linenum;
2095
2096 expr2 = JSC$parser_parse_logical_and_expr (stream);
2097 if (typeof expr2 == "boolean")
2098 JSC$parser_syntax_error ();
2099
2100 expr = new JSC$expr_logical_or (ln, expr, expr2);
2101 }
2102
2103 return expr;
2104 }
2105
2106
2107 function JSC$parser_parse_logical_and_expr (stream)
2108 {
2109 var expr, expr2;
2110
2111 if (typeof (expr = JSC$parser_parse_bitwise_or_expr (stream))
2112 == "boolean")
2113 return false;
2114
2115 while (JSC$parser_peek_token (stream) == JSC$tAND)
2116 {
2117 JSC$parser_get_token (stream);
2118 var ln = JSC$parser_token_linenum;
2119
2120 expr2 = JSC$parser_parse_bitwise_or_expr (stream);
2121 if (typeof expr2 == "boolean")
2122 JSC$parser_syntax_error ();
2123
2124 expr = new JSC$expr_logical_and (ln, expr, expr2);
2125 }
2126
2127 return expr;
2128 }
2129
2130
2131 function JSC$parser_parse_bitwise_or_expr (stream)
2132 {
2133 var expr, expr2;
2134
2135 if (typeof (expr = JSC$parser_parse_bitwise_xor_expr (stream))
2136 == "boolean")
2137 return false;
2138
2139 while (JSC$parser_peek_token (stream) == #'|')
2140 {
2141 JSC$parser_get_token (stream);
2142 var ln = JSC$parser_token_linenum;
2143
2144 expr2 = JSC$parser_parse_bitwise_xor_expr (stream);
2145 if (typeof expr2 == "boolean")
2146 JSC$parser_syntax_error ();
2147
2148 expr = new JSC$expr_bitwise_or (ln, expr, expr2);
2149 }
2150
2151 return expr;
2152 }
2153
2154
2155 function JSC$parser_parse_bitwise_xor_expr (stream)
2156 {
2157 var expr, expr2;
2158
2159 if (typeof (expr = JSC$parser_parse_bitwise_and_expr (stream))
2160 == "boolean")
2161 return false;
2162
2163 while (JSC$parser_peek_token (stream) == #'^')
2164 {
2165 JSC$parser_get_token (stream);
2166 var ln = JSC$parser_token_linenum;
2167
2168 expr2 = JSC$parser_parse_bitwise_and_expr (stream);
2169 if (typeof expr2 == "boolean")
2170 JSC$parser_syntax_error ();
2171
2172 expr = new JSC$expr_bitwise_xor (ln, expr, expr2);
2173 }
2174
2175 return expr;
2176 }
2177
2178
2179 function JSC$parser_parse_bitwise_and_expr (stream)
2180 {
2181 var expr, expr2;
2182
2183 if (typeof (expr = JSC$parser_parse_equality_expr (stream))
2184 == "boolean")
2185 return false;
2186
2187 while (JSC$parser_peek_token (stream) == #'&')
2188 {
2189 JSC$parser_get_token (stream);
2190 var ln = JSC$parser_token_linenum;
2191
2192 expr2 = JSC$parser_parse_equality_expr (stream);
2193 if (typeof expr2 == "boolean")
2194 JSC$parser_syntax_error ();
2195
2196 expr = new JSC$expr_bitwise_and (ln, expr, expr2);
2197 }
2198
2199 return expr;
2200 }
2201
2202
2203 function JSC$parser_parse_equality_expr (stream)
2204 {
2205 var expr, expr2, token;
2206
2207 if (typeof (expr = JSC$parser_parse_relational_expr (stream))
2208 == "boolean")
2209 return false;
2210
2211 token = JSC$parser_peek_token (stream);
2212 while (token == JSC$tEQUAL || token == JSC$tNEQUAL
2213 || token == JSC$tSEQUAL || token == JSC$tSNEQUAL)
2214 {
2215 JSC$parser_get_token (stream);
2216 var ln = JSC$parser_token_linenum;
2217
2218 expr2 = JSC$parser_parse_relational_expr (stream);
2219 if (typeof expr2 == "boolean")
2220 JSC$parser_syntax_error ();
2221
2222 expr = new JSC$expr_equality (ln, token, expr, expr2);
2223 token = JSC$parser_peek_token (stream);
2224 }
2225
2226 return expr;
2227 }
2228
2229
2230 function JSC$parser_parse_relational_expr (stream)
2231 {
2232 var expr, expr2, token;
2233
2234 if (typeof (expr = JSC$parser_parse_shift_expr (stream))
2235 == "boolean")
2236 return false;
2237
2238 token = JSC$parser_peek_token (stream);
2239 while (token == #'<' || token == #'>' || token == JSC$tLE
2240 || token == JSC$tGE)
2241 {
2242 JSC$parser_get_token (stream);
2243 var ln = JSC$parser_token_linenum;
2244
2245 expr2 = JSC$parser_parse_shift_expr (stream);
2246 if (typeof expr2 == "boolean")
2247 JSC$parser_syntax_error ();
2248
2249 expr = new JSC$expr_relational (ln, token, expr, expr2);
2250 token = JSC$parser_peek_token (stream);
2251 }
2252
2253 return expr;
2254 }
2255
2256
2257 function JSC$parser_parse_shift_expr (stream)
2258 {
2259 var expr, expr2, token;
2260
2261 if (typeof (expr = JSC$parser_parse_additive_expr (stream))
2262 == "boolean")
2263 return false;
2264
2265 token = JSC$parser_peek_token (stream);
2266 while (token == JSC$tLSHIFT || token == JSC$tRSHIFT || token == JSC$tRRSHIFT)
2267 {
2268 JSC$parser_get_token (stream);
2269 var ln = JSC$parser_token_linenum;
2270
2271 expr2 = JSC$parser_parse_additive_expr (stream);
2272
2273 if (typeof expr2 == "boolean")
2274 JSC$parser_syntax_error ();
2275
2276 expr = new JSC$expr_shift (ln, token, expr, expr2);
2277 token = JSC$parser_peek_token (stream);
2278 }
2279
2280 return expr;
2281 }
2282
2283
2284 function JSC$parser_parse_additive_expr (stream)
2285 {
2286 var expr, expr2, token;
2287
2288 if (typeof (expr = JSC$parser_parse_multiplicative_expr (stream))
2289 == "boolean")
2290 return false;
2291
2292 token = JSC$parser_peek_token (stream);
2293 while (token == #'+' || token == #'-')
2294 {
2295 JSC$parser_get_token (stream);
2296 var ln = JSC$parser_token_linenum;
2297
2298 expr2 = JSC$parser_parse_multiplicative_expr (stream);
2299 if (typeof expr2 == "boolean")
2300 JSC$parser_syntax_error ();
2301
2302 expr = new JSC$expr_additive (ln, token, expr, expr2);
2303 token = JSC$parser_peek_token (stream);
2304 }
2305
2306 return expr;
2307 }
2308
2309
2310 function JSC$parser_parse_multiplicative_expr (stream)
2311 {
2312 var expr, expr2, token;
2313
2314 if (typeof (expr = JSC$parser_parse_unary_expr (stream)) == "boolean")
2315 return false;
2316
2317 token = JSC$parser_peek_token (stream);
2318 while (token == #'*' || token == #'/' || token == #'%')
2319 {
2320 JSC$parser_get_token (stream);
2321 var ln = JSC$parser_token_linenum;
2322
2323 expr2 = JSC$parser_parse_unary_expr (stream);
2324 if (typeof expr2 == "boolean")
2325 JSC$parser_syntax_error ();
2326
2327 expr = new JSC$expr_multiplicative (ln, token, expr, expr2);
2328 token = JSC$parser_peek_token (stream);
2329 }
2330
2331 return expr;
2332 }
2333
2334
2335 function JSC$parser_parse_unary_expr (stream)
2336 {
2337 var expr, token;
2338
2339 token = JSC$parser_peek_token (stream);
2340 if (token == JSC$tDELETE
2341 || token == JSC$tVOID
2342 || token == JSC$tTYPEOF
2343 || token == JSC$tPLUSPLUS
2344 || token == JSC$tMINUSMINUS
2345 || token == #'+'
2346 || token == #'-'
2347 || token == #'~'
2348 || token == #'!')
2349 {
2350 JSC$parser_get_token (stream);
2351 var ln = JSC$parser_token_linenum;
2352
2353 expr = JSC$parser_parse_unary_expr (stream);
2354 if (typeof expr == "boolean")
2355 JSC$parser_syntax_error ();
2356
2357 return new JSC$expr_unary (ln, token, expr);
2358 }
2359
2360 return JSC$parser_parse_postfix_expr (stream);
2361 }
2362
2363
2364 function JSC$parser_parse_postfix_expr (stream)
2365 {
2366 var expr, token;
2367
2368 if (typeof (expr = JSC$parser_parse_left_hand_side_expr (stream))
2369 == "boolean")
2370 return false;
2371
2372 token = JSC$parser_peek_token (stream);
2373 if (token == JSC$tPLUSPLUS || token == JSC$tMINUSMINUS)
2374 {
2375 if (JSC$parser_peek_token_linenum > JSC$parser_token_linenum)
2376 {
2377 if (JSC$warn_missing_semicolon)
2378 JSC$warning (JSC$filename + ":"
2379 + JSC$parser_token_linenum.toString ()
2380 + ": warning: automatic semicolon insertion cuts the expression before ++ or --");
2381 }
2382 else
2383 {
2384 JSC$parser_get_token (stream);
2385 var ln = JSC$parser_token_linenum;
2386
2387 return new JSC$expr_postfix (ln, token, expr);
2388 }
2389 }
2390
2391 return expr;
2392 }
2393
2394
2395 function JSC$parser_parse_left_hand_side_expr (stream)
2396 {
2397 var expr, args, token, expr2;
2398
2399 if (typeof (expr = JSC$parser_parse_member_expr (stream))
2400 == "boolean")
2401 return false;
2402
2403 /* Parse the possible first pair of arguments. */
2404 if (JSC$parser_peek_token (stream) == #'(')
2405 {
2406 var ln = JSC$parser_peek_token_linenum;
2407
2408 args = JSC$parser_parse_arguments (stream);
2409 if (typeof args == "boolean")
2410 JSC$parser_syntax_error ();
2411
2412 expr = new JSC$expr_call (ln, expr, args);
2413 }
2414 else
2415 return expr;
2416
2417 /* Parse to possibly following arguments and selectors. */
2418 while ((token = JSC$parser_peek_token (stream)) == #'('
2419 || token == #'[' || token == #'.')
2420 {
2421 var ln = JSC$parser_peek_token_linenum;
2422
2423 if (token == #'(')
2424 {
2425 args = JSC$parser_parse_arguments (stream);
2426 expr = new JSC$expr_call (ln, expr, args);
2427 }
2428 else if (token == #'[')
2429 {
2430 JSC$parser_get_token (stream);
2431
2432 expr2 = JSC$parser_parse_expr (stream);
2433 if (typeof expr2 == "boolean")
2434 JSC$parser_syntax_error ();
2435
2436 if (JSC$parser_get_token (stream) != #']')
2437 JSC$parser_syntax_error ();
2438
2439 expr = new JSC$expr_object_array (ln, expr, expr2);
2440 }
2441 else
2442 {
2443 JSC$parser_get_token (stream);
2444 if (JSC$parser_get_token (stream) != JSC$tIDENTIFIER)
2445 JSC$parser_syntax_error ();
2446
2447 expr = new JSC$expr_object_property (ln, expr,
2448 JSC$parser_token_value);
2449 }
2450 }
2451
2452 return expr;
2453 }
2454
2455
2456 function JSC$parser_parse_member_expr (stream)
2457 {
2458 var expr, args, token, expr2;
2459
2460 if (typeof (expr = JSC$parser_parse_primary_expr (stream))
2461 == "boolean")
2462 {
2463 token = JSC$parser_peek_token (stream);
2464
2465 if (token == JSC$tNEW)
2466 {
2467 JSC$parser_get_token (stream);
2468 var ln = JSC$parser_token_linenum;
2469
2470 expr = JSC$parser_parse_member_expr (stream);
2471 if (typeof expr == "boolean")
2472 JSC$parser_syntax_error ();
2473
2474 if (JSC$parser_peek_token (stream) == #'(')
2475 {
2476 args = JSC$parser_parse_arguments (stream);
2477 if (typeof args == "boolean")
2478 JSC$parser_syntax_error ();
2479 }
2480 else
2481 return new JSC$expr_new (ln, expr, null);
2482
2483 expr = new JSC$expr_new (ln, expr, args);
2484 }
2485 else
2486 return false;
2487 }
2488
2489 /* Ok, now we have valid starter. */
2490 token = JSC$parser_peek_token (stream);
2491 while (token == #'[' || token == #'.')
2492 {
2493 JSC$parser_get_token (stream);
2494 var ln = JSC$parser_token_linenum;
2495
2496 if (token == #'[')
2497 {
2498 expr2 = JSC$parser_parse_expr (stream);
2499 if (typeof expr2 == "boolean")
2500 JSC$parser_syntax_error ();
2501
2502 if (JSC$parser_get_token (stream) != #']')
2503 JSC$parser_syntax_error ();
2504
2505 expr = new JSC$expr_object_array (ln, expr, expr2);
2506 }
2507 else
2508 {
2509 if (JSC$parser_get_token (stream) != JSC$tIDENTIFIER)
2510 JSC$parser_syntax_error ();
2511
2512 expr = new JSC$expr_object_property (ln, expr,
2513 JSC$parser_token_value);
2514 }
2515
2516 token = JSC$parser_peek_token (stream);
2517 }
2518
2519 return expr;
2520 }
2521
2522
2523 function JSC$parser_parse_primary_expr (stream)
2524 {
2525 var token, val;
2526
2527 token = JSC$parser_peek_token (stream);
2528 var ln = JSC$parser_peek_token_linenum;
2529
2530 if (token == JSC$tTHIS)
2531 val = new JSC$expr_this (ln);
2532 else if (token == JSC$tIDENTIFIER)
2533 val = new JSC$expr_identifier (ln, JSC$parser_peek_token_value);
2534 else if (token == JSC$tFLOAT)
2535 val = new JSC$expr_float (ln, JSC$parser_peek_token_value);
2536 else if (token == JSC$tINTEGER)
2537 val = new JSC$expr_integer (ln, JSC$parser_peek_token_value);
2538 else if (token == JSC$tSTRING)
2539 val = new JSC$expr_string (ln, JSC$parser_peek_token_value);
2540 else if (token == #'/')
2541 {
2542 /*
2543 * Kludge alert! The regular expression constants (/.../) and
2544 * div operands are impossible to distinguish, based only on the
2545 * lexical analysis. Therefore, we need some syntactical
2546 * knowledge when the regular expression constants are possible
2547 * at all. This is the place where they can appear. In all
2548 * other places, the character `/' is interpreted as a div
2549 * operator.
2550 */
2551 JSC$parser_get_token (stream);
2552
2553 return new JSC$expr_regexp (ln, JSC$lexer_read_regexp_constant (stream));
2554 }
2555 else if (token == JSC$tNULL)
2556 val = new JSC$expr_null (ln);
2557 else if (token == JSC$tTRUE)
2558 val = new JSC$expr_true (ln);
2559 else if (token == JSC$tFALSE)
2560 val = new JSC$expr_false (ln);
2561 else if (token == #'[')
2562 {
2563 /* Array initializer. */
2564 /* TODO: SharpVarDefinition_{opt} */
2565
2566 JSC$parser_get_token (stream);
2567
2568 var items = new Array ();
2569 var pos = 0;
2570
2571 while ((token = JSC$parser_peek_token (stream)) != #']')
2572 {
2573 if (token == #',')
2574 {
2575 JSC$parser_get_token (stream);
2576 items[++pos] = false;
2577 continue;
2578 }
2579
2580 var expr = JSC$parser_parse_assignment_expr (stream);
2581 if (!expr)
2582 JSC$parser_syntax_error ();
2583
2584 items[pos] = expr;
2585
2586 /* Got one expression. It must be followed by ',' or ']'. */
2587 token = JSC$parser_peek_token (stream);
2588 if (token != #',' && token != #']')
2589 JSC$parser_syntax_error ();
2590 }
2591
2592 val = new JSC$expr_array_initializer (ln, items);
2593 }
2594 else if (token == #'{')
2595 {
2596 /* Object literal. */
2597 /* TODO: SharpVarDefinition_{opt} */
2598
2599 JSC$parser_get_token (stream);
2600
2601 var items = new Array ();
2602
2603 while ((token = JSC$parser_peek_token (stream)) != #'}')
2604 {
2605 var pair = new Object ();
2606
2607 token = JSC$parser_get_token (stream);
2608
2609 pair.linenum = JSC$linenum;
2610 pair.id_type = token;
2611 pair.id = JSC$parser_token_value;
2612
2613 if (token != JSC$tIDENTIFIER && token != JSC$tSTRING
2614 && token != JSC$tINTEGER)
2615 JSC$parser_syntax_error ();
2616
2617 if (JSC$parser_get_token (stream) != #':')
2618 JSC$parser_syntax_error ();
2619
2620 pair.expr = JSC$parser_parse_assignment_expr (stream);
2621 if (!pair.expr)
2622 JSC$parser_syntax_error ();
2623
2624 items.push (pair);
2625
2626 /*
2627 * Got one property, initializer pair. It must be followed
2628 * by ',' or '}'.
2629 */
2630 token = JSC$parser_peek_token (stream);
2631 if (token == #',')
2632 {
2633 /* Ok, we have more items. */
2634 JSC$parser_get_token (stream);
2635
2636 token = JSC$parser_peek_token (stream);
2637 if (token != JSC$tIDENTIFIER && token != JSC$tSTRING
2638 && token != JSC$tINTEGER)
2639 JSC$parser_syntax_error ();
2640 }
2641 else if (token != #'}' && token)
2642 JSC$parser_syntax_error ();
2643 }
2644
2645 val = new JSC$expr_object_initializer (ln, items);
2646 }
2647 else if (token == #'(')
2648 {
2649 JSC$parser_get_token (stream);
2650
2651 val = JSC$parser_parse_expr (stream);
2652 if (typeof val == "boolean"
2653 || JSC$parser_peek_token (stream) != #')')
2654 JSC$parser_syntax_error ();
2655 }
2656 else
2657 return false;
2658
2659 JSC$parser_get_token (stream);
2660 return val;
2661 }
2662
2663
2664 function JSC$parser_parse_arguments (stream)
2665 {
2666 var args, item;
2667
2668 if (JSC$parser_peek_token (stream) != #'(')
2669 return false;
2670
2671 args = new Array ();
2672
2673 JSC$parser_get_token (stream);
2674 while (JSC$parser_peek_token (stream) != #')')
2675 {
2676 item = JSC$parser_parse_assignment_expr (stream);
2677 if (typeof item == "boolean")
2678 JSC$parser_syntax_error ();
2679 args.push (item);
2680
2681 var token = JSC$parser_peek_token (stream);
2682 if (token == #',')
2683 JSC$parser_get_token (stream);
2684 else if (token != #')')
2685 JSC$parser_syntax_error ();
2686 }
2687 JSC$parser_get_token (stream);
2688
2689 return args;
2690 }
2691
2692 \f
2693 /*
2694 Local variables:
2695 mode: c
2696 End:
2697 */
2698 /*
2699 * Grammar components.
2700 * Copyright (c) 1998 New Generation Software (NGS) Oy
2701 *
2702 * Author: Markku Rossi <mtr@ngs.fi>
2703 */
2704
2705 /*
2706 * This library is free software; you can redistribute it and/or
2707 * modify it under the terms of the GNU Library General Public
2708 * License as published by the Free Software Foundation; either
2709 * version 2 of the License, or (at your option) any later version.
2710 *
2711 * This library is distributed in the hope that it will be useful,
2712 * but WITHOUT ANY WARRANTY; without even the implied warranty of
2713 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2714 * Library General Public License for more details.
2715 *
2716 * You should have received a copy of the GNU Library General Public
2717 * License along with this library; if not, write to the Free
2718 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
2719 * MA 02111-1307, USA
2720 */
2721
2722 /*
2723 * $Source: /cygdrive/c/RCVS/CVS/ReactOS/reactos/lib/kjs/jsc/compiler.js,v $
2724 * $Id$
2725 */
2726
2727 /* General helpers. */
2728
2729 function JSC$gram_reset ()
2730 {
2731 JSC$label_count = 1;
2732 JSC$cont_break = new JSC$ContBreak ();
2733 }
2734
2735
2736 function JSC$alloc_label (num_labels)
2737 {
2738 JSC$label_count += num_labels;
2739
2740 return JSC$label_count - num_labels;
2741 }
2742
2743
2744 function JSC$format_label (num)
2745 {
2746 return ".L" + num.toString ();
2747 }
2748
2749
2750 function JSC$count_locals_from_stmt_list (list)
2751 {
2752 var i;
2753
2754 /* First, count how many variables we need at the toplevel. */
2755 var lcount = 0;
2756 for (i = 0; i < list.length; i++)
2757 lcount += list[i].count_locals (false);
2758
2759 /* Second, count the maximum amount needed by the nested blocks. */
2760 var rmax = 0;
2761 for (i = 0; i < list.length; i++)
2762 {
2763 var rc = list[i].count_locals (true);
2764 if (rc > rmax)
2765 rmax = rc;
2766 }
2767
2768 return lcount + rmax;
2769 }
2770
2771 /*
2772 * The handling of the `continue' and `break' labels for looping
2773 * constructs. The variable `JSC$cont_break' holds an instance of
2774 * JSC$ContBreak class. The instance contains a valid chain of
2775 * looping constructs and the currently active with and try testing
2776 * levels. The actual `continue', `break', and `return' statements
2777 * investigate the chain and generate appropriate `with_pop' and
2778 * `try_pop' operands.
2779 *
2780 * If the instance variable `inswitch' is true, the continue statement
2781 * is inside a switch statement. In this case, the continue statement
2782 * must pop one item from the stack. That item is the value of the
2783 * case expression.
2784 */
2785
2786 function JSC$ContBreakFrame (loop_break, loop_continue, inswitch, label, next)
2787 {
2788 this.loop_break = loop_break;
2789 this.loop_continue = loop_continue;
2790 this.inswitch = inswitch;
2791 this.label = label;
2792 this.next = next;
2793
2794 this.with_nesting = 0;
2795 this.try_nesting = 0;
2796 }
2797
2798
2799 function JSC$ContBreak ()
2800 {
2801 this.top = new JSC$ContBreakFrame (null, null, false, null);
2802 }
2803
2804 new JSC$ContBreak ();
2805
2806 function JSC$ContBreak$push (loop_break, loop_continue, inswitch, label)
2807 {
2808 this.top = new JSC$ContBreakFrame (loop_break, loop_continue, inswitch,
2809 label, this.top);
2810 }
2811 JSC$ContBreak.prototype.push = JSC$ContBreak$push;
2812
2813 function JSC$ContBreak$pop ()
2814 {
2815 if (this.top == null)
2816 error ("jsc: internal error: continue-break stack underflow");
2817
2818 this.top = this.top.next;
2819 }
2820 JSC$ContBreak.prototype.pop = JSC$ContBreak$pop;
2821
2822 /*
2823 * Count the currently active `try' nesting that should be removed on
2824 * `return' statement.
2825 */
2826 function JSC$ContBreak$try_return_nesting ()
2827 {
2828 var f;
2829 var count = 0;
2830
2831 for (f = this.top; f; f = f.next)
2832 count += f.try_nesting;
2833
2834 return count;
2835 }
2836 JSC$ContBreak.prototype.try_return_nesting = JSC$ContBreak$try_return_nesting;
2837
2838 /*
2839 * Count currently active `with' nesting that should be removed on
2840 * `continue' or `break' statement.
2841 */
2842 function JSC$ContBreak$count_with_nesting (label)
2843 {
2844 var f;
2845 var count = 0;
2846
2847 for (f = this.top; f; f = f.next)
2848 {
2849 count += f.with_nesting;
2850 if (label)
2851 {
2852 if (f.label == label)
2853 break;
2854 }
2855 else
2856 if (f.loop_continue)
2857 break;
2858 }
2859 return count;
2860 }
2861 JSC$ContBreak.prototype.count_with_nesting = JSC$ContBreak$count_with_nesting;
2862
2863 /*
2864 * Count the currently active `try' nesting that should be removed on
2865 * `continue' or `break' statement.
2866 */
2867 function JSC$ContBreak$count_try_nesting (label)
2868 {
2869 var f;
2870 var count = 0;
2871
2872 for (f = this.top; f; f = f.next)
2873 {
2874 count += f.try_nesting;
2875 if (label)
2876 {
2877 if (f.label == label)
2878 break;
2879 }
2880 else
2881 if (f.loop_continue)
2882 break;
2883 }
2884 return count;
2885 }
2886 JSC$ContBreak.prototype.count_try_nesting = JSC$ContBreak$count_try_nesting;
2887
2888 function JSC$ContBreak$count_switch_nesting (label)
2889 {
2890 var f;
2891 var count = 0;
2892
2893 for (f = this.top; f; f = f.next)
2894 {
2895 if (f.inswitch)
2896 count++;
2897 if (label)
2898 {
2899 if (f.label == label)
2900 break;
2901 }
2902 else
2903 if (f.loop_continue)
2904 break;
2905 }
2906 return count;
2907 }
2908 JSC$ContBreak.prototype.count_switch_nesting
2909 = JSC$ContBreak$count_switch_nesting;
2910
2911 function JSC$ContBreak$get_continue (label)
2912 {
2913 var f;
2914
2915 for (f = this.top; f; f = f.next)
2916 if (label)
2917 {
2918 if (f.label == label)
2919 return f.loop_continue;
2920 }
2921 else
2922 if (f.loop_continue)
2923 return f.loop_continue;
2924
2925 return null;
2926 }
2927 JSC$ContBreak.prototype.get_continue = JSC$ContBreak$get_continue;
2928
2929 function JSC$ContBreak$get_break (label)
2930 {
2931 var f;
2932
2933 for (f = this.top; f; f = f.next)
2934 if (label)
2935 {
2936 if (f.label == label)
2937 return f.loop_break;
2938 }
2939 else
2940 if (f.loop_break)
2941 return f.loop_break;
2942
2943 return null;
2944 }
2945 JSC$ContBreak.prototype.get_break = JSC$ContBreak$get_break;
2946
2947 function JSC$ContBreak$is_unique_label (label)
2948 {
2949 var f;
2950
2951 for (f = this.top; f; f = f.next)
2952 if (f.label == label)
2953 return false;
2954
2955 return true;
2956 }
2957 JSC$ContBreak.prototype.is_unique_label = JSC$ContBreak$is_unique_label;
2958
2959 JSC$cont_break = null;
2960
2961
2962 /* Function declaration. */
2963
2964 function JSC$function_declaration (ln, lbrace_ln, name, name_given, args,
2965 block, use_arguments_prop)
2966 {
2967 this.linenum = ln;
2968 this.lbrace_linenum = lbrace_ln;
2969 this.name = name;
2970 this.name_given = name_given;
2971 this.args = args;
2972 this.block = block;
2973 this.use_arguments_prop = use_arguments_prop;
2974 this.asm = JSC$function_declaration_asm;
2975 }
2976
2977 function JSC$function_declaration_asm ()
2978 {
2979 var i, a;
2980
2981 /* Define arguments. */
2982 JSC$ns.push_frame ();
2983
2984 for (i = 0, a = 2; i < this.args.length; i++, a++)
2985 JSC$ns.define_symbol (this.args[i], JSC$SCOPE_ARG, a, this.linenum);
2986
2987 /* Define the function name to be a global symbol. */
2988 new JSC$ASM_symbol (this.linenum, this.name).link ();
2989
2990 /* Check that function gets the required amount of arguments. */
2991 new JSC$ASM_load_arg (this.lbrace_linenum, 1).link ();
2992 new JSC$ASM_add_2_i (this.lbrace_linenum).link ();
2993 new JSC$ASM_min_args (this.lbrace_linenum, this.args.length + 2).link ();
2994
2995 /* Count how many local variables we need. */
2996 var num_locals = JSC$count_locals_from_stmt_list (this.block);
2997
2998 /* Is the `arguments' property of function instance used? */
2999 if (this.use_arguments_prop)
3000 num_locals++;
3001
3002 if (num_locals > 0)
3003 {
3004 new JSC$ASM_locals (this.lbrace_linenum, num_locals).link ();
3005 if (this.use_arguments_prop)
3006 {
3007 /*
3008 * Create an array for the arguments array and store it to
3009 * the first local variable.
3010 */
3011 var ln = this.lbrace_linenum;
3012 var locn = JSC$ns.alloc_local ();
3013 JSC$ns.define_symbol ("arguments", JSC$SCOPE_LOCAL, locn, ln);
3014
3015 new JSC$ASM_const_i0 (ln).link ();
3016 new JSC$ASM_load_global (ln, "Array").link ();
3017 new JSC$ASM_new (ln).link ();
3018 new JSC$ASM_swap (ln).link ();
3019 new JSC$ASM_apop (ln, 2).link ();
3020 new JSC$ASM_store_local (ln, locn).link ();
3021
3022 /* Push individual argumens to the array. */
3023
3024 /* Init the loop counter. */
3025 new JSC$ASM_const_i0 (ln).link ();
3026
3027 var l_loop = new JSC$ASM_label ();
3028 var l_out = new JSC$ASM_label ();
3029
3030 l_loop.link ();
3031
3032 /* Check if we'r done. */
3033 new JSC$ASM_dup (ln).link ();
3034 new JSC$ASM_load_arg (ln, 1).link ();
3035 new JSC$ASM_cmp_ge (ln).link ();
3036 new JSC$ASM_iftrue_b (ln, l_out).link ();
3037
3038 /* Load the nth argument to the top of the stack. */
3039 new JSC$ASM_dup (ln).link ();
3040 new JSC$ASM_add_2_i (ln).link ();
3041 new JSC$ASM_load_nth_arg (ln).link ();
3042
3043 /* Push it to the array. */
3044 new JSC$ASM_const_i1 (ln).link ();
3045 new JSC$ASM_load_local (ln, locn).link ();
3046 new JSC$ASM_call_method (ln, "push").link ();
3047 new JSC$ASM_pop_n (ln, 4).link ();
3048
3049 /* Increment loop counter and continue. */
3050 new JSC$ASM_add_1_i (ln).link ();
3051 new JSC$ASM_jmp (ln, l_loop).link ();
3052
3053 /* We'r done. */
3054 l_out.link ();
3055
3056 /* Pop the loop counter. */
3057 new JSC$ASM_pop (ln).link ();
3058 }
3059 }
3060
3061 /* Assembler for our body. */
3062 for (i = 0; i < this.block.length; i++)
3063 this.block[i].asm ();
3064
3065 /*
3066 * Every function must return something. We could check if all
3067 * control flows in this function ends to a return, but that would
3068 * bee too hard... Just append a return const_undefined. The optimizer
3069 * will remove it if it is not needed.
3070 */
3071 var ln;
3072 if (this.block.length > 0)
3073 ln = this.block[this.block.length - 1].linenum;
3074 else
3075 ln = this.linenum;
3076
3077 new JSC$ASM_const_undefined (ln).link ();
3078 new JSC$ASM_return (ln).link ();
3079
3080 /* Pop our namespace. */
3081 JSC$ns.pop_frame ();
3082 }
3083
3084
3085 function JSC$zero_function ()
3086 {
3087 return 0;
3088 }
3089
3090
3091 /*
3092 * Statements.
3093 */
3094
3095 /* Block. */
3096
3097 function JSC$stmt_block (ln, list)
3098 {
3099 this.stype = JSC$STMT_BLOCK;
3100 this.linenum = ln;
3101 this.stmts = list;
3102 this.asm = JSC$stmt_block_asm;
3103 this.count_locals = JSC$stmt_block_count_locals;
3104 }
3105
3106 function JSC$stmt_block_asm ()
3107 {
3108 JSC$ns.push_frame ();
3109
3110 /* Assembler for our stmts. */
3111 var i;
3112 for (i = 0; i < this.stmts.length; i++)
3113 this.stmts[i].asm ();
3114
3115 JSC$ns.pop_frame ();
3116 }
3117
3118
3119 function JSC$stmt_block_count_locals (recursive)
3120 {
3121 if (!recursive)
3122 return 0;
3123
3124 return JSC$count_locals_from_stmt_list (this.stmts);
3125 }
3126
3127 /* Function declaration. */
3128
3129 function JSC$stmt_function_declaration (ln, container_id, function_id,
3130 given_id)
3131 {
3132 this.stype = JSC$STMT_FUNCTION_DECLARATION;
3133 this.linenum = ln;
3134 this.container_id = container_id;
3135 this.function_id = function_id;
3136 this.given_id = given_id;
3137 this.asm = JSC$stmt_function_declaration_asm;
3138 this.count_locals = JSC$zero_function;
3139 }
3140
3141 function JSC$stmt_function_declaration_asm ()
3142 {
3143 new JSC$ASM_load_global (this.linenum, this.function_id).link ();
3144 new JSC$ASM_load_global (this.linenum, this.container_id).link ();
3145 new JSC$ASM_store_property (this.linenum, this.given_id).link ();
3146 }
3147
3148 /* Empty */
3149
3150 function JSC$stmt_empty (ln)
3151 {
3152 this.stype = JSC$STMT_EMPTY;
3153 this.linenum = ln;
3154 this.asm = JSC$stmt_empty_asm;
3155 this.count_locals = JSC$zero_function;
3156 }
3157
3158 function JSC$stmt_empty_asm ()
3159 {
3160 /* Nothing here. */
3161 }
3162
3163
3164 /* Continue. */
3165
3166 function JSC$stmt_continue (ln, label)
3167 {
3168 this.stype = JSC$STMT_CONTINUE;
3169 this.linenum = ln;
3170 this.label = label;
3171 this.asm = JSC$stmt_continue_asm;
3172 this.count_locals = JSC$zero_function;
3173 }
3174
3175 function JSC$stmt_continue_asm ()
3176 {
3177 var l_cont = JSC$cont_break.get_continue (this.label);
3178
3179 if (l_cont == null)
3180 {
3181 if (this.label)
3182 error (JSC$filename + ":" + this.linenum.toString ()
3183 + ": label `" + this.label
3184 + "' not found for continue statement");
3185 else
3186 error (JSC$filename + ":" + this.linenum.toString ()
3187 + ": continue statement not within a loop");
3188 }
3189
3190 var nesting = JSC$cont_break.count_with_nesting (this.label);
3191 if (nesting > 0)
3192 new JSC$ASM_with_pop (this.linenum, nesting).link ();
3193
3194 nesting = JSC$cont_break.count_try_nesting (this.label);
3195 if (nesting > 0)
3196 new JSC$ASM_try_pop (this.linenum, nesting).link ();
3197
3198 nesting = JSC$cont_break.count_switch_nesting (this.label);
3199 if (nesting > 0)
3200 {
3201 /* Pop the value of the switch expression. */
3202 if (nesting == 1)
3203 new JSC$ASM_pop (this.linenum).link ();
3204 else
3205 new JSC$ASM_pop_n (this.linenum, nesting).link ();
3206 }
3207
3208 new JSC$ASM_jmp (this.linenum, l_cont).link ();
3209 }
3210
3211
3212 /* Break. */
3213
3214 function JSC$stmt_break (ln, label)
3215 {
3216 this.stype = JSC$STMT_BREAK;
3217 this.linenum = ln;
3218 this.label = label;
3219 this.asm = JSC$stmt_break_asm;
3220 this.count_locals = JSC$zero_function;
3221 }
3222
3223 function JSC$stmt_break_asm ()
3224 {
3225 var l_break = JSC$cont_break.get_break (this.label);
3226
3227 if (l_break == null)
3228 {
3229 if (this.label)
3230 error (JSC$filename + ":" + this.linenum.toString ()
3231 + ": label `" + this.label
3232 + "' not found for break statement");
3233 else
3234 error (JSC$filename + ":" + this.linenum.toString()
3235 + ": break statement not within a loop or switch");
3236 }
3237
3238 var nesting = JSC$cont_break.count_with_nesting (this.label);
3239 if (nesting > 0)
3240 new JSC$ASM_with_pop (this.linenum, nesting).link ();
3241
3242 nesting = JSC$cont_break.count_try_nesting (this.label);
3243 if (nesting > 0)
3244 new JSC$ASM_try_pop (this.linenum, nesting).link ();
3245
3246 /*
3247 * For non-labeled breaks, the switch nesting is handled in the
3248 * stmt_switch(). The code after the label, returned by the
3249 * get_break(), will handle the switch nesting in these cases.
3250 * For the labeled breaks, we must pop the switch nesting here.
3251 */
3252 if (this.label)
3253 {
3254 nesting = JSC$cont_break.count_switch_nesting (this.label);
3255 if (nesting > 0)
3256 {
3257 if (nesting == 1)
3258 new JSC$ASM_pop (this.linenum).link ();
3259 else
3260 new JSC$ASM_pop_n (this.linenum, nesting).link ();
3261 }
3262 }
3263
3264 new JSC$ASM_jmp (this.linenum, l_break).link ();
3265 }
3266
3267
3268 /* Return. */
3269
3270 function JSC$stmt_return (ln, expr)
3271 {
3272 this.stype = JSC$STMT_RETURN;
3273 this.linenum = ln;
3274 this.expr = expr;
3275 this.asm = JSC$stmt_return_asm;
3276 this.count_locals = JSC$zero_function;
3277 }
3278
3279 function JSC$stmt_return_asm ()
3280 {
3281 var nesting = JSC$cont_break.try_return_nesting ();
3282 if (nesting > 0)
3283 new JSC$ASM_try_pop (this.linenum, nesting).link ();
3284
3285 if (this.expr != null)
3286 this.expr.asm ();
3287 else
3288 new JSC$ASM_const_undefined (this.linenum).link ();
3289
3290 new JSC$ASM_return (this.linenum).link ();
3291 }
3292
3293
3294 /* Switch. */
3295
3296 function JSC$stmt_switch (ln, last_ln, expr, clauses)
3297 {
3298 this.stype = JSC$STMT_SWITCH;
3299 this.linenum = ln;
3300 this.last_linenum = last_ln;
3301 this.expr = expr;
3302 this.clauses = clauses;
3303 this.asm = JSC$stmt_switch_asm;
3304 this.count_locals = JSC$stmt_switch_count_locals;
3305 }
3306
3307 function JSC$stmt_switch_asm ()
3308 {
3309 /* Evaluate the switch expression to the top of the stack. */
3310 this.expr.asm ();
3311
3312 /* The switch statement define a break label. */
3313 var l_break = new JSC$ASM_label ();
3314 JSC$cont_break.push (l_break, null, true, null);
3315
3316 /* For each clause (except the first), insert check and body labels. */
3317 var i;
3318 for (i = 1; i < this.clauses.length; i++)
3319 {
3320 this.clauses[i].l_check = new JSC$ASM_label ();
3321 this.clauses[i].l_body = new JSC$ASM_label ();
3322 }
3323
3324 /* Generate code for each clause. */
3325 for (i = 0; i < this.clauses.length; i++)
3326 {
3327 /* Is this the last clause? */
3328 var last = i + 1 >= this.clauses.length;
3329 var c = this.clauses[i];
3330
3331 var next_check, next_body;
3332 if (last)
3333 next_check = next_body = l_break;
3334 else
3335 {
3336 next_check = this.clauses[i + 1].l_check;
3337 next_body = this.clauses[i + 1].l_body;
3338 }
3339
3340 if (c.expr)
3341 {
3342 /*
3343 * Must check if this clause matches the expression. If c.expr
3344 * is null, this is the default clause that matches always.
3345 */
3346
3347 if (i > 0)
3348 c.l_check.link ();
3349
3350 new JSC$ASM_dup (c.linenum).link ();
3351 c.expr.asm ();
3352 new JSC$ASM_cmp_eq (c.linenum).link ();
3353 new JSC$ASM_iffalse_b (c.linenum, next_check).link ();
3354 }
3355 else
3356 {
3357 if (i > 0)
3358 /* The check label for the default case. */
3359 c.l_check.link ();
3360 }
3361
3362 /* Generate assembler for the body. */
3363 if (i > 0)
3364 c.l_body.link ();
3365
3366 var j;
3367 for (j = 0; j < c.length; j++)
3368 c[j].asm ();
3369
3370 /* And finally, jump to the next body. (this is the fallthrough case). */
3371 new JSC$ASM_jmp (c.last_linenum, next_body).link ();
3372 }
3373
3374 JSC$cont_break.pop ();
3375
3376 /* The break label. */
3377 l_break.link ();
3378
3379 /* Pop the value of the switch expression. */
3380 new JSC$ASM_pop (this.last_linenum).link ();
3381 }
3382
3383 function JSC$stmt_switch_count_locals (recursive)
3384 {
3385 var locals = 0;
3386 var i, j;
3387
3388 if (recursive)
3389 {
3390 /* For the recursive cases, we need the maximum of our clause stmts. */
3391 for (i = 0; i < this.clauses.length; i++)
3392 {
3393 var c = this.clauses[i];
3394 for (j = 0; j < c.length; j++)
3395 {
3396 var l = c[j].count_locals (true);
3397 if (l > locals)
3398 locals = l;
3399 }
3400 }
3401 }
3402 else
3403 {
3404 /*
3405 * The case clauses are not blocks. Therefore, we need the amount,
3406 * needed by the clauses at the top-level.
3407 */
3408
3409 for (i = 0; i < this.clauses.length; i++)
3410 {
3411 var c = this.clauses[i];
3412 for (j = 0; j < c.length; j++)
3413 locals += c[j].count_locals (false);
3414 }
3415 }
3416
3417 return locals;
3418 }
3419
3420
3421 /* With. */
3422
3423 function JSC$stmt_with (ln, expr, stmt)
3424 {
3425 this.stype = JSC$STMT_WITH;
3426 this.linenum = ln;
3427 this.expr = expr;
3428 this.stmt = stmt;
3429 this.asm = JSC$stmt_with_asm;
3430 this.count_locals = JSC$stmt_with_count_locals;
3431 }
3432
3433 function JSC$stmt_with_asm ()
3434 {
3435 this.expr.asm ();
3436
3437 new JSC$ASM_with_push (this.linenum).link ();
3438 JSC$cont_break.top.with_nesting++;
3439
3440 this.stmt.asm ();
3441
3442 JSC$cont_break.top.with_nesting--;
3443 new JSC$ASM_with_pop (this.linenum, 1).link ();
3444 }
3445
3446 function JSC$stmt_with_count_locals (recursive)
3447 {
3448 if (!recursive)
3449 {
3450 if (this.stmt.stype == JSC$STMT_VARIABLE)
3451 return this.stmt.list.length;
3452
3453 return 0;
3454 }
3455 else
3456 return this.stmt.count_locals (true);
3457 }
3458
3459
3460 /* Try. */
3461
3462 function JSC$stmt_try (ln, try_block_last_ln, try_last_ln, block, catch_list,
3463 fin)
3464 {
3465 this.stype = JSC$STMT_TRY;
3466 this.linenum = ln;
3467 this.try_block_last_linenum = try_block_last_ln;
3468 this.try_last_linenum = try_last_ln;
3469 this.block = block;
3470 this.catch_list = catch_list;
3471 this.fin = fin;
3472 this.asm = JSC$stmt_try_asm;
3473 this.count_locals = JSC$stmt_try_count_locals;
3474 }
3475
3476 function JSC$stmt_try_asm ()
3477 {
3478 var l_finally = new JSC$ASM_label ();
3479
3480 /* Protect and execute the try-block. */
3481
3482 var l_try_error = new JSC$ASM_label ();
3483 new JSC$ASM_try_push (this.linenum, l_try_error).link ();
3484 JSC$cont_break.top.try_nesting++;
3485
3486 this.block.asm ();
3487
3488 JSC$cont_break.top.try_nesting--;
3489 new JSC$ASM_try_pop (this.try_block_last_linenum, 1).link ();
3490
3491 /*
3492 * All ok so far. Push a `false' to indicate no error and jump to
3493 * the finally block (or out if we have no finally block).
3494 */
3495 new JSC$ASM_const_false (this.try_block_last_linenum).link ();
3496 new JSC$ASM_jmp (this.try_block_last_linenum, l_finally).link ();
3497
3498 /*
3499 * Handle try block failures. The thrown value is on the top of the
3500 * stack.
3501 */
3502
3503 l_try_error.link ();
3504
3505 if (this.catch_list)
3506 {
3507 /*
3508 * We keep one boolean variable below the thrown value. Its default
3509 * value is false. When one of our catch blocks are entered, it is
3510 * set to true to indicate that we shouldn't throw the error
3511 * anymore.
3512 */
3513 new JSC$ASM_const_false (this.catch_list.linenum).link ();
3514 new JSC$ASM_swap (this.catch_list.linenum).link ();
3515
3516 /* Protect and execute the catch list. */
3517
3518 var l_catch_list_error = new JSC$ASM_label ();
3519 new JSC$ASM_try_push (this.catch_list.linenum,
3520 l_catch_list_error).link ();
3521 JSC$cont_break.top.try_nesting++;
3522
3523 /* Insert start and body labels for each catch list item. */
3524 var i;
3525 for (i = 0; i < this.catch_list.length; i++)
3526 {
3527 this.catch_list[i].l_start = new JSC$ASM_label ();
3528 this.catch_list[i].l_body = new JSC$ASM_label ();
3529 }
3530
3531 /* A label for the catch list end. */
3532 var l_catch_list_end = new JSC$ASM_label ();
3533
3534 /* Process the individual catches. */
3535 for (i = 0; i < this.catch_list.length; i++)
3536 {
3537 var c = this.catch_list[i];
3538
3539 /* This is the starting point of this catch frame. */
3540 c.l_start.link ();
3541
3542 /*
3543 * Create a new namespace frame and bind the catch's
3544 * identifier to the thrown exception.
3545 */
3546
3547 JSC$ns.push_frame ();
3548 JSC$ns.define_symbol (c.id, JSC$SCOPE_LOCAL, JSC$ns.alloc_local (),
3549 c.linenum);
3550
3551 new JSC$ASM_dup (c.linenum).link ();
3552 new JSC$ASM_store_local (c.linenum,
3553 JSC$ns.lookup_symbol (c.id).value).link ();
3554
3555 /* Check the possible guard. We must protect its calculation. */
3556 if (c.guard)
3557 {
3558 var l_guard_error = new JSC$ASM_label ();
3559 new JSC$ASM_try_push (c.linenum, l_guard_error).link ();
3560 JSC$cont_break.top.try_nesting++;
3561
3562 /* Calculate the guard. */
3563 c.guard.asm ();
3564
3565 JSC$cont_break.top.try_nesting--;
3566 new JSC$ASM_try_pop (c.linenum, 1).link ();
3567
3568 /*
3569 * Wow! We managed to do it. Now, let's check if we
3570 * accept this catch case.
3571 */
3572
3573 var next;
3574 if (i + 1 >= this.catch_list.length)
3575 next = l_catch_list_end;
3576 else
3577 next = this.catch_list[i + 1].l_start;
3578
3579 if (c.guard.lang_type == JSC$JS_BOOLEAN)
3580 new JSC$ASM_iffalse_b (c.linenum, next).link ();
3581 else
3582 new JSC$ASM_iffalse (c.linenum, next).link ();
3583
3584 /* Yes, we do accept it. Just jump to do the stuffs. */
3585 new JSC$ASM_jmp (c.linenum, c.l_body).link ();
3586
3587 /*
3588 * The evaluation of the guard failed. Do the cleanup
3589 * and jump to the next case.
3590 */
3591
3592 l_guard_error.link ();
3593
3594 /* Pop the exception. */
3595 new JSC$ASM_pop (c.linenum).link ();
3596
3597 /* Check the next case. */
3598 new JSC$ASM_jmp (c.linenum, next).link ();
3599 }
3600
3601 /*
3602 * We did enter the catch body. Let's update our boolean
3603 * status variable to reflect this fact.
3604 */
3605 c.l_body.link ();
3606
3607 new JSC$ASM_swap (c.linenum).link ();
3608 new JSC$ASM_pop (c.linenum).link ();
3609 new JSC$ASM_const_true (c.linenum).link ();
3610 new JSC$ASM_swap (c.linenum).link ();
3611
3612 /* Code for the catch body. */
3613 c.stmt.asm ();
3614
3615 /* We'r done with the namespace frame. */
3616 JSC$ns.pop_frame ();
3617
3618 /*
3619 * The next catch tag, or the l_catch_list_end follows us,
3620 * so we don't need a jumps here.
3621 */
3622 }
3623
3624 /*
3625 * The catch list was evaluated without errors.
3626 */
3627
3628 l_catch_list_end.link ();
3629 JSC$cont_break.top.try_nesting--;
3630 new JSC$ASM_try_pop (this.catch_list.last_linenum, 1).link ();
3631
3632 /* Did we enter any of our catch lists? */
3633
3634 var l_we_did_enter = new JSC$ASM_label ();
3635 new JSC$ASM_swap (this.catch_list.last_linenum).link ();
3636 new JSC$ASM_iftrue_b (this.catch_list.last_linenum,
3637 l_we_did_enter).link ();
3638
3639 /* No we didn't. */
3640
3641 /*
3642 * Push `true' to indicate an exception and jump to the finally
3643 * block. The exception is now on the top of the stack.
3644 */
3645 new JSC$ASM_const_true (this.catch_list.last_linenum).link ();
3646 new JSC$ASM_jmp (this.catch_list.last_linenum, l_finally).link ();
3647
3648 /* Yes, we did enter one (or many) of our catch lists. */
3649
3650 l_we_did_enter.link ();
3651
3652 /* Pop the try-block's exception */
3653 new JSC$ASM_pop (this.catch_list.last_linenum).link ();
3654
3655 /*
3656 * Push a `false' to indicate "no errors" and jump to the
3657 * finally block.
3658 */
3659 new JSC$ASM_const_false (this.catch_list.last_linenum).link ();
3660 new JSC$ASM_jmp (this.catch_list.last_linenum, l_finally).link ();
3661
3662
3663 /*
3664 * Handle catch list failures. The thrown value is on the top of the
3665 * stack.
3666 */
3667
3668 l_catch_list_error.link ();
3669
3670 /*
3671 * Pop the try-block's exception and our boolean `did we enter a
3672 * catch block' variable. They are below our new exception.
3673 */
3674 new JSC$ASM_apop (this.catch_list.last_linenum, 2).link ();
3675
3676 /*
3677 * Push `true' to indicate an exception. We will fallthrough to
3678 * the finally part, so no jump is needed here.
3679 */
3680 new JSC$ASM_const_true (this.catch_list.last_linenum).link ();
3681 }
3682 else
3683 {
3684 /* No catch list. */
3685 new JSC$ASM_const_true (this.try_block_last_linenum).link ();
3686 }
3687
3688 /* The possible finally block. */
3689
3690 l_finally.link ();
3691
3692 if (this.fin)
3693 /* Execute it without protection. */
3694 this.fin.asm ();
3695
3696 /* We'r almost there. Let's see if we have to raise a new exception. */
3697
3698 var l_out = new JSC$ASM_label ();
3699 new JSC$ASM_iffalse_b (this.try_last_linenum, l_out).link ();
3700
3701 /* Do raise it. */
3702 new JSC$ASM_throw (this.try_last_linenum).link ();
3703
3704 /* The possible exception is handled. Please, continue. */
3705 l_out.link ();
3706 }
3707
3708 function JSC$stmt_try_count_locals (recursive)
3709 {
3710 var count = 0;
3711 var c;
3712
3713 if (recursive)
3714 {
3715 c = this.block.count_locals (true);
3716 if (c > count)
3717 count = c;
3718
3719 if (this.catch_list)
3720 {
3721 var i;
3722 for (i = 0; i < this.catch_list.length; i++)
3723 {
3724 c = this.catch_list[i].stmt.count_locals (true);
3725 if (c > count)
3726 count = c;
3727 }
3728 }
3729 if (this.fin)
3730 {
3731 c = this.fin.count_locals (true);
3732 if (c > count)
3733 count = c;
3734 }
3735 }
3736 else
3737 {
3738 if (this.block.stype == JSC$STMT_VARIABLE)
3739 count += this.block.list.length;
3740
3741 if (this.catch_list)
3742 {
3743 /* One for the call variable. */
3744 count++;
3745
3746 var i;
3747 for (i = 0; i < this.catch_list.length; i++)
3748 if (this.catch_list[i].stmt.stype == JSC$STMT_VARIABLE)
3749 count += this.catch_list[i].stmt.list.length;
3750 }
3751
3752 if (this.fin)
3753 if (this.fin.stype == JSC$STMT_VARIABLE)
3754 count += this.fin.list.length;
3755 }
3756
3757 return count;
3758 }
3759
3760
3761 /* Throw. */
3762
3763 function JSC$stmt_throw (ln, expr)
3764 {
3765 this.stype = JSC$STMT_THROW;
3766 this.linenum = ln;
3767 this.expr = expr;
3768 this.asm = JSC$stmt_throw_asm;
3769 this.count_locals = JSC$zero_function;
3770 }
3771
3772 function JSC$stmt_throw_asm ()
3773 {
3774 this.expr.asm ();
3775 new JSC$ASM_throw (this.linenum).link ();
3776 }
3777
3778
3779 /* Labeled statement. */
3780 function JSC$stmt_labeled_stmt (ln, id, stmt)
3781 {
3782 this.stype = JSC$STMT_LABELED_STMT;
3783 this.linenum = ln;
3784 this.id = id;
3785 this.stmt = stmt;
3786 this.asm = JSC$stmt_labeled_stmt_asm;
3787 this.count_locals = JSC$stmt_labeled_stmt_count_locals;
3788 }
3789
3790 function JSC$stmt_labeled_stmt_asm ()
3791 {
3792 var l_continue = new JSC$ASM_label ();
3793 var l_break = new JSC$ASM_label ();
3794
3795 /*
3796 * It is an error if we already have a labeled statement with the
3797 * same id.
3798 */
3799 if (!JSC$cont_break.is_unique_label (this.id))
3800 error (JSC$filename + ":" + this.linenum.toString ()
3801 + ": labeled statement is enclosed by another labeled statement "
3802 + "with the same label");
3803
3804 /* Push the break and continue labels. */
3805 JSC$cont_break.push (l_break, l_continue, false, this.id);
3806
3807 /* Dump the assembler. */
3808 l_continue.link ();
3809 this.stmt.asm ();
3810 l_break.link ();
3811
3812 /* And we'r done with out label scope. */
3813 JSC$cont_break.pop ();
3814 }
3815
3816 function JSC$stmt_labeled_stmt_count_locals (recursive)
3817 {
3818 return this.stmt.count_locals (recursive);
3819 }
3820
3821
3822 /* Expression. */
3823
3824 function JSC$stmt_expr (expr)
3825 {
3826 this.stype = JSC$STMT_EXPR;
3827 this.linenum = expr.linenum;
3828 this.expr = expr;
3829 this.asm = JSC$stmt_expr_asm;
3830 this.count_locals = JSC$zero_function;
3831 }
3832
3833 function JSC$stmt_expr_asm ()
3834 {
3835 this.expr.asm ();
3836 new JSC$ASM_pop (this.linenum).link ();
3837 }
3838
3839
3840 /* If. */
3841
3842 function JSC$stmt_if (ln, expr, stmt1, stmt2)
3843 {
3844 this.stype = JSC$STMT_IF;
3845 this.linenum = ln;
3846 this.expr = expr;
3847 this.stmt1 = stmt1;
3848 this.stmt2 = stmt2;
3849 this.asm = JSC$stmt_if_asm;
3850 this.count_locals = JSC$stmt_if_count_locals;
3851 }
3852
3853 function JSC$stmt_if_asm ()
3854 {
3855 this.expr.asm ();
3856
3857 var l1 = new JSC$ASM_label ();
3858 var l2 = new JSC$ASM_label ();
3859
3860 if (JSC$optimize_type && this.expr.lang_type
3861 && this.expr.lang_type == JSC$JS_BOOLEAN)
3862 new JSC$ASM_iffalse_b (this.linenum, l1).link ();
3863 else
3864 new JSC$ASM_iffalse (this.linenum, l1).link ();
3865
3866 /* Code for the then branch. */
3867 this.stmt1.asm ();
3868 new JSC$ASM_jmp (this.linenum, l2).link ();
3869
3870 /* Code for the else branch. */
3871 l1.link ();
3872 if (this.stmt2 != null)
3873 this.stmt2.asm ();
3874
3875 /* Done label. */
3876 l2.link ();
3877 }
3878
3879
3880 function JSC$stmt_if_count_locals (recursive)
3881 {
3882 var lcount;
3883
3884 if (!recursive)
3885 {
3886 lcount = 0;
3887 if (this.stmt1.stype == JSC$STMT_VARIABLE)
3888 lcount += this.stmt1.list.length;
3889
3890 if (this.stmt2 != null && this.stmt2.stype == JSC$STMT_VARIABLE)
3891 lcount += this.stmt2.list.length;
3892 }
3893 else
3894 {
3895 lcount = this.stmt1.count_locals (true);
3896
3897 if (this.stmt2)
3898 {
3899 var c = this.stmt2.count_locals (true);
3900 if (c > lcount)
3901 lcount = c;
3902 }
3903 }
3904
3905 return lcount;
3906 }
3907
3908
3909 /* Do...While. */
3910
3911 function JSC$stmt_do_while (ln, expr, stmt)
3912 {
3913 this.stype = JSC$STMT_DO_WHILE;
3914 this.linenum = ln;
3915 this.expr = expr;
3916 this.stmt = stmt;
3917 this.asm = JSC$stmt_do_while_asm;
3918 this.count_locals = JSC$stmt_do_while_count_locals;
3919 }
3920
3921 function JSC$stmt_do_while_asm ()
3922 {
3923 var l1 = new JSC$ASM_label ();
3924 var l2 = new JSC$ASM_label ();
3925 var l3 = new JSC$ASM_label ();
3926
3927 /* Loop label. */
3928 l1.link ();
3929
3930 /* Body. */
3931 JSC$cont_break.push (l3, l2, false, null);
3932 this.stmt.asm ();
3933 JSC$cont_break.pop ();
3934
3935 /* Condition & continue. */
3936 l2.link ();
3937 this.expr.asm ();
3938 if (JSC$optimize_type && this.expr.lang_type
3939 && this.expr.lang_type == JSC$JS_BOOLEAN)
3940 new JSC$ASM_iftrue_b (this.linenum, l1).link ();
3941 else
3942 new JSC$ASM_iftrue (this.linenum, l1).link ();
3943
3944 /* Break label. */
3945 l3.link ();
3946 }
3947
3948 function JSC$stmt_do_while_count_locals (recursive)
3949 {
3950 if (!recursive)
3951 {
3952 if (this.stmt.stype == JSC$STMT_VARIABLE)
3953 return this.stmt.list.length;
3954
3955 return 0;
3956 }
3957 else
3958 return this.stmt.count_locals (true);
3959 }
3960
3961 /* While. */
3962
3963 function JSC$stmt_while (ln, expr, stmt)
3964 {
3965 this.stype = JSC$STMT_WHILE;
3966 this.linenum = ln;
3967 this.expr = expr;
3968 this.stmt = stmt;
3969 this.asm = JSC$stmt_while_asm;
3970 this.count_locals = JSC$stmt_while_count_locals;
3971 }
3972
3973 function JSC$stmt_while_asm ()
3974 {
3975 var l1 = new JSC$ASM_label ();
3976 var l2 = new JSC$ASM_label ();
3977
3978 /* Loop label. */
3979 l1.link ();
3980
3981 /* Condition. */
3982 this.expr.asm ();
3983 if (JSC$optimize_type && this.expr.lang_type
3984 && this.expr.lang_type == JSC$JS_BOOLEAN)
3985 new JSC$ASM_iffalse_b (this.linenum, l2).link ();
3986 else
3987 new JSC$ASM_iffalse (this.linenum, l2).link ();
3988
3989 /* Body. */
3990 JSC$cont_break.push (l2, l1, false, null);
3991 this.stmt.asm ();
3992 JSC$cont_break.pop ();
3993
3994 /* Goto loop. */
3995 new JSC$ASM_jmp (this.linenum, l1).link ();
3996
3997 /* Break label. */
3998 l2.link ();
3999 }
4000
4001
4002 function JSC$stmt_while_count_locals (recursive)
4003 {
4004 if (!recursive)
4005 {
4006 if (this.stmt.stype == JSC$STMT_VARIABLE)
4007 return this.stmt.list.length;
4008
4009 return 0;
4010 }
4011 else
4012 return this.stmt.count_locals (true);
4013 }
4014
4015
4016 /* For. */
4017
4018 function JSC$stmt_for (ln, vars, e1, e2, e3, stmt)
4019 {
4020 this.stype = JSC$STMT_FOR;
4021 this.linenum = ln;
4022 this.vars = vars;
4023 this.expr1 = e1;
4024 this.expr2 = e2;
4025 this.expr3 = e3;
4026 this.stmt = stmt;
4027 this.asm = JSC$stmt_for_asm;
4028 this.count_locals = JSC$stmt_for_count_locals;
4029 }
4030
4031 function JSC$stmt_for_asm ()
4032 {
4033 /* Code for the init. */
4034 if (this.vars)
4035 {
4036 /* We have our own variable scope. */
4037 JSC$ns.push_frame ();
4038
4039 var i;
4040 for (i = 0; i < this.vars.length; i++)
4041 {
4042 var decl = this.vars[i];
4043
4044 JSC$ns.define_symbol (decl.id, JSC$SCOPE_LOCAL,
4045 JSC$ns.alloc_local (), this.linenum);
4046
4047 /* Possible init. */
4048 if (decl.expr)
4049 {
4050 decl.expr.asm ();
4051
4052 var r = JSC$ns.lookup_symbol (decl.id);
4053 if (r == null || r.scope != JSC$SCOPE_LOCAL)
4054 error (JSC$filename + ":" + this.liennum.toString ()
4055 + ": internal compiler error in local variable "
4056 + "declaration in for statement");
4057
4058 new JSC$ASM_store_local (this.linenum, r.value).link ();
4059 }
4060 }
4061 }
4062 else if (this.expr1 != null)
4063 {
4064 this.expr1.asm ();
4065 new JSC$ASM_pop (this.linenum).link ();
4066 }
4067
4068 var l1 = new JSC$ASM_label ();
4069 var l2 = new JSC$ASM_label ();
4070 var l3 = new JSC$ASM_label ();
4071
4072 /* Loop label. */
4073 l1.link ();
4074
4075 /* Condition. */
4076 var type_op = false;
4077 if (this.expr2 != null)
4078 {
4079 this.expr2.asm ();
4080 if (JSC$optimize_type && this.expr2.lang_type
4081 && this.expr2.lang_type == JSC$JS_BOOLEAN)
4082 type_op = true;
4083 }
4084 else
4085 {
4086 new JSC$ASM_const_true (this.linenum).link ();
4087 type_op = JSC$optimize_type;
4088 }
4089 if (type_op)
4090 new JSC$ASM_iffalse_b (this.linenum, l3).link ();
4091 else
4092 new JSC$ASM_iffalse (this.linenum, l3).link ();
4093
4094 JSC$cont_break.push (l3, l2, false, null);
4095 /* Body. */
4096 this.stmt.asm ();
4097 JSC$cont_break.pop ();
4098
4099 /* Continue label. */
4100 l2.link ();
4101
4102 /* Increment. */
4103 if (this.expr3 != null)
4104 {
4105 this.expr3.asm ();
4106 new JSC$ASM_pop (this.linenum).link ();
4107 }
4108
4109 /* Goto loop. */
4110 new JSC$ASM_jmp (this.linenum, l1).link ();
4111
4112 /* Break label. */
4113 l3.link ();
4114
4115 if (this.vars)
4116 /* Pop the local variable scope. */
4117 JSC$ns.pop_frame ();
4118 }
4119
4120
4121 function JSC$stmt_for_count_locals (recursive)
4122 {
4123 var count = 0;
4124
4125 if (recursive)
4126 {
4127 if (this.vars)
4128 count += this.vars.length;
4129
4130 count += this.stmt.count_locals (true);
4131 }
4132 else
4133 {
4134 if (this.stmt.stype == JSC$STMT_VARIABLE)
4135 count += this.stmt.list.length;
4136 }
4137
4138 return count;
4139 }
4140
4141
4142 /* For...in. */
4143
4144 function JSC$stmt_for_in (ln, vars, e1, e2, stmt)
4145 {
4146 this.stype = JSC$STMT_FOR_IN;
4147 this.linenum = ln;
4148 this.vars = vars;
4149 this.expr1 = e1;
4150 this.expr2 = e2;
4151 this.stmt = stmt;
4152 this.asm = JSC$stmt_for_in_asm;
4153 this.count_locals = JSC$stmt_for_in_count_locals;
4154 }
4155
4156 function JSC$stmt_for_in_asm ()
4157 {
4158 var local_id;
4159
4160 if (this.vars)
4161 {
4162 /* We need our own variable scope here. */
4163 JSC$ns.push_frame ();
4164
4165 var decl = this.vars[0];
4166 local_id = JSC$ns.alloc_local ();
4167 JSC$ns.define_symbol (decl.id, JSC$SCOPE_LOCAL, local_id, this.linenum);
4168
4169 /* Possible init. */
4170 if (decl.expr)
4171 {
4172 decl.expr.asm ();
4173 new JSC$ASM_store_local (this.linenum, local_id).link ();
4174 }
4175 }
4176
4177 /* Init the world. */
4178 this.expr2.asm ();
4179 new JSC$ASM_dup (this.linenum).link ();
4180 new JSC$ASM_const_i0 (this.linenum).link ();
4181 new JSC$ASM_swap (this.linenum).link ();
4182 new JSC$ASM_const_i0 (this.linenum).link ();
4183
4184 var l_loop = new JSC$ASM_label ();
4185 var l_cont = new JSC$ASM_label ();
4186 var l_iffalse_b = new JSC$ASM_label ();
4187 var l_break = new JSC$ASM_label ();
4188
4189 /* Loop label. */
4190 l_loop.link ();
4191
4192 /* Fetch nth. */
4193 new JSC$ASM_nth (this.linenum).link ();
4194 new JSC$ASM_iffalse_b (this.linenum, l_iffalse_b).link ();
4195
4196 /* Store value to variable. */
4197 if (this.vars)
4198 new JSC$ASM_store_local (this.linenum, local_id).link ();
4199 else
4200 JSC$asm_expr_lvalue_store_asm (this.expr1);
4201
4202 /* Body. */
4203 JSC$cont_break.push (l_break, l_cont, false, null);
4204 this.stmt.asm ();
4205 JSC$cont_break.pop ();
4206
4207 /* Continue label. */
4208 l_cont.link ();
4209
4210 /* Increment. */
4211 new JSC$ASM_const_i1 (this.linenum).link ();
4212 new JSC$ASM_add (this.linenum).link ();
4213 new JSC$ASM_dup (this.linenum).link ();
4214 new JSC$ASM_roll (this.linenum, -3).link ();
4215 new JSC$ASM_dup (this.linenum).link ();
4216 new JSC$ASM_roll (this.linenum, 4).link ();
4217 new JSC$ASM_swap (this.linenum).link ();
4218
4219 /* Goto loop. */
4220 new JSC$ASM_jmp (this.linenum, l_loop).link ();
4221
4222 /* Out label. */
4223 l_iffalse_b.link ();
4224
4225 new JSC$ASM_pop (this.linenum).link ();
4226
4227 /* Break label. */
4228 l_break.link ();
4229 new JSC$ASM_pop_n (this.linenum, 2).link ();
4230
4231 if (this.vars)
4232 /* Pop the variable scope. */
4233 JSC$ns.pop_frame ();
4234 }
4235
4236 function JSC$stmt_for_in_count_locals (recursive)
4237 {
4238 var count = 0;
4239
4240 if (recursive)
4241 {
4242 if (this.vars)
4243 count++;
4244
4245 count += this.stmt.count_locals (true);
4246 }
4247 else
4248 {
4249 if (this.stmt.stype == JSC$STMT_VARIABLE)
4250 count += this.stmt.list.length;
4251
4252 }
4253
4254 return count;
4255 }
4256
4257
4258 /* Variable. */
4259
4260 function JSC$stmt_variable (ln, list)
4261 {
4262 this.stype = JSC$STMT_VARIABLE;
4263 this.linenum = ln;
4264 this.global_level = false;
4265 this.list = list;
4266 this.asm = JSC$stmt_variable_asm;
4267 this.count_locals = JSC$stmt_variable_count_locals;
4268 }
4269
4270 function JSC$stmt_variable_asm ()
4271 {
4272 var j, r;
4273
4274 /* Define all local variables to our namespace. */
4275 for (j = 0; j < this.list.length; j++)
4276 {
4277 var i = this.list[j];
4278
4279 if (!this.global_level)
4280 JSC$ns.define_symbol (i.id, JSC$SCOPE_LOCAL,
4281 JSC$ns.alloc_local (), this.linenum);
4282 if (i.expr)
4283 {
4284 i.expr.asm ();
4285
4286 if (this.global_level)
4287 new JSC$ASM_store_global (this.linenum, i.id).link ();
4288 else
4289 {
4290 r = JSC$ns.lookup_symbol (i.id);
4291 if (r == null || r.scope != JSC$SCOPE_LOCAL)
4292 error (JSC$filename + ":" + this.linenum.toString()
4293 + ": internal compiler error in local variable declaration");
4294
4295 new JSC$ASM_store_local (this.linenum, r.value).link ();
4296 }
4297 }
4298 }
4299 }
4300
4301 function JSC$stmt_variable_count_locals (recursive)
4302 {
4303 if (!recursive)
4304 {
4305 if (this.global_level)
4306 /* We define these as global variables. */
4307 return 0;
4308
4309 return this.list.length;
4310 }
4311
4312 return 0;
4313 }
4314
4315 function JSC$var_declaration (id, expr)
4316 {
4317 this.id = id;
4318 this.expr = expr;
4319 }
4320
4321
4322 /*
4323 * Expressions.
4324 */
4325
4326 /* This. */
4327
4328 function JSC$expr_this (ln)
4329 {
4330 this.etype = JSC$EXPR_THIS;
4331 this.linenum = ln;
4332 this.asm = JSC$expr_this_asm;
4333 }
4334
4335 function JSC$expr_this_asm ()
4336 {
4337 new JSC$ASM_load_arg (this.linenum, 0).link ();
4338 }
4339
4340 /* Identifier. */
4341
4342 function JSC$expr_identifier (ln, value)
4343 {
4344 this.etype = JSC$EXPR_IDENTIFIER;
4345 this.linenum = ln;
4346 this.value = value;
4347 this.asm = JSC$expr_identifier_asm;
4348 }
4349
4350 function JSC$expr_identifier_asm ()
4351 {
4352 JSC$asm_expr_lvalue_load_asm (this);
4353 }
4354
4355 /* Float. */
4356
4357 function JSC$expr_float (ln, value)
4358 {
4359 this.etype = JSC$EXPR_FLOAT;
4360 this.lang_type = JSC$JS_FLOAT;
4361 this.linenum = ln;
4362 this.value = value;
4363 this.asm = JSC$expr_float_asm;
4364 }
4365
4366 function JSC$expr_float_asm ()
4367 {
4368 new JSC$ASM_const (this.linenum, this.value).link ();
4369 }
4370
4371 /* Integer. */
4372
4373 function JSC$expr_integer (ln, value)
4374 {
4375 this.etype = JSC$EXPR_INTEGER;
4376 this.lang_type = JSC$JS_INTEGER;
4377 this.linenum = ln;
4378 this.value = value;
4379 this.asm = JSC$expr_integer_asm;
4380 }
4381
4382 function JSC$expr_integer_asm ()
4383 {
4384 if (this.value == 0)
4385 new JSC$ASM_const_i0 (this.linenum).link ();
4386 else if (this.value == 1)
4387 new JSC$ASM_const_i1 (this.linenum).link ();
4388 else if (this.value == 2)
4389 new JSC$ASM_const_i2 (this.linenum).link ();
4390 else if (this.value == 3)
4391 new JSC$ASM_const_i3 (this.linenum).link ();
4392 else
4393 new JSC$ASM_const_i (this.linenum, this.value).link ();
4394 }
4395
4396 /* String. */
4397
4398 function JSC$expr_string (ln, value)
4399 {
4400 this.etype = JSC$EXPR_STRING;
4401 this.lang_type = JSC$JS_STRING;
4402 this.linenum = ln;
4403 this.value = value;
4404 this.asm = JSC$expr_string_asm;
4405 }
4406
4407 function JSC$expr_string_asm ()
4408 {
4409 new JSC$ASM_const (this.linenum, this.value).link ();
4410 }
4411
4412 /* Regexp. */
4413
4414 function JSC$expr_regexp (ln, value)
4415 {
4416 this.etype = JSC$EXPR_REGEXP;
4417 this.lang_type = JSC$JS_BUILTIN;
4418 this.linenum = ln;
4419 this.value = value;
4420 this.asm = JSC$expr_regexp_asm;
4421 }
4422
4423 function JSC$expr_regexp_asm ()
4424 {
4425 new JSC$ASM_const (this.linenum, this.value).link ();
4426 }
4427
4428 /* Array initializer. */
4429
4430 function JSC$expr_array_initializer (ln, items)
4431 {
4432 this.etype = JSC$EXPR_ARRAY_INITIALIZER;
4433 this.lang_type = JSC$JS_ARRAY;
4434 this.linenum = ln;
4435 this.items = items;
4436 this.asm = JSC$expr_array_initializer_asm;
4437 }
4438
4439 function JSC$expr_array_initializer_asm ()
4440 {
4441 /* Generate assembler for the individual items. */
4442
4443 var i;
4444 for (i = this.items.length - 1; i >= 0; i--)
4445 {
4446 if (this.items[i])
4447 this.items[i].asm ();
4448 else
4449 new JSC$ASM_const_undefined (this.linenum).link ();
4450 }
4451
4452 /*
4453 * The number of items as a negative integer. The Array object's
4454 * constructor knows that if the number of arguments is negative, it
4455 * is called from the array initializer. Why? Because the code:
4456 *
4457 * new Array (5);
4458 *
4459 * creates an array of length of 5, but code:
4460 *
4461 * [5]
4462 *
4463 * creates an array with one item: integer number five. These cases
4464 * must be separatable from the code and that's why the argument
4465 * counts for the array initializers are negative.
4466 */
4467 new JSC$ASM_const (this.linenum, -this.items.length).link ();
4468
4469 /* Call the constructor. */
4470 new JSC$ASM_load_global (this.linenum, "Array").link ();
4471 new JSC$ASM_new (this.linenum).link ();
4472 new JSC$ASM_swap (this.linenum).link ();
4473 new JSC$ASM_apop (this.linenum, this.items.length + 2).link ();
4474 }
4475
4476 /* Object initializer. */
4477
4478 function JSC$expr_object_initializer (ln, items)
4479 {
4480 this.etype = JSC$EXPR_OBJECT_INITIALIZER;
4481 this.lang_type = JSC$JS_OBJECT;
4482 this.linenum = ln;
4483 this.items = items;
4484 this.asm = JSC$expr_object_initializer_asm;
4485 }
4486
4487 function JSC$expr_object_initializer_asm ()
4488 {
4489 /* Create a new object. */
4490 new JSC$ASM_const_i0 (this.linenum).link ();
4491 new JSC$ASM_load_global (this.linenum, "Object").link ();
4492 new JSC$ASM_new (this.linenum).link ();
4493 new JSC$ASM_swap (this.linenum).link ();
4494 new JSC$ASM_apop (this.linenum, 2).link ();
4495
4496 /* Insert the items. */
4497 for (var i = 0; i < this.items.length; i++)
4498 {
4499 var item = this.items[i];
4500
4501 new JSC$ASM_dup (item.linenum).link ();
4502 item.expr.asm ();
4503 new JSC$ASM_swap (item.linenum).link ();
4504
4505 switch (item.id_type)
4506 {
4507 case JSC$tIDENTIFIER:
4508 new JSC$ASM_store_property (item.linenum, item.id).link ();
4509 break;
4510
4511 case JSC$tSTRING:
4512 new JSC$ASM_const (item.linenum, item.id).link ();
4513 new JSC$ASM_store_array (item.linenum).link ();
4514 break;
4515
4516 case JSC$tINTEGER:
4517 switch (item.id)
4518 {
4519 case 0:
4520 new JSC$ASM_const_i0 (item.linenum).link ();
4521 break;
4522
4523 case 1:
4524 new JSC$ASM_const_i1 (item.linenum).link ();
4525 break;
4526
4527 case 2:
4528 new JSC$ASM_const_i2 (item.linenum).link ();
4529 break;
4530
4531 case 3:
4532 new JSC$ASM_const_i3 (item.linenum).link ();
4533 break;
4534
4535 default:
4536 new JSC$ASM_const_i (item.linenum, item.id).link ();
4537 break;
4538 }
4539 new JSC$ASM_store_array (item.linenum).link ();
4540 break;
4541 }
4542 }
4543 }
4544
4545
4546 /* Null. */
4547
4548 function JSC$expr_null (ln)
4549 {
4550 this.etype = JSC$EXPR_NULL;
4551 this.lang_type = JSC$JS_NULL;
4552 this.linenum = ln;
4553 this.asm = JSC$expr_null_asm;
4554 }
4555
4556 function JSC$expr_null_asm ()
4557 {
4558 new JSC$ASM_const_null (this.linenum).link ();
4559 }
4560
4561 /* True. */
4562
4563 function JSC$expr_true (ln)
4564 {
4565 this.etype = JSC$EXPR_TRUE;
4566 this.lang_type = JSC$JS_BOOLEAN;
4567 this.linenum = ln;
4568 this.asm = JSC$expr_true_asm;
4569 }
4570
4571 function JSC$expr_true_asm ()
4572 {
4573 new JSC$ASM_const_true (this.linenum).link ();
4574 }
4575
4576 /* False. */
4577
4578 function JSC$expr_false (ln)
4579 {
4580 this.etype = JSC$EXPR_FALSE;
4581 this.lang_type = JSC$JS_BOOLEAN;
4582 this.linenum = ln;
4583 this.asm = JSC$expr_false_asm;
4584 }
4585
4586 function JSC$expr_false_asm ()
4587 {
4588 new JSC$ASM_const_false (this.linenum).link ();
4589 }
4590
4591
4592 /* Multiplicative expr. */
4593
4594 function JSC$expr_multiplicative (ln, type, e1, e2)
4595 {
4596 this.etype = JSC$EXPR_MULTIPLICATIVE;
4597 this.linenum = ln;
4598 this.type = type;
4599 this.e1 = e1;
4600 this.e2 = e2;
4601 this.asm = JSC$expr_multiplicative_asm;
4602 }
4603
4604 function JSC$expr_multiplicative_asm ()
4605 {
4606 this.e1.asm ();
4607 this.e2.asm ();
4608 if (this.type == #'*')
4609 new JSC$ASM_mul (this.linenum).link ();
4610 else if (this.type == #'/')
4611 new JSC$ASM_div (this.linenum).link ();
4612 else
4613 new JSC$ASM_mod (this.linenum).link ();
4614 }
4615
4616
4617 /* Additive expr. */
4618
4619 function JSC$expr_additive (ln, type, e1, e2)
4620 {
4621 this.etype = JSC$EXPR_ADDITIVE;
4622 this.linenum = ln;
4623 this.type = type;
4624 this.e1 = e1;
4625 this.e2 = e2;
4626 this.asm = JSC$expr_additive_asm;
4627 this.constant_folding = JSC$expr_additive_constant_folding;
4628 }
4629
4630 function JSC$expr_additive_asm ()
4631 {
4632 this.e1.asm ();
4633 this.e2.asm ();
4634 if (this.type == #'+')
4635 new JSC$ASM_add (this.linenum).link ();
4636 else
4637 new JSC$ASM_sub (this.linenum).link ();
4638 }
4639
4640 function JSC$expr_additive_constant_folding ()
4641 {
4642 if (this.e1.constant_folding)
4643 this.e1 = this.e1.constant_folding ();
4644 if (this.e2.constant_folding)
4645 this.e2 = this.e2.constant_folding ();
4646
4647 /* This could be smarter. */
4648 if (this.e1.lang_type && this.e2.lang_type
4649 && this.e1.lang_type == this.e2.lang_type)
4650 {
4651 switch (this.e1.lang_type)
4652 {
4653 case JSC$JS_INTEGER:
4654 return new JSC$expr_integer (this.linenum,
4655 this.type == #'+'
4656 ? this.e1.value + this.e2.value
4657 : this.e1.value - this.e2.value);
4658 break;
4659
4660 case JSC$JS_FLOAT:
4661 return new JSC$expr_float (this.linenum,
4662 this.type == #'+'
4663 ? this.e1.value + this.e2.value
4664 : this.e1.value - this.e2.value);
4665 break;
4666
4667 case JSC$JS_STRING:
4668 if (this.type == #'+')
4669 /* Only the addition is available for the strings. */
4670 return new JSC$expr_string (this.linenum,
4671 this.e1.value + this.e2.value);
4672 break;
4673
4674 default:
4675 /* FALLTHROUGH */
4676 break;
4677 }
4678 }
4679
4680 return this;
4681 }
4682
4683 /* Shift expr. */
4684
4685 function JSC$expr_shift (ln, type, e1, e2)
4686 {
4687 this.etype = JSC$EXPR_SHIFT;
4688 this.linenum = ln;
4689 this.type = type;
4690 this.e1 = e1;
4691 this.e2 = e2;
4692 this.asm = JSC$expr_shift_asm;
4693 }
4694
4695 function JSC$expr_shift_asm ()
4696 {
4697 this.e1.asm ();
4698 this.e2.asm ();
4699
4700 if (this.type == JSC$tLSHIFT)
4701 new JSC$ASM_shift_left (this.linenum).link ();
4702 else if (this.type == JSC$tRSHIFT)
4703 new JSC$ASM_shift_right (this.linenum).link ();
4704 else
4705 new JSC$ASM_shift_rright (this.linenum).link ();
4706 }
4707
4708
4709 /* Relational expr. */
4710
4711 function JSC$expr_relational (ln, type, e1, e2)
4712 {
4713 this.etype = JSC$EXPR_RELATIONAL;
4714 this.lang_type = JSC$JS_BOOLEAN;
4715 this.linenum = ln;
4716 this.type = type;
4717 this.e1 = e1;
4718 this.e2 = e2;
4719 this.asm = JSC$expr_relational_asm;
4720 }
4721
4722 function JSC$expr_relational_asm ()
4723 {
4724 this.e1.asm ();
4725 this.e2.asm ();
4726
4727 if (this.type == #'<')
4728 new JSC$ASM_cmp_lt (this.linenum).link ();
4729 else if (this.type == #'>')
4730 new JSC$ASM_cmp_gt (this.linenum).link ();
4731 else if (this.type == JSC$tLE)
4732 new JSC$ASM_cmp_le (this.linenum).link ();
4733 else
4734 new JSC$ASM_cmp_ge (this.linenum).link ();
4735 }
4736
4737
4738 /* Equality expr. */
4739
4740 function JSC$expr_equality (ln, type, e1, e2)
4741 {
4742 this.etype = JSC$EXPR_EQUALITY;
4743 this.lang_type = JSC$JS_BOOLEAN;
4744 this.linenum = ln;
4745 this.type = type;
4746 this.e1 = e1;
4747 this.e2 = e2;
4748 this.asm = JSC$expr_equality_asm;
4749 }
4750
4751 function JSC$expr_equality_asm ()
4752 {
4753 this.e1.asm ();
4754 this.e2.asm ();
4755
4756 switch (this.type)
4757 {
4758 case JSC$tEQUAL:
4759 new JSC$ASM_cmp_eq (this.linenum).link ();
4760 break;
4761
4762 case JSC$tNEQUAL:
4763 new JSC$ASM_cmp_ne (this.linenum).link ();
4764 break;
4765
4766 case JSC$tSEQUAL:
4767 new JSC$ASM_cmp_seq (this.linenum).link ();
4768 break;
4769
4770 case JSC$tSNEQUAL:
4771 new JSC$ASM_cmp_sne (this.linenum).link ();
4772 break;
4773
4774 default:
4775 error ("jsc: expr_equality: internal compiler error");
4776 break;
4777 }
4778 }
4779
4780
4781 /* Bitwise and expr. */
4782
4783 function JSC$expr_bitwise_and (ln, e1, e2)
4784 {
4785 this.etype = JSC$EXPR_BITWISE;
4786 this.linenum = ln;
4787 this.e1 = e1;
4788 this.e2 = e2;
4789 this.asm = JSC$expr_bitwise_and_asm;
4790 }
4791
4792 function JSC$expr_bitwise_and_asm ()
4793 {
4794 this.e1.asm ();
4795 this.e2.asm ();
4796
4797 new JSC$ASM_and (this.linenum).link ();
4798 }
4799
4800
4801 /* Bitwise or expr. */
4802
4803 function JSC$expr_bitwise_or (ln, e1, e2)
4804 {
4805 this.etype = JSC$EXPR_BITWISE;
4806 this.linenum = ln;
4807 this.e1 = e1;
4808 this.e2 = e2;
4809 this.asm = JSC$expr_bitwise_or_asm;
4810 }
4811
4812 function JSC$expr_bitwise_or_asm ()
4813 {
4814 this.e1.asm ();
4815 this.e2.asm ();
4816
4817 new JSC$ASM_or (this.linenum).link ();
4818 }
4819
4820
4821 /* Bitwise xor expr. */
4822
4823 function JSC$expr_bitwise_xor (ln, e1, e2)
4824 {
4825 this.etype = JSC$EXPR_BITWISE;
4826 this.linenum = ln;
4827 this.e1 = e1;
4828 this.e2 = e2;
4829 this.asm = JSC$expr_bitwise_xor_asm;
4830 }
4831
4832 function JSC$expr_bitwise_xor_asm ()
4833 {
4834 this.e1.asm ();
4835 this.e2.asm ();
4836
4837 new JSC$ASM_xor (this.linenum).link ();
4838 }
4839
4840
4841 /* Logical and expr. */
4842
4843 function JSC$expr_logical_and (ln, e1, e2)
4844 {
4845 this.etype = JSC$EXPR_LOGICAL;
4846
4847 if (e1.lang_type && e2.lang_type
4848 && e1.lang_type == JSC$JS_BOOLEAN && e2.lang_type == JSC$JS_BOOLEAN)
4849 this.lang_type = JSC$JS_BOOLEAN;
4850
4851 this.linenum = ln;
4852 this.e1 = e1;
4853 this.e2 = e2;
4854 this.asm = JSC$expr_logical_and_asm;
4855 }
4856
4857 function JSC$expr_logical_and_asm ()
4858 {
4859 this.e1.asm ();
4860
4861 var l = new JSC$ASM_label ();
4862 new JSC$ASM_dup (this.linenum).link ();
4863
4864 if (JSC$optimize_type && this.e1.lang_type
4865 && this.e1.lang_type == JSC$JS_BOOLEAN)
4866 new JSC$ASM_iffalse_b (this.linenum, l).link ();
4867 else
4868 new JSC$ASM_iffalse (this.linenum, l).link ();
4869
4870 new JSC$ASM_pop (this.linenum).link ();
4871
4872 this.e2.asm ();
4873
4874 /* Done label. */
4875 l.link ();
4876 }
4877
4878
4879 /* Logical or expr. */
4880
4881 function JSC$expr_logical_or (ln, e1, e2)
4882 {
4883 this.etype = JSC$EXPR_LOGICAL;
4884
4885 if (e1.lang_type && e2.lang_type
4886 && e1.lang_type == JSC$JS_BOOLEAN && e2.lang_type == JSC$JS_BOOLEAN)
4887 this.lang_type = JSC$JS_BOOLEAN;
4888
4889 this.linenum = ln;
4890 this.e1 = e1;
4891 this.e2 = e2;
4892 this.asm = JSC$expr_logical_or_asm;
4893 }
4894
4895 function JSC$expr_logical_or_asm ()
4896 {
4897 this.e1.asm ();
4898
4899 var l = new JSC$ASM_label ();
4900 new JSC$ASM_dup (this.linenum).link ();
4901
4902 if (JSC$optimize_type && this.e1.lang_type
4903 && this.e1.lang_type == JSC$JS_BOOLEAN)
4904 new JSC$ASM_iftrue_b (this.linenum, l).link ();
4905 else
4906 new JSC$ASM_iftrue (this.linenum, l).link ();
4907
4908 new JSC$ASM_pop (this.linenum).link ();
4909
4910 this.e2.asm ();
4911
4912 /* Done label. */
4913 l.link ();
4914 }
4915
4916
4917 /* New expr. */
4918
4919 function JSC$expr_new (ln, expr, args)
4920 {
4921 this.etype = JSC$EXPR_NEW;
4922 this.linenum = ln;
4923 this.expr = expr;
4924 this.args = args;
4925 this.asm = JSC$expr_new_asm;
4926 }
4927
4928 function JSC$expr_new_asm ()
4929 {
4930 var i;
4931
4932 if (this.args)
4933 {
4934 /* Code for the arguments. */
4935 for (i = this.args.length - 1; i >= 0; i--)
4936 this.args[i].asm ();
4937
4938 if (this.args.length == 0)
4939 new JSC$ASM_const_i0 (this.linenum).link ();
4940 else if (this.args.length == 1)
4941 new JSC$ASM_const_i1 (this.linenum).link ();
4942 else if (this.args.length == 2)
4943 new JSC$ASM_const_i2 (this.linenum).link ();
4944 else if (this.args.length == 3)
4945 new JSC$ASM_const_i3 (this.linenum).link ();
4946 else
4947 new JSC$ASM_const (this.linenum, this.args.length).link ();
4948 }
4949 else
4950 {
4951 /* A `new Foo' call. This is identical to `new Foo ()'. */
4952 new JSC$ASM_const_i0 (this.linenum).link ();
4953 }
4954
4955 /* Object. */
4956 this.expr.asm ();
4957
4958 /* Call new. */
4959 new JSC$ASM_new (this.linenum).link ();
4960
4961 /* Replace the constructor's return value with the object. */
4962 new JSC$ASM_swap (this.linenum).link ();
4963
4964 /* Remove the arguments and return the new object. */
4965 new JSC$ASM_apop (this.linenum,
4966 (this.args ? this.args.length : 0) + 2).link ();
4967 }
4968
4969
4970 /* Object property expr. */
4971
4972 function JSC$expr_object_property (ln, expr, id)
4973 {
4974 this.etype = JSC$EXPR_OBJECT_PROPERTY;
4975 this.linenum = ln;
4976 this.expr = expr;
4977 this.id = id;
4978 this.asm = JSC$expr_object_property_asm;
4979 }
4980
4981 function JSC$expr_object_property_asm ()
4982 {
4983 JSC$asm_expr_lvalue_load_asm (this);
4984 }
4985
4986
4987 /* Object array expr. */
4988
4989 function JSC$expr_object_array (ln, expr1, expr2)
4990 {
4991 this.etype = JSC$EXPR_OBJECT_ARRAY;
4992 this.linenum = ln;
4993 this.expr1 = expr1;
4994 this.expr2 = expr2;
4995 this.asm = JSC$expr_object_array_asm;
4996 }
4997
4998 function JSC$expr_object_array_asm ()
4999 {
5000 JSC$asm_expr_lvalue_load_asm (this);
5001 }
5002
5003
5004 /* Call. */
5005
5006 function JSC$expr_call (ln, expr, args)
5007 {
5008 this.etype = JSC$EXPR_CALL;
5009 this.linenum = ln;
5010 this.expr = expr;
5011 this.args = args;
5012 this.asm = JSC$expr_call_asm;
5013 }
5014
5015 function JSC$expr_call_asm ()
5016 {
5017 var i;
5018
5019 /* Code for the arguments. */
5020 for (i = this.args.length - 1; i >= 0; i--)
5021 this.args[i].asm ();
5022
5023 if (this.args.length == 0)
5024 new JSC$ASM_const_i0 (this.linenum).link ();
5025 else if (this.args.length == 1)
5026 new JSC$ASM_const_i1 (this.linenum).link ();
5027 else if (this.args.length == 2)
5028 new JSC$ASM_const_i2 (this.linenum).link ();
5029 else if (this.args.length == 3)
5030 new JSC$ASM_const_i3 (this.linenum).link ();
5031 else
5032 new JSC$ASM_const (this.linenum, this.args.length).link ();
5033
5034 /* Check the function type. */
5035 if (this.expr.etype == JSC$EXPR_IDENTIFIER)
5036 {
5037 /* The simple subroutine or global object method invocation. */
5038
5039 var saved_with_nesting = JSC$cont_break.top.with_nesting;
5040 JSC$cont_break.top.with_nesting = 0;
5041
5042 JSC$asm_expr_lvalue_load_asm (this.expr);
5043
5044 JSC$cont_break.top.with_nesting = saved_with_nesting;
5045
5046 if (JSC$cont_break.top.with_nesting > 0)
5047 new JSC$ASM_jsr_w (this.linenum, this.expr.value).link ();
5048 else
5049 new JSC$ASM_jsr (this.linenum).link ();
5050
5051 new JSC$ASM_apop (this.linenum, this.args.length + 2).link ();
5052 }
5053 else if (this.expr.etype == JSC$EXPR_OBJECT_PROPERTY)
5054 {
5055 /* Method invocation. */
5056 this.expr.expr.asm ();
5057 new JSC$ASM_call_method (this.linenum, this.expr.id).link ();
5058 new JSC$ASM_apop (this.linenum, this.args.length + 2).link ();
5059 }
5060 else
5061 {
5062 /* Something like a function pointer invocation. */
5063 JSC$asm_expr_lvalue_load_asm (this.expr);
5064 new JSC$ASM_jsr (this.linenum).link ();
5065 new JSC$ASM_apop (this.linenum, this.args.length + 2).link ();
5066 }
5067 }
5068
5069
5070 /* Assignment. */
5071
5072 function JSC$expr_assignment (ln, type, expr1, expr2)
5073 {
5074 this.etype = JSC$EXPR_ASSIGNMENT;
5075 this.linenum = ln;
5076 this.type = type;
5077 this.expr1 = expr1;
5078 this.expr2 = expr2;
5079 this.asm = JSC$expr_assignment_asm;
5080 }
5081
5082 function JSC$expr_assignment_asm ()
5083 {
5084 if (this.type != #'=')
5085 JSC$asm_expr_lvalue_load_asm (this.expr1);
5086
5087 /* Count the rvalue. */
5088 this.expr2.asm ();
5089
5090 if (this.type == #'=')
5091 /* Nothing here. */
5092 ;
5093 else if (this.type == JSC$tMULA)
5094 new JSC$ASM_mul (this.linenum).link ();
5095 else if (this.type == JSC$tDIVA)
5096 new JSC$ASM_div (this.linenum).link ();
5097 else if (this.type == JSC$tMODA)
5098 new JSC$ASM_mod (this.linenum).link ();
5099 else if (this.type == JSC$tADDA)
5100 new JSC$ASM_add (this.linenum).link ();
5101 else if (this.type == JSC$tSUBA)
5102 new JSC$ASM_sub (this.linenum).link ();
5103 else if (this.type == JSC$tLSIA)
5104 new JSC$ASM_shift_left (this.linenum).link ();
5105 else if (this.type == JSC$tRSIA)
5106 new JSC$ASM_shift_right (this.linenum).link ();
5107 else if (this.type == JSC$tRRSA)
5108 new JSC$ASM_shift_rright (this.linenum).link ();
5109 else if (this.type == JSC$tANDA)
5110 new JSC$ASM_and (this.linenum).link ();
5111 else if (this.type == JSC$tXORA)
5112 new JSC$ASM_xor (this.linenum).link ();
5113 else if (this.type == JSC$tORA)
5114 new JSC$ASM_or (this.linenum).link ();
5115 else
5116 error (JSC$filename + ":" + this.linenum.toString ()
5117 + ": internal compiler error in assignment expression");
5118
5119 /* Duplicate the value. */
5120 new JSC$ASM_dup (this.linenum).link ();
5121
5122 /* Store it to the lvalue. */
5123 JSC$asm_expr_lvalue_store_asm (this.expr1);
5124 }
5125
5126 function JSC$asm_expr_lvalue_load_asm (expr)
5127 {
5128 var i;
5129
5130 if (expr.etype == JSC$EXPR_IDENTIFIER)
5131 {
5132 /* Must check global / local / argument. */
5133 i = JSC$ns.lookup_symbol (expr.value);
5134 if (i == null)
5135 {
5136 if (JSC$cont_break.top.with_nesting > 0)
5137 new JSC$ASM_load_global_w (expr.linenum, expr.value).link ();
5138 else
5139 new JSC$ASM_load_global (expr.linenum, expr.value).link ();
5140 }
5141 else if (i.scope == JSC$SCOPE_ARG)
5142 {
5143 if (JSC$cont_break.top.with_nesting > 0 && JSC$warn_with_clobber)
5144 JSC$warning (JSC$filename + ":" + expr.linenum.toString ()
5145 + ": warning: the with-lookup of symbol `" + i.symbol
5146 + "' is clobbered by the argument definition");
5147
5148 new JSC$ASM_load_arg (expr.linenum, i.value).link ();
5149 }
5150 else
5151 {
5152 if (JSC$cont_break.top.with_nesting > 0 && JSC$warn_with_clobber)
5153 JSC$warning (JSC$filename + ":" + expr.linenum.toString ()
5154 + ": warning: the with-lookup of symbol `" + i.symbol
5155 + "' is clobbered by the local variable definition");
5156
5157 new JSC$ASM_load_local (expr.linenum, i.value).link ();
5158 }
5159 }
5160 else if (expr.etype == JSC$EXPR_OBJECT_PROPERTY)
5161 {
5162 expr.expr.asm ();
5163 new JSC$ASM_load_property (expr.linenum, expr.id).link ();
5164 }
5165 else if (expr.etype == JSC$EXPR_OBJECT_ARRAY)
5166 {
5167 expr.expr1.asm ();
5168 expr.expr2.asm ();
5169 new JSC$ASM_load_array (expr.linenum).link ();
5170 }
5171 else
5172 error (JSC$filename + ":" + expr.linenum.toString () + ": syntax error");
5173 }
5174
5175 function JSC$asm_expr_lvalue_store_asm (expr)
5176 {
5177 var i;
5178
5179 if (expr.etype == JSC$EXPR_IDENTIFIER)
5180 {
5181 i = JSC$ns.lookup_symbol (expr.value);
5182 if (i == null)
5183 new JSC$ASM_store_global (expr.linenum, expr.value).link ();
5184 else if (i.scope == JSC$SCOPE_ARG)
5185 new JSC$ASM_store_arg (expr.linenum, i.value).link ();
5186 else
5187 new JSC$ASM_store_local (expr.linenum, i.value).link ();
5188 }
5189 else if (expr.etype == JSC$EXPR_OBJECT_PROPERTY)
5190 {
5191 expr.expr.asm ();
5192 new JSC$ASM_store_property (expr.linenum, expr.id).link ();
5193 }
5194 else if (expr.etype == JSC$EXPR_OBJECT_ARRAY)
5195 {
5196 expr.expr1.asm ();
5197 expr.expr2.asm ();
5198 new JSC$ASM_store_array (expr.linenum).link ();
5199 }
5200 else
5201 error (JSC$filename + ":" + expr.linenum.toString () + ": syntax error");
5202 }
5203
5204
5205 /* Quest colon. */
5206
5207 function JSC$expr_quest_colon (ln, e1, e2, e3)
5208 {
5209 this.etype = JSC$EXPR_QUEST_COLON;
5210 this.linenum = ln;
5211 this.e1 = e1;
5212 this.e2 = e2;
5213 this.e3 = e3;
5214 this.asm = JSC$expr_quest_colon_asm;
5215 }
5216
5217 function JSC$expr_quest_colon_asm()
5218 {
5219 /* Code for the condition. */
5220 this.e1.asm ();
5221
5222 var l1 = new JSC$ASM_label ();
5223 var l2 = new JSC$ASM_label ();
5224
5225 if (JSC$optimize_type && this.e1.lang_type
5226 && this.e1.lang_type == JSC$JS_BOOLEAN)
5227 new JSC$ASM_iffalse_b (this.linenum, l1).link ();
5228 else
5229 new JSC$ASM_iffalse (this.linenum, l1).link ();
5230
5231 /* Code for the true branch. */
5232 this.e2.asm ();
5233 new JSC$ASM_jmp (this.linenum, l2).link ();
5234
5235 /* Code for the false branch. */
5236 l1.link ();
5237 this.e3.asm ();
5238
5239 /* Done label. */
5240 l2.link ();
5241 }
5242
5243
5244 /* Unary. */
5245
5246 function JSC$expr_unary (ln, type, expr)
5247 {
5248 this.etype = JSC$EXPR_UNARY;
5249 this.linenum = ln;
5250 this.type = type;
5251 this.expr = expr;
5252 this.asm = JSC$expr_unary_asm;
5253 }
5254
5255 function JSC$expr_unary_asm ()
5256 {
5257 if (this.type == #'!')
5258 {
5259 this.expr.asm ();
5260 new JSC$ASM_not (this.linenum).link ();
5261 }
5262 else if (this.type == #'+')
5263 {
5264 this.expr.asm ();
5265 /* Nothing here. */
5266 }
5267 else if (this.type == #'~')
5268 {
5269 this.expr.asm ();
5270 new JSC$ASM_const (this.linenum, -1).link ();
5271 new JSC$ASM_xor (this.linenum).link ();
5272 }
5273 else if (this.type == #'-')
5274 {
5275 this.expr.asm ();
5276 new JSC$ASM_neg (this.linenum).link ();
5277 }
5278 else if (this.type == JSC$tDELETE)
5279 {
5280 if (this.expr.etype == JSC$EXPR_OBJECT_PROPERTY)
5281 {
5282 this.expr.expr.asm ();
5283 new JSC$ASM_delete_property (this.linenum, this.expr.id).link ();
5284 }
5285 else if (this.expr.etype == JSC$EXPR_OBJECT_ARRAY)
5286 {
5287 this.expr.expr1.asm ();
5288 this.expr.expr2.asm ();
5289 new JSC$ASM_delete_array (this.linenum).link ();
5290 }
5291 else if (this.expr.etype == JSC$EXPR_IDENTIFIER)
5292 {
5293 if (JSC$cont_break.top.with_nesting == 0)
5294 error (JSC$filename + ":" + this.linenum.toString ()
5295 + ": `delete property' called outside of a with-block");
5296
5297 new JSC$ASM_const_null (this.linenum).link ();
5298 new JSC$ASM_delete_property (this.linenum, this.expr.value).link ();
5299 }
5300 else
5301 error (JSC$filename + ":" + this.linenum.toString ()
5302 + ": illegal target for the delete operand");
5303 }
5304 else if (this.type == JSC$tVOID)
5305 {
5306 this.expr.asm ();
5307 new JSC$ASM_pop (this.linenum).link ();
5308 new JSC$ASM_const_undefined (this.linenum).link ();
5309 }
5310 else if (this.type == JSC$tTYPEOF)
5311 {
5312 this.expr.asm ();
5313 new JSC$ASM_typeof (this.linenum).link ();
5314 }
5315 else if (this.type == JSC$tPLUSPLUS
5316 || this.type == JSC$tMINUSMINUS)
5317 {
5318 /* Fetch the old value. */
5319 JSC$asm_expr_lvalue_load_asm (this.expr);
5320
5321 /* Do the operation. */
5322 new JSC$ASM_const_i1 (this.linenum).link ();
5323 if (this.type == JSC$tPLUSPLUS)
5324 new JSC$ASM_add (this.linenum).link ();
5325 else
5326 new JSC$ASM_sub (this.linenum).link ();
5327
5328 /* Duplicate the value and store one copy pack to lvalue. */
5329 new JSC$ASM_dup (this.linenum).link ();
5330 JSC$asm_expr_lvalue_store_asm (this.expr);
5331 }
5332 else
5333 {
5334 error ("jsc: internal error: unary expr's type is "
5335 + this.type.toString ());
5336 }
5337 }
5338
5339
5340 /* Postfix. */
5341
5342 function JSC$expr_postfix (ln, type, expr)
5343 {
5344 this.etype = JSC$EXPR_POSTFIX;
5345 this.linenum = ln;
5346 this.type = type;
5347 this.expr = expr;
5348 this.asm = JSC$expr_postfix_asm;
5349 }
5350
5351 function JSC$expr_postfix_asm ()
5352 {
5353 /* Fetch the old value. */
5354 JSC$asm_expr_lvalue_load_asm (this.expr);
5355
5356 /* Duplicate the value since it is the expression's value. */
5357 new JSC$ASM_dup (this.linenum).link ();
5358
5359 /* Do the operation. */
5360 new JSC$ASM_const_i1 (this.linenum).link ();
5361 if (this.type == JSC$tPLUSPLUS)
5362 new JSC$ASM_add (this.linenum).link ();
5363 else
5364 new JSC$ASM_sub (this.linenum).link ();
5365
5366 /* And finally, store it back. */
5367 JSC$asm_expr_lvalue_store_asm (this.expr);
5368 }
5369
5370
5371 /* Postfix. */
5372
5373 function JSC$expr_comma (ln, expr1, expr2)
5374 {
5375 this.etype = JSC$EXPR_COMMA;
5376 this.linenum = ln;
5377 this.expr1 = expr1;
5378 this.expr2 = expr2;
5379 this.asm = JSC$expr_comma_asm;
5380 }
5381
5382 function JSC$expr_comma_asm ()
5383 {
5384 this.expr1.asm ();
5385 new JSC$ASM_pop (this.linenum).link ();
5386 this.expr2.asm ();
5387 }
5388
5389 \f
5390 /*
5391 Local variables:
5392 mode: c
5393 End:
5394 */
5395 /*
5396 * Namespace handling.
5397 * Copyright (c) 1998 New Generation Software (NGS) Oy
5398 *
5399 * Author: Markku Rossi <mtr@ngs.fi>
5400 */
5401
5402 /*
5403 * This library is free software; you can redistribute it and/or
5404 * modify it under the terms of the GNU Library General Public
5405 * License as published by the Free Software Foundation; either
5406 * version 2 of the License, or (at your option) any later version.
5407 *
5408 * This library is distributed in the hope that it will be useful,
5409 * but WITHOUT ANY WARRANTY; without even the implied warranty of
5410 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5411 * Library General Public License for more details.
5412 *
5413 * You should have received a copy of the GNU Library General Public
5414 * License along with this library; if not, write to the Free
5415 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
5416 * MA 02111-1307, USA
5417 */
5418
5419 /*
5420 * $Source: /cygdrive/c/RCVS/CVS/ReactOS/reactos/lib/kjs/jsc/compiler.js,v $
5421 * $Id$
5422 */
5423
5424 /*
5425 * Global functions.
5426 */
5427
5428 JSC$SCOPE_ARG = 1;
5429 JSC$SCOPE_LOCAL = 2;
5430
5431 function JSC$NameSpace ()
5432 {
5433 this.frame = new JSC$NameSpaceFrame ();
5434 this.push_frame = JSC$NameSpace_push_frame;
5435 this.pop_frame = JSC$NameSpace_pop_frame;
5436 this.alloc_local = JSC$NameSpace_alloc_local;
5437 this.define_symbol = JSC$NameSpace_define_symbol;
5438 this.lookup_symbol = JSC$NameSpace_lookup_symbol;
5439 }
5440
5441
5442 function JSC$NameSpace_push_frame ()
5443 {
5444 var f = new JSC$NameSpaceFrame ();
5445
5446 f.num_locals = this.frame.num_locals;
5447
5448 f.next = this.frame;
5449 this.frame = f;
5450 }
5451
5452
5453 function JSC$NameSpace_pop_frame ()
5454 {
5455 var i;
5456
5457 for (i = this.frame.defs; i != null; i = i.next)
5458 if (i.usecount == 0)
5459 {
5460 if (i.scope == JSC$SCOPE_ARG)
5461 {
5462 if (JSC$warn_unused_argument)
5463 JSC$warning (JSC$filename + ":" + i.linenum.toString ()
5464 + ": warning: unused argument `" + i.symbol + "'");
5465 }
5466 else
5467 {
5468 if (JSC$warn_unused_variable)
5469 JSC$warning (JSC$filename + ":" + i.linenum.toString ()
5470 + ": warning: unused variable `" + i.symbol + "'");
5471 }
5472 }
5473
5474 this.frame = this.frame.next;
5475 }
5476
5477
5478 function JSC$NameSpace_alloc_local ()
5479 {
5480 return this.frame.num_locals++;
5481 }
5482
5483
5484 function JSC$NameSpace_define_symbol (symbol, scope, value, linenum)
5485 {
5486 var i;
5487
5488 for (i = this.frame.defs; i != null; i = i.next)
5489 if (i.symbol == symbol)
5490 {
5491 if (i.scope == scope)
5492 error (JSC$filename + ":" + i.linenum.toString()
5493 + ": redeclaration of `" + i.symbol + "'");
5494 if (i.scope == JSC$SCOPE_ARG && JSC$warn_shadow)
5495 JSC$warning (JSC$filename + ":" + linenum.toString ()
5496 + ": warning: declaration of `" + symbol
5497 + "' shadows a parameter");
5498
5499 i.scope = scope;
5500 i.value = value;
5501 i.linenum = linenum;
5502
5503 return;
5504 }
5505
5506 /* Create a new definition. */
5507 i = new JSC$SymbolDefinition (symbol, scope, value, linenum);
5508 i.next = this.frame.defs;
5509 this.frame.defs = i;
5510 }
5511
5512
5513 function JSC$NameSpace_lookup_symbol (symbol)
5514 {
5515 var f, i;
5516
5517 for (f = this.frame; f != null; f = f.next)
5518 for (i = f.defs; i != null; i = i.next)
5519 if (i.symbol == symbol)
5520 {
5521 i.usecount++;
5522 return i;
5523 }
5524
5525 return null;
5526 }
5527
5528 /*
5529 * Static helpers.
5530 */
5531
5532 function JSC$NameSpaceFrame ()
5533 {
5534 this.next = null;
5535 this.defs = null;
5536 this.num_locals = 0;
5537 }
5538
5539
5540 function JSC$SymbolDefinition (symbol, scope, value, linenum)
5541 {
5542 this.next = null;
5543 this.symbol = symbol;
5544 this.scope = scope;
5545 this.value = value;
5546 this.linenum = linenum;
5547 this.usecount = 0;
5548 }
5549
5550 \f
5551 /*
5552 Local variables:
5553 mode: c
5554 End:
5555 */
5556 /*
5557 * Input stream definitions.
5558 * Copyright (c) 1998 New Generation Software (NGS) Oy
5559 *
5560 * Author: Markku Rossi <mtr@ngs.fi>
5561 */
5562
5563 /*
5564 * This library is free software; you can redistribute it and/or
5565 * modify it under the terms of the GNU Library General Public
5566 * License as published by the Free Software Foundation; either
5567 * version 2 of the License, or (at your option) any later version.
5568 *
5569 * This library is distributed in the hope that it will be useful,
5570 * but WITHOUT ANY WARRANTY; without even the implied warranty of
5571 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5572 * Library General Public License for more details.
5573 *
5574 * You should have received a copy of the GNU Library General Public
5575 * License along with this library; if not, write to the Free
5576 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
5577 * MA 02111-1307, USA
5578 */
5579
5580 /*
5581 * $Source: /cygdrive/c/RCVS/CVS/ReactOS/reactos/lib/kjs/jsc/compiler.js,v $
5582 * $Id$
5583 */
5584
5585 /*
5586 * File stream.
5587 */
5588
5589 function JSC$StreamFile (name)
5590 {
5591 this.name = name;
5592 this.stream = new File (name);
5593 this.error = "";
5594
5595 this.open = JSC$StreamFile_open;
5596 this.close = JSC$StreamFile_close;
5597 this.rewind = JSC$StreamFile_rewind;
5598 this.readByte = JSC$StreamFile_read_byte;
5599 this.ungetByte = JSC$StreamFile_unget_byte;
5600 this.readln = JSC$StreamFile_readln;
5601 }
5602
5603
5604 function JSC$StreamFile_open ()
5605 {
5606 if (!this.stream.open ("r"))
5607 {
5608 this.error = System.strerror (System.errno);
5609 return false;
5610 }
5611
5612 return true;
5613 }
5614
5615
5616 function JSC$StreamFile_close ()
5617 {
5618 return this.stream.close ();
5619 }
5620
5621
5622 function JSC$StreamFile_rewind ()
5623 {
5624 return this.stream.setPosition (0);
5625 }
5626
5627
5628 function JSC$StreamFile_read_byte ()
5629 {
5630 return this.stream.readByte ();
5631 }
5632
5633
5634 function JSC$StreamFile_unget_byte (byte)
5635 {
5636 this.stream.ungetByte (byte);
5637 }
5638
5639
5640 function JSC$StreamFile_readln ()
5641 {
5642 return this.stream.readln ();
5643 }
5644
5645
5646 /*
5647 * String stream.
5648 */
5649
5650 function JSC$StreamString (str)
5651 {
5652 this.name = "StringStream";
5653 this.string = str;
5654 this.pos = 0;
5655 this.unget_byte = -1;
5656 this.error = "";
5657
5658 this.open = JSC$StreamString_open;
5659 this.close = JSC$StreamString_close;
5660 this.rewind = JSC$StreamString_rewind;
5661 this.readByte = JSC$StreamString_read_byte;
5662 this.ungetByte = JSC$StreamString_unget_byte;
5663 this.readln = JSC$StreamString_readln;
5664 }
5665
5666
5667 function JSC$StreamString_open ()
5668 {
5669 return true;
5670 }
5671
5672
5673 function JSC$StreamString_close ()
5674 {
5675 return true;
5676 }
5677
5678
5679 function JSC$StreamString_rewind ()
5680 {
5681 this.pos = 0;
5682 this.unget_byte = -1;
5683 this.error = "";
5684 return true;
5685 }
5686
5687
5688 function JSC$StreamString_read_byte ()
5689 {
5690 var ch;
5691
5692 if (this.unget_byte >= 0)
5693 {
5694 ch = this.unget_byte;
5695 this.unget_byte = -1;
5696 return ch;
5697 }
5698
5699 if (this.pos >= this.string.length)
5700 return -1;
5701
5702 return this.string.charCodeAt (this.pos++);
5703 }
5704
5705
5706 function JSC$StreamString_unget_byte (byte)
5707 {
5708 this.unget_byte = byte;
5709 }
5710
5711
5712 function JSC$StreamString_readln ()
5713 {
5714 var line = new String ("");
5715 var ch;
5716
5717 while ((ch = this.readByte ()) != -1 && ch != #'\n')
5718 line.append (String.pack ("C", ch));
5719
5720 return line;
5721 }
5722
5723 \f
5724 /*
5725 Local variables:
5726 mode: c
5727 End:
5728 */
5729 /*
5730 * JavaScript Assembler.
5731 * Copyright (c) 1998 New Generation Software (NGS) Oy
5732 *
5733 * Author: Markku Rossi <mtr@ngs.fi>
5734 */
5735
5736 /*
5737 * This library is free software; you can redistribute it and/or
5738 * modify it under the terms of the GNU Library General Public
5739 * License as published by the Free Software Foundation; either
5740 * version 2 of the License, or (at your option) any later version.
5741 *
5742 * This library is distributed in the hope that it will be useful,
5743 * but WITHOUT ANY WARRANTY; without even the implied warranty of
5744 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5745 * Library General Public License for more details.
5746 *
5747 * You should have received a copy of the GNU Library General Public
5748 * License along with this library; if not, write to the Free
5749 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
5750 * MA 02111-1307, USA
5751 */
5752
5753 /*
5754 * $Source: /cygdrive/c/RCVS/CVS/ReactOS/reactos/lib/kjs/jsc/compiler.js,v $
5755 * $Id$
5756 */
5757
5758 /* Byte-code file definitions. */
5759
5760 JSC$BC_MAGIC = 0xc0014a53;
5761
5762 JSC$BC_SECT_CODE = 0;
5763 JSC$BC_SECT_CONSTANTS = 1;
5764 JSC$BC_SECT_SYMTAB = 2;
5765 JSC$BC_SECT_DEBUG = 3;
5766
5767 JSC$CONST_INT = 3;
5768 JSC$CONST_STRING = 4;
5769 JSC$CONST_FLOAT = 5;
5770 JSC$CONST_SYMBOL = 10;
5771 JSC$CONST_REGEXP = 11;
5772 JSC$CONST_NAN = 13;
5773
5774 JSC$CONST_REGEXP_FLAG_G = 0x01;
5775 JSC$CONST_REGEXP_FLAG_I = 0x02;
5776
5777 JSC$DEBUG_FILENAME = 1;
5778 JSC$DEBUG_LINENUMBER = 2;
5779
5780 /* Opcode definitions. */
5781
5782 JSC$OP_HALT = 0;
5783 JSC$OP_DONE = 1;
5784 JSC$OP_NOP = 2;
5785 JSC$OP_DUP = 3;
5786 JSC$OP_POP = 4;
5787 JSC$OP_POP_N = 5;
5788 JSC$OP_APOP = 6;
5789 JSC$OP_SWAP = 7;
5790 JSC$OP_ROLL = 8;
5791 JSC$OP_CONST = 9;
5792 JSC$OP_CONST_NULL = 10;
5793 JSC$OP_CONST_TRUE = 11;
5794 JSC$OP_CONST_FALSE = 12;
5795 JSC$OP_CONST_UNDEFINED = 13;
5796 JSC$OP_CONST_I0 = 14;
5797 JSC$OP_CONST_I1 = 15;
5798 JSC$OP_CONST_I2 = 16;
5799 JSC$OP_CONST_I3 = 17;
5800 JSC$OP_CONST_I = 18;
5801 JSC$OP_LOAD_GLOBAL = 19;
5802 JSC$OP_STORE_GLOBAL = 20;
5803 JSC$OP_LOAD_ARG = 21;
5804 JSC$OP_STORE_ARG = 22;
5805 JSC$OP_LOAD_LOCAL = 23;
5806 JSC$OP_STORE_LOCAL = 24;
5807 JSC$OP_LOAD_PROPERTY = 25;
5808 JSC$OP_STORE_PROPERTY = 26;
5809 JSC$OP_LOAD_ARRAY = 27;
5810 JSC$OP_STORE_ARRAY = 28;
5811 JSC$OP_NTH = 29;
5812 JSC$OP_CMP_EQ = 30;
5813 JSC$OP_CMP_NE = 31;
5814 JSC$OP_CMP_LT = 32;
5815 JSC$OP_CMP_GT = 33;
5816 JSC$OP_CMP_LE = 34;
5817 JSC$OP_CMP_GE = 35;
5818 JSC$OP_CMP_SEQ = 36;
5819 JSC$OP_CMP_SNE = 37;
5820 JSC$OP_SUB = 38;
5821 JSC$OP_ADD = 39;
5822 JSC$OP_MUL = 40;
5823 JSC$OP_DIV = 41;
5824 JSC$OP_MOD = 42;
5825 JSC$OP_NEG = 43;
5826 JSC$OP_AND = 44;
5827 JSC$OP_NOT = 45;
5828 JSC$OP_OR = 46;
5829 JSC$OP_XOR = 47;
5830 JSC$OP_SHIFT_LEFT = 48;
5831 JSC$OP_SHIFT_RIGHT = 49;
5832 JSC$OP_SHIFT_RRIGHT = 50;
5833 JSC$OP_IFFALSE = 51;
5834 JSC$OP_IFTRUE = 52;
5835 JSC$OP_CALL_METHOD = 53;
5836 JSC$OP_JMP = 54;
5837 JSC$OP_JSR = 55;
5838 JSC$OP_RETURN = 56;
5839 JSC$OP_TYPEOF = 57;
5840 JSC$OP_NEW = 58;
5841 JSC$OP_DELETE_PROPERTY = 59;
5842 JSC$OP_DELETE_ARRAY = 60;
5843 JSC$OP_LOCALS = 61;
5844 JSC$OP_MIN_ARGS = 62;
5845 JSC$OP_LOAD_NTH_ARG = 63;
5846 JSC$OP_WITH_PUSH = 64;
5847 JSC$OP_WITH_POP = 65;
5848 JSC$OP_TRY_PUSH = 66;
5849 JSC$OP_TRY_POP = 67;
5850 JSC$OP_THROW = 68;
5851
5852 /* Type aware operands. */
5853 JSC$OP_IFFALSE_B = 69;
5854 JSC$OP_IFTRUE_B = 70;
5855 JSC$OP_ADD_1_I = 71;
5856 JSC$OP_ADD_2_I = 72;
5857 JSC$OP_LOAD_GLOBAL_W = 73;
5858 JSC$OP_JSR_W = 74;
5859
5860 /* Internal values. */
5861 JSC$ASM_SYMBOL = 1000;
5862 JSC$ASM_LABEL = 1001;
5863
5864 /*
5865 * General helpers.
5866 */
5867
5868 /* Generate byte-code for operands with Int8 value. */
5869 function JSC$ASM_bytecode_int8 ()
5870 {
5871 return String.pack ("C", this.value);
5872 }
5873
5874 /* Generate byte-code for operands with Int16 value. */
5875 function JSC$ASM_bytecode_int16 ()
5876 {
5877 return String.pack ("n", this.value);
5878 }
5879
5880 /* Generate byte-code for operands with Int32 value. */
5881 function JSC$ASM_bytecode_int32 ()
5882 {
5883 return String.pack ("N", this.value);
5884 }
5885
5886 /* Generate byte-code for operands with Symbol value. */
5887 function JSC$ASM_bytecode_symbol ()
5888 {
5889 var cid = JSC$asm_genconstant (String.pack ("C", JSC$CONST_SYMBOL)
5890 + this.value + String.pack ("C", 0));
5891 return String.pack ("N", cid);
5892 }
5893
5894 /* Generate byte-code for local jump operands. */
5895 function JSC$ASM_bytecode_local_jump ()
5896 {
5897 var delta = this.value.offset - (this.offset + this.size);
5898 return String.pack ("N", delta);
5899 }
5900
5901
5902 /*
5903 * Assembler operands.
5904 */
5905
5906 /* Symbol. */
5907
5908 function JSC$ASM_symbol (ln, value)
5909 {
5910 this.type = JSC$ASM_SYMBOL;
5911 this.linenum = ln;
5912 this.value = value;
5913 this.size = 0;
5914 this.print = JSC$ASM_symbol_print;
5915 this.link = JSC$asm_link;
5916 }
5917
5918 function JSC$ASM_symbol_print (stream)
5919 {
5920 stream.write ("\n" + this.value + ":\n");
5921 }
5922
5923 /* Label */
5924
5925 function JSC$ASM_label ()
5926 {
5927 this.type = JSC$ASM_LABEL;
5928 this.linenum = 0;
5929 this.size = 0;
5930 this.value = JSC$asm_label_count++;
5931 this.referenced = false;
5932 this.next = null;
5933 this.print = JSC$ASM_label_print;
5934 this.link = JSC$asm_link;
5935 this.format = JSC$ASM_label_format;
5936 }
5937
5938 function JSC$ASM_label_print (stream)
5939 {
5940 stream.write (this.format () + ":\n");
5941 }
5942
5943 function JSC$ASM_label_format ()
5944 {
5945 return ".L" + this.value.toString ();
5946 }
5947
5948 /* halt */
5949
5950 function JSC$ASM_halt (ln)
5951 {
5952 this.type = JSC$OP_HALT;
5953 this.linenum = ln;
5954 this.size = 1;
5955 this.print = JSC$ASM_halt_print;
5956 this.link = JSC$asm_link;
5957 }
5958
5959 function JSC$ASM_halt_print (stream)
5960 {
5961 stream.write ("\thalt\n");
5962 }
5963
5964 /* done */
5965
5966 function JSC$ASM_done (ln)
5967 {
5968 this.type = JSC$OP_DONE;
5969 this.linenum = ln;
5970 this.size = 1;
5971 this.print = JSC$ASM_done_print;
5972 this.link = JSC$asm_link;
5973 }
5974
5975 function JSC$ASM_done_print (stream)
5976 {
5977 stream.write ("\tdone\n");
5978 }
5979
5980 /* nop */
5981
5982 function JSC$ASM_nop (ln)
5983 {
5984 this.type = JSC$OP_NOP;
5985 this.linenum = ln;
5986 this.size = 1;
5987 this.print = JSC$ASM_nop_print;
5988 this.link = JSC$asm_link;
5989 }
5990
5991 function JSC$ASM_nop_print (stream)
5992 {
5993 stream.write ("\tnop\n");
5994 }
5995
5996 /* dup */
5997
5998 function JSC$ASM_dup (ln)
5999 {
6000 this.type = JSC$OP_DUP;
6001 this.linenum = ln;
6002 this.stack_delta = 1;
6003 this.size = 1;
6004 this.print = JSC$ASM_dup_print;
6005 this.link = JSC$asm_link;
6006 }
6007
6008 function JSC$ASM_dup_print (stream)
6009 {
6010 stream.write ("\tdup\n");
6011 }
6012
6013 /* pop */
6014
6015 function JSC$ASM_pop (ln)
6016 {
6017 this.type = JSC$OP_POP;
6018 this.linenum = ln;
6019 this.stack_delta = -1;
6020 this.size = 1;
6021 this.print = JSC$ASM_pop_print;
6022 this.link = JSC$asm_link;
6023 }
6024
6025 function JSC$ASM_pop_print (stream)
6026 {
6027 stream.write ("\tpop\n");
6028 }
6029
6030 /* pop_n */
6031
6032 function JSC$ASM_pop_n (ln, value)
6033 {
6034 this.type = JSC$OP_POP_N;
6035 this.linenum = ln;
6036 this.value = value;
6037 this.stack_delta = -value;
6038 this.size = 2;
6039 this.print = JSC$ASM_pop_n_print;
6040 this.link = JSC$asm_link;
6041 this.bytecode = JSC$ASM_bytecode_int8;
6042 }
6043
6044 function JSC$ASM_pop_n_print (stream)
6045 {
6046 stream.write ("\tpop_n\t\t" + this.value.toString () + "\n");
6047 }
6048
6049 /* apop */
6050
6051 function JSC$ASM_apop (ln, value)
6052 {
6053 this.type = JSC$OP_APOP;
6054 this.linenum = ln;
6055 this.value = value;
6056 this.stack_delta = -value;
6057 this.size = 2;
6058 this.print = JSC$ASM_apop_print;
6059 this.link = JSC$asm_link;
6060 this.bytecode = JSC$ASM_bytecode_int8;
6061 }
6062
6063 function JSC$ASM_apop_print (stream)
6064 {
6065 stream.write ("\tapop\t\t" + this.value.toString () + "\n");
6066 }
6067
6068 /* swap */
6069
6070 function JSC$ASM_swap (ln)
6071 {
6072 this.type = JSC$OP_SWAP;
6073 this.linenum = ln;
6074 this.size = 1;
6075 this.print = JSC$ASM_swap_print;
6076 this.link = JSC$asm_link;
6077 }
6078
6079 function JSC$ASM_swap_print (stream)
6080 {
6081 stream.write ("\tswap\n");
6082 }
6083
6084 /* roll */
6085 function JSC$ASM_roll (ln, value)
6086 {
6087 this.type = JSC$OP_ROLL;
6088 this.linenum = ln;
6089 this.value = value;
6090 this.size = 2;
6091 this.print = JSC$ASM_roll_print;
6092 this.link = JSC$asm_link;
6093 this.bytecode = JSC$ASM_bytecode_int8;
6094 }
6095
6096 function JSC$ASM_roll_print (stream)
6097 {
6098 stream.write ("\troll\t\t" + this.value.toString () + "\n");
6099 }
6100
6101 /* const */
6102
6103 function JSC$ASM_const (ln, value)
6104 {
6105 this.type = JSC$OP_CONST;
6106 this.linenum = ln;
6107 this.value = value;
6108 this.stack_delta = 1;
6109 this.size = 5;
6110 this.print = JSC$ASM_const_print;
6111 this.link = JSC$asm_link;
6112 this.bytecode = JSC$ASM_const_bytecode;
6113 }
6114
6115 function JSC$ASM_const_print (stream)
6116 {
6117 if (typeof this.value == "number")
6118 stream.write ("\tconst\t\t" + this.value.toString () + "\n");
6119 else if (typeof this.value == "string"
6120 || typeof this.value == "#builtin")
6121 {
6122 var i, c;
6123 var ender, src;
6124 var stringp = (typeof this.value == "string");
6125
6126 if (stringp)
6127 {
6128 ender = "\"";
6129 src = this.value;
6130 }
6131 else
6132 {
6133 ender = "/";
6134 src = this.value.source;
6135 }
6136
6137 stream.write ("\tconst\t\t" + ender);
6138 for (i = 0; i < src.length; i++)
6139 {
6140 c = src.charCodeAt (i);
6141 if (c == ender[0] || c == #'\\')
6142 stream.write ("\\" + src.charAt (i));
6143 else if (c == #'\n')
6144 stream.write ("\\n");
6145 else if (c == #'\r')
6146 stream.write ("\\r");
6147 else if (c == #'\t')
6148 stream.write ("\\t");
6149 else if (c == #'\f')
6150 stream.write ("\\f");
6151 else
6152 stream.write (src.charAt (i));
6153 }
6154 stream.write (ender);
6155
6156 if (!stringp)
6157 {
6158 if (this.value.global)
6159 stream.write ("g");
6160 if (this.value.ignoreCase)
6161 stream.write ("i");
6162 }
6163
6164 stream.write ("\n");
6165 }
6166 }
6167
6168 function JSC$ASM_const_bytecode ()
6169 {
6170 var cid;
6171
6172 if (typeof this.value == "number")
6173 {
6174 if (isInt (this.value))
6175 cid = JSC$asm_genconstant (String.pack ("CN", JSC$CONST_INT,
6176 this.value));
6177 else if (isFloat (this.value))
6178 cid = JSC$asm_genconstant (String.pack ("Cd", JSC$CONST_FLOAT,
6179 this.value));
6180 else
6181 cid = JSC$asm_genconstant (String.pack ("C", JSC$CONST_NAN));
6182 }
6183 else if (typeof this.value == "string")
6184 cid = JSC$asm_genconstant (String.pack ("CN", JSC$CONST_STRING,
6185 this.value.length)
6186 + this.value);
6187 else if (typeof this.value == "#builtin")
6188 {
6189 /* Regular expression. */
6190 var flags = 0;
6191
6192 if (this.value.global)
6193 flags |= JSC$CONST_REGEXP_FLAG_G;
6194 if (this.value.ignoreCase)
6195 flags |= JSC$CONST_REGEXP_FLAG_I;
6196
6197 cid = JSC$asm_genconstant (String.pack ("CCN", JSC$CONST_REGEXP, flags,
6198 this.value.source.length)
6199 + this.value.source);
6200 }
6201 else
6202 error ("ASM_const_bytecode(): unknown type: " + typeof this.value);
6203
6204 return String.pack ("N", cid);
6205 }
6206
6207 /* const_null */
6208
6209 function JSC$ASM_const_null (ln)
6210 {
6211 this.type = JSC$OP_CONST_NULL;
6212 this.linenum = ln;
6213 this.stack_delta = 1;
6214 this.size = 1;
6215 this.print = JSC$ASM_const_null_print;
6216 this.link = JSC$asm_link;
6217 }
6218
6219 function JSC$ASM_const_null_print (stream)
6220 {
6221 stream.write ("\tconst_null\n");
6222 }
6223
6224 /* const_true */
6225
6226 function JSC$ASM_const_true (ln)
6227 {
6228 this.type = JSC$OP_CONST_TRUE;
6229 this.linenum = ln;
6230 this.stack_delta = 1;
6231 this.size = 1;
6232 this.print = JSC$ASM_const_true_print;
6233 this.link = JSC$asm_link;
6234 }
6235
6236 function JSC$ASM_const_true_print (stream)
6237 {
6238 stream.write ("\tconst_true\n");
6239 }
6240
6241 /* const_false */
6242
6243 function JSC$ASM_const_false (ln)
6244 {
6245 this.type = JSC$OP_CONST_FALSE;
6246 this.linenum = ln;
6247 this.stack_delta = 1;
6248 this.size = 1;
6249 this.print = JSC$ASM_const_false_print;
6250 this.link = JSC$asm_link;
6251 }
6252
6253 function JSC$ASM_const_false_print (stream)
6254 {
6255 stream.write ("\tconst_false\n");
6256 }
6257
6258 /* const_undefined */
6259
6260 function JSC$ASM_const_undefined (ln)
6261 {
6262 this.type = JSC$OP_CONST_UNDEFINED;
6263 this.linenum = ln;
6264 this.stack_delta = 1;
6265 this.size = 1;
6266 this.print = JSC$ASM_const_undefined_print;
6267 this.link = JSC$asm_link;
6268 }
6269
6270 function JSC$ASM_const_undefined_print (stream)
6271 {
6272 stream.write ("\tconst_undefined\n");
6273 }
6274
6275 /* const_i0 */
6276
6277 function JSC$ASM_const_i0 (ln)
6278 {
6279 this.type = JSC$OP_CONST_I0;
6280 this.linenum = ln;
6281 this.stack_delta = 1;
6282 this.size = 1;
6283 this.print = JSC$ASM_const_i0_print;
6284 this.link = JSC$asm_link;
6285 }
6286
6287 function JSC$ASM_const_i0_print (stream)
6288 {
6289 stream.write ("\tconst_i0\n");
6290 }
6291
6292 /* const_i1 */
6293
6294 function JSC$ASM_const_i1 (ln)
6295 {
6296 this.type = JSC$OP_CONST_I1;
6297 this.linenum = ln;
6298 this.stack_delta = 1;
6299 this.size = 1;
6300 this.print = JSC$ASM_const_i1_print;
6301 this.link = JSC$asm_link;
6302 }
6303
6304 function JSC$ASM_const_i1_print (stream)
6305 {
6306 stream.write ("\tconst_i1\n");
6307 }
6308
6309 /* const_i2 */
6310
6311 function JSC$ASM_const_i2 (ln)
6312 {
6313 this.type = JSC$OP_CONST_I2;
6314 this.linenum = ln;
6315 this.stack_delta = 1;
6316 this.size = 1;
6317 this.print = JSC$ASM_const_i2_print;
6318 this.link = JSC$asm_link;
6319 }
6320
6321 function JSC$ASM_const_i2_print (stream)
6322 {
6323 stream.write ("\tconst_i2\n");
6324 }
6325
6326 /* const_i3 */
6327
6328 function JSC$ASM_const_i3 (ln)
6329 {
6330 this.type = JSC$OP_CONST_I3;
6331 this.linenum = ln;
6332 this.stack_delta = 1;
6333 this.size = 1;
6334 this.print = JSC$ASM_const_i3_print;
6335 this.link = JSC$asm_link;
6336 }
6337
6338 function JSC$ASM_const_i3_print (stream)
6339 {
6340 stream.write ("\tconst_i3\n");
6341 }
6342
6343 /* const_i */
6344
6345 function JSC$ASM_const_i (ln, value)
6346 {
6347 this.type = JSC$OP_CONST_I;
6348 this.linenum = ln;
6349 this.value = value;
6350 this.stack_delta = 1;
6351 this.size = 5;
6352 this.print = JSC$ASM_const_i_print;
6353 this.bytecode = JSC$ASM_bytecode_int32;
6354 this.link = JSC$asm_link;
6355 }
6356
6357 function JSC$ASM_const_i_print (stream)
6358 {
6359 stream.write ("\tconst_i\t\t" + this.value.toString () + "\n");
6360 }
6361
6362 /* load_global */
6363
6364 function JSC$ASM_load_global (ln, value)
6365 {
6366 this.type = JSC$OP_LOAD_GLOBAL;
6367 this.linenum = ln;
6368 this.value = value;
6369 this.stack_delta = 1;
6370 this.size = 5;
6371 this.print = JSC$ASM_load_global_print;
6372 this.bytecode = JSC$ASM_bytecode_symbol;
6373 this.link = JSC$asm_link;
6374 }
6375
6376 function JSC$ASM_load_global_print (stream)
6377 {
6378 stream.write ("\tload_global\t" + this.value + "\n");
6379 }
6380
6381 /* store_global */
6382
6383 function JSC$ASM_store_global (ln, value)
6384 {
6385 this.type = JSC$OP_STORE_GLOBAL;
6386 this.linenum = ln;
6387 this.value = value;
6388 this.stack_delta = -1;
6389 this.size = 5;
6390 this.print = JSC$ASM_store_global_print;
6391 this.bytecode = JSC$ASM_bytecode_symbol;
6392 this.link = JSC$asm_link;
6393 }
6394
6395 function JSC$ASM_store_global_print (stream)
6396 {
6397 stream.write ("\tstore_global\t" + this.value + "\n");
6398 }
6399
6400 /* load_arg */
6401
6402 function JSC$ASM_load_arg (ln, value)
6403 {
6404 this.type = JSC$OP_LOAD_ARG;
6405 this.linenum = ln;
6406 this.value = value;
6407 this.stack_delta = 1;
6408 this.size = 2;
6409 this.print = JSC$ASM_load_arg_print;
6410 this.bytecode = JSC$ASM_bytecode_int8;
6411 this.link = JSC$asm_link;
6412 }
6413
6414 function JSC$ASM_load_arg_print (stream)
6415 {
6416 stream.write ("\tload_arg\t" + this.value.toString () + "\n");
6417 }
6418
6419 /* store_arg */
6420
6421 function JSC$ASM_store_arg (ln, value)
6422 {
6423 this.type = JSC$OP_STORE_ARG;
6424 this.linenum = ln;
6425 this.value = value;
6426 this.stack_delta = -1;
6427 this.size = 2;
6428 this.print = JSC$ASM_store_arg_print;
6429 this.bytecode = JSC$ASM_bytecode_int8;
6430 this.link = JSC$asm_link;
6431 }
6432
6433 function JSC$ASM_store_arg_print (stream)
6434 {
6435 stream.write ("\tstore_arg\t" + this.value.toString () + "\n");
6436 }
6437
6438 /* load_local */
6439
6440 function JSC$ASM_load_local (ln, value)
6441 {
6442 this.type = JSC$OP_LOAD_LOCAL;
6443 this.linenum = ln;
6444 this.value = value;
6445 this.stack_delta = 1;
6446 this.size = 3;
6447 this.print = JSC$ASM_load_local_print;
6448 this.bytecode = JSC$ASM_bytecode_int16;
6449 this.link = JSC$asm_link;
6450 }
6451
6452 function JSC$ASM_load_local_print (stream)
6453 {
6454 stream.write ("\tload_local\t" + this.value.toString () + "\n");
6455 }
6456
6457 /* store_local */
6458
6459 function JSC$ASM_store_local (ln, value)
6460 {
6461 this.type = JSC$OP_STORE_LOCAL;
6462 this.linenum = ln;
6463 this.value = value;
6464 this.stack_delta = -1;
6465 this.size = 3;
6466 this.print = JSC$ASM_store_local_print;
6467 this.bytecode = JSC$ASM_bytecode_int16;
6468 this.link = JSC$asm_link;
6469 }
6470
6471 function JSC$ASM_store_local_print (stream)
6472 {
6473 stream.write ("\tstore_local\t" + this.value.toString () + "\n");
6474 }
6475
6476 /* load_property */
6477
6478 function JSC$ASM_load_property (ln, value)
6479 {
6480 this.type = JSC$OP_LOAD_PROPERTY;
6481 this.linenum = ln;
6482 this.value = value;
6483 this.size = 5;
6484 this.print = JSC$ASM_load_property_print;
6485 this.bytecode = JSC$ASM_bytecode_symbol;
6486 this.link = JSC$asm_link;
6487 }
6488
6489 function JSC$ASM_load_property_print (stream)
6490 {
6491 stream.write ("\tload_property\t" + this.value + "\n");
6492 }
6493
6494 /* store_property */
6495
6496 function JSC$ASM_store_property (ln, value)
6497 {
6498 this.type = JSC$OP_STORE_PROPERTY;
6499 this.linenum = ln;
6500 this.value = value;
6501 this.stack_delta = -2;
6502 this.size = 5;
6503 this.print = JSC$ASM_store_property_print;
6504 this.bytecode = JSC$ASM_bytecode_symbol;
6505 this.link = JSC$asm_link;
6506 }
6507
6508 function JSC$ASM_store_property_print (stream)
6509 {
6510 stream.write ("\tstore_property\t" + this.value + "\n");
6511 }
6512
6513 /* load_array */
6514
6515 function JSC$ASM_load_array (ln)
6516 {
6517 this.type = JSC$OP_LOAD_ARRAY;
6518 this.linenum = ln;
6519 this.stack_delta = -1;
6520 this.size = 1;
6521 this.print = JSC$ASM_load_array_print;
6522 this.link = JSC$asm_link;
6523 }
6524
6525 function JSC$ASM_load_array_print (stream)
6526 {
6527 stream.write ("\tload_array\n");
6528 }
6529
6530 /* store_array */
6531
6532 function JSC$ASM_store_array (ln)
6533 {
6534 this.type = JSC$OP_STORE_ARRAY;
6535 this.linenum = ln;
6536 this.stack_delta = -3;
6537 this.size = 1;
6538 this.print = JSC$ASM_store_array_print;
6539 this.link = JSC$asm_link;
6540 }
6541
6542 function JSC$ASM_store_array_print (stream)
6543 {
6544 stream.write ("\tstore_array\n");
6545 }
6546
6547 /* nth */
6548
6549 function JSC$ASM_nth (ln)
6550 {
6551 this.type = JSC$OP_NTH;
6552 this.linenum = ln;
6553 this.size = 1;
6554 this.print = JSC$ASM_nth_print;
6555 this.link = JSC$asm_link;
6556 }
6557
6558 function JSC$ASM_nth_print (stream)
6559 {
6560 stream.write ("\tnth\n");
6561 }
6562
6563 /* cmp_eq */
6564
6565 function JSC$ASM_cmp_eq (ln)
6566 {
6567 this.type = JSC$OP_CMP_EQ;
6568 this.linenum = ln;
6569 this.stack_delta = -1;
6570 this.size = 1;
6571 this.print = JSC$ASM_cmp_eq_print;
6572 this.link = JSC$asm_link;
6573 }
6574
6575 function JSC$ASM_cmp_eq_print (stream)
6576 {
6577 stream.write ("\tcmp_eq\n");
6578 }
6579
6580 /* cmp_ne */
6581
6582 function JSC$ASM_cmp_ne (ln)
6583 {
6584 this.type = JSC$OP_CMP_NE;
6585 this.linenum = ln;
6586 this.stack_delta = -1;
6587 this.size = 1;
6588 this.print = JSC$ASM_cmp_ne_print;
6589 this.link = JSC$asm_link;
6590 }
6591
6592 function JSC$ASM_cmp_ne_print (stream)
6593 {
6594 stream.write ("\tcmp_ne\n");
6595 }
6596
6597 /* cmp_lt */
6598
6599 function JSC$ASM_cmp_lt (ln)
6600 {
6601 this.type = JSC$OP_CMP_LT;
6602 this.linenum = ln;
6603 this.stack_delta = -1;
6604 this.size = 1;
6605 this.print = JSC$ASM_cmp_lt_print;
6606 this.link = JSC$asm_link;
6607 }
6608
6609 function JSC$ASM_cmp_lt_print (stream)
6610 {
6611 stream.write ("\tcmp_lt\n");
6612 }
6613
6614 /* cmp_gt */
6615
6616 function JSC$ASM_cmp_gt (ln)
6617 {
6618 this.type = JSC$OP_CMP_GT;
6619 this.linenum = ln;
6620 this.stack_delta = -1;
6621 this.size = 1;
6622 this.print = JSC$ASM_cmp_gt_print;
6623 this.link = JSC$asm_link;
6624 }
6625
6626 function JSC$ASM_cmp_gt_print (stream)
6627 {
6628 stream.write ("\tcmp_gt\n");
6629 }
6630
6631 /* cmp_le */
6632
6633 function JSC$ASM_cmp_le (ln)
6634 {
6635 this.type = JSC$OP_CMP_LE;
6636 this.linenum = ln;
6637 this.stack_delta = -1;
6638 this.size = 1;
6639 this.print = JSC$ASM_cmp_le_print;
6640 this.link = JSC$asm_link;
6641 }
6642
6643 function JSC$ASM_cmp_le_print (stream)
6644 {
6645 stream.write ("\tcmp_le\n");
6646 }
6647
6648 /* cmp_ge */
6649
6650 function JSC$ASM_cmp_ge (ln)
6651 {
6652 this.type = JSC$OP_CMP_GE;
6653 this.linenum = ln;
6654 this.stack_delta = -1;
6655 this.size = 1;
6656 this.print = JSC$ASM_cmp_ge_print;
6657 this.link = JSC$asm_link;
6658 }
6659
6660 function JSC$ASM_cmp_ge_print (stream)
6661 {
6662 stream.write ("\tcmp_ge\n");
6663 }
6664
6665 /* cmp_seq */
6666
6667 function JSC$ASM_cmp_seq (ln)
6668 {
6669 this.type = JSC$OP_CMP_SEQ;
6670 this.linenum = ln;
6671 this.stack_delta = -1;
6672 this.size = 1;
6673 this.print = JSC$ASM_cmp_seq_print;
6674 this.link = JSC$asm_link;
6675 }
6676
6677 function JSC$ASM_cmp_seq_print (stream)
6678 {
6679 stream.write ("\tcmp_seq\n");
6680 }
6681
6682 /* cmp_sne */
6683
6684 function JSC$ASM_cmp_sne (ln)
6685 {
6686 this.type = JSC$OP_CMP_SNE;
6687 this.linenum = ln;
6688 this.stack_delta = -1;
6689 this.size = 1;
6690 this.print = JSC$ASM_cmp_sne_print;
6691 this.link = JSC$asm_link;
6692 }
6693
6694 function JSC$ASM_cmp_sne_print (stream)
6695 {
6696 stream.write ("\tcmp_sne\n");
6697 }
6698
6699 /* sub */
6700
6701 function JSC$ASM_sub (ln)
6702 {
6703 this.type = JSC$OP_SUB;
6704 this.linenum = ln;
6705 this.stack_delta = -1;
6706 this.size = 1;
6707 this.print = JSC$ASM_sub_print;
6708 this.link = JSC$asm_link;
6709 }
6710
6711 function JSC$ASM_sub_print (stream)
6712 {
6713 stream.write ("\tsub\n");
6714 }
6715
6716 /* add */
6717
6718 function JSC$ASM_add (ln)
6719 {
6720 this.type = JSC$OP_ADD;
6721 this.linenum = ln;
6722 this.stack_delta = -1;
6723 this.size = 1;
6724 this.print = JSC$ASM_add_print;
6725 this.link = JSC$asm_link;
6726 }
6727
6728 function JSC$ASM_add_print (stream)
6729 {
6730 stream.write ("\tadd\n");
6731 }
6732
6733 /* mul */
6734
6735 function JSC$ASM_mul (ln)
6736 {
6737 this.type = JSC$OP_MUL;
6738 this.linenum = ln;
6739 this.stack_delta = -1;
6740 this.size = 1;
6741 this.print = JSC$ASM_mul_print;
6742 this.link = JSC$asm_link;
6743 }
6744
6745 function JSC$ASM_mul_print (stream)
6746 {
6747 stream.write ("\tmul\n");
6748 }
6749
6750 /* div */
6751
6752 function JSC$ASM_div (ln)
6753 {
6754 this.type = JSC$OP_DIV;
6755 this.linenum = ln;
6756 this.stack_delta = -1;
6757 this.size = 1;
6758 this.print = JSC$ASM_div_print;
6759 this.link = JSC$asm_link;
6760 }
6761
6762 function JSC$ASM_div_print (stream)
6763 {
6764 stream.write ("\tdiv\n");
6765 }
6766
6767 /* mod */
6768
6769 function JSC$ASM_mod (ln)
6770 {
6771 this.type = JSC$OP_MOD;
6772 this.linenum = ln;
6773 this.stack_delta = -1;
6774 this.size = 1;
6775 this.print = JSC$ASM_mod_print;
6776 this.link = JSC$asm_link;
6777 }
6778
6779 function JSC$ASM_mod_print (stream)
6780 {
6781 stream.write ("\tmod\n");
6782 }
6783
6784 /* neg */
6785
6786 function JSC$ASM_neg (ln)
6787 {
6788 this.type = JSC$OP_NEG;
6789 this.linenum = ln;
6790 this.size = 1;
6791 this.print = JSC$ASM_neg_print;
6792 this.link = JSC$asm_link;
6793 }
6794
6795 function JSC$ASM_neg_print (stream)
6796 {
6797 stream.write ("\tneg\n");
6798 }
6799
6800 /* and */
6801
6802 function JSC$ASM_and (ln)
6803 {
6804 this.type = JSC$OP_AND;
6805 this.linenum = ln;
6806 this.stack_delta = -1;
6807 this.size = 1;
6808 this.print = JSC$ASM_and_print;
6809 this.link = JSC$asm_link;
6810 }
6811
6812 function JSC$ASM_and_print (stream)
6813 {
6814 stream.write ("\tand\n");
6815 }
6816
6817 /* not */
6818
6819 function JSC$ASM_not (ln)
6820 {
6821 this.type = JSC$OP_NOT;
6822 this.linenum = ln;
6823 this.size = 1;
6824 this.print = JSC$ASM_not_print;
6825 this.link = JSC$asm_link;
6826 }
6827
6828 function JSC$ASM_not_print (stream)
6829 {
6830 stream.write ("\tnot\n");
6831 }
6832
6833 /* or */
6834
6835 function JSC$ASM_or (ln)
6836 {
6837 this.type = JSC$OP_OR;
6838 this.linenum = ln;
6839 this.stack_delta = -1;
6840 this.size = 1;
6841 this.print = JSC$ASM_or_print;
6842 this.link = JSC$asm_link;
6843 }
6844
6845 function JSC$ASM_or_print (stream)
6846 {
6847 stream.write ("\tor\n");
6848 }
6849
6850 /* xor */
6851
6852 function JSC$ASM_xor (ln)
6853 {
6854 this.type = JSC$OP_XOR;
6855 this.linenum = ln;
6856 this.stack_delta = -1;
6857 this.size = 1;
6858 this.print = JSC$ASM_xor_print;
6859 this.link = JSC$asm_link;
6860 }
6861
6862 function JSC$ASM_xor_print (stream)
6863 {
6864 stream.write ("\txor\n");
6865 }
6866
6867 /* shift_left */
6868
6869 function JSC$ASM_shift_left (ln)
6870 {
6871 this.type = JSC$OP_SHIFT_LEFT;
6872 this.linenum = ln;
6873 this.stack_delta = -1;
6874 this.size = 1;
6875 this.print = JSC$ASM_shift_left_print;
6876 this.link = JSC$asm_link;
6877 }
6878
6879 function JSC$ASM_shift_left_print (stream)
6880 {
6881 stream.write ("\tshift_left\n");
6882 }
6883
6884 /* shift_right */
6885
6886 function JSC$ASM_shift_right (ln)
6887 {
6888 this.type = JSC$OP_SHIFT_RIGHT;
6889 this.linenum = ln;
6890 this.stack_delta = -1;
6891 this.size = 1;
6892 this.print = JSC$ASM_shift_right_print;
6893 this.link = JSC$asm_link;
6894 }
6895
6896 function JSC$ASM_shift_right_print (stream)
6897 {
6898 stream.write ("\tshift_right\n");
6899 }
6900
6901 /* shift_rright */
6902
6903 function JSC$ASM_shift_rright (ln)
6904 {
6905 this.type = JSC$OP_SHIFT_RRIGHT;
6906 this.linenum = ln;
6907 this.stack_delta = -1;
6908 this.size = 1;
6909 this.print = JSC$ASM_shift_rright_print;
6910 this.link = JSC$asm_link;
6911 }
6912
6913 function JSC$ASM_shift_rright_print (stream)
6914 {
6915 stream.write ("\tshift_rright\n");
6916 }
6917
6918 /* iffalse */
6919
6920 function JSC$ASM_iffalse (ln, value)
6921 {
6922 this.type = JSC$OP_IFFALSE;
6923 this.linenum = ln;
6924 this.value = value;
6925 this.stack_delta = -1;
6926 this.size = 5;
6927 this.print = JSC$ASM_iffalse_print;
6928 this.bytecode = JSC$ASM_bytecode_local_jump;
6929 this.link = JSC$asm_link;
6930 }
6931
6932 function JSC$ASM_iffalse_print (stream)
6933 {
6934 stream.write ("\tiffalse\t\t" + this.value.format () + "\n");
6935 }
6936
6937 /* iftrue */
6938
6939 function JSC$ASM_iftrue (ln, value)
6940 {
6941 this.type = JSC$OP_IFTRUE;
6942 this.linenum = ln;
6943 this.value = value;
6944 this.stack_delta = -1;
6945 this.size = 5;
6946 this.print = JSC$ASM_iftrue_print;
6947 this.bytecode = JSC$ASM_bytecode_local_jump;
6948 this.link = JSC$asm_link;
6949 }
6950
6951 function JSC$ASM_iftrue_print (stream)
6952 {
6953 stream.write ("\tiftrue\t\t" + this.value.format () + "\n");
6954 }
6955
6956 /* call_method */
6957
6958 function JSC$ASM_call_method (ln, value)
6959 {
6960 this.type = JSC$OP_CALL_METHOD;
6961 this.linenum = ln;
6962 this.value = value;
6963 this.stack_delta = 1;
6964 this.size = 5;
6965 this.print = JSC$ASM_call_method_print;
6966 this.bytecode = JSC$ASM_bytecode_symbol;
6967 this.link = JSC$asm_link;
6968 }
6969
6970 function JSC$ASM_call_method_print (stream)
6971 {
6972 stream.write ("\tcall_method\t" + this.value + "\n");
6973 }
6974
6975 /* jmp */
6976
6977 function JSC$ASM_jmp (ln, value)
6978 {
6979 this.type = JSC$OP_JMP;
6980 this.linenum = ln;
6981 this.value = value;
6982 this.size = 5;
6983 this.print = JSC$ASM_jmp_print;
6984 this.bytecode = JSC$ASM_bytecode_local_jump;
6985 this.link = JSC$asm_link;
6986 }
6987
6988 function JSC$ASM_jmp_print (stream)
6989 {
6990 stream.write ("\tjmp\t\t" + this.value.format () + "\n");
6991 }
6992
6993 /* jsr */
6994
6995 function JSC$ASM_jsr (ln)
6996 {
6997 this.type = JSC$OP_JSR;
6998 this.linenum = ln;
6999 this.stack_delta = 1;
7000 this.size = 1;
7001 this.print = JSC$ASM_jsr_print;
7002 this.link = JSC$asm_link;
7003 }
7004
7005 function JSC$ASM_jsr_print (stream)
7006 {
7007 stream.write ("\tjsr\n");
7008 }
7009
7010 /* return */
7011
7012 function JSC$ASM_return (ln)
7013 {
7014 this.type = JSC$OP_RETURN;
7015 this.linenum = ln;
7016 this.size = 1;
7017 this.print = JSC$ASM_return_print;
7018 this.link = JSC$asm_link;
7019 }
7020
7021 function JSC$ASM_return_print (stream)
7022 {
7023 stream.write ("\treturn\n");
7024 }
7025
7026 /* typeof */
7027
7028 function JSC$ASM_typeof (ln)
7029 {
7030 this.type = JSC$OP_TYPEOF;
7031 this.linenum = ln;
7032 this.size = 1;
7033 this.print = JSC$ASM_typeof_print;
7034 this.link = JSC$asm_link;
7035 }
7036
7037 function JSC$ASM_typeof_print (stream)
7038 {
7039 stream.write ("\ttypeof\n");
7040 }
7041
7042 /* new */
7043
7044 function JSC$ASM_new (ln)
7045 {
7046 this.type = JSC$OP_NEW;
7047 this.linenum = ln;
7048 this.stack_delta = 1;
7049 this.size = 1;
7050 this.print = JSC$ASM_new_print;
7051 this.link = JSC$asm_link;
7052 }
7053
7054 function JSC$ASM_new_print (stream)
7055 {
7056 stream.write ("\tnew\n");
7057 }
7058
7059 /* delete_property */
7060
7061 function JSC$ASM_delete_property (ln, value)
7062 {
7063 this.type = JSC$OP_DELETE_PROPERTY;
7064 this.linenum = ln;
7065 this.value = value;
7066 this.size = 5;
7067 this.print = JSC$ASM_delete_property_print;
7068 this.bytecode = JSC$ASM_bytecode_symbol;
7069 this.link = JSC$asm_link;
7070 }
7071
7072 function JSC$ASM_delete_property_print (stream)
7073 {
7074 stream.write ("\tdelete_property\t" + this.value + "\n");
7075 }
7076
7077 /* delete_array */
7078
7079 function JSC$ASM_delete_array (ln)
7080 {
7081 this.type = JSC$OP_DELETE_ARRAY;
7082 this.linenum = ln;
7083 this.stack_delta = -1;
7084 this.size = 1;
7085 this.print = JSC$ASM_delete_array_print;
7086 this.link = JSC$asm_link;
7087 }
7088
7089 function JSC$ASM_delete_array_print (stream)
7090 {
7091 stream.write ("\tdelete_array\n");
7092 }
7093
7094 /* locals */
7095
7096 function JSC$ASM_locals (ln, value)
7097 {
7098 this.type = JSC$OP_LOCALS;
7099 this.linenum = ln;
7100 this.value = value;
7101 this.stack_delta = value;
7102 this.size = 3;
7103 this.print = JSC$ASM_locals_print;
7104 this.bytecode = JSC$ASM_bytecode_int16;
7105 this.link = JSC$asm_link;
7106 }
7107
7108 function JSC$ASM_locals_print (stream)
7109 {
7110 stream.write ("\tlocals\t\t" + this.value.toString () + "\n");
7111 }
7112
7113 /* min_args */
7114
7115 function JSC$ASM_min_args (ln, value)
7116 {
7117 this.type = JSC$OP_MIN_ARGS;
7118 this.linenum = ln;
7119 this.value = value;
7120 this.stack_delta = -1;
7121 this.size = 2;
7122 this.print = JSC$ASM_min_args_print;
7123 this.bytecode = JSC$ASM_bytecode_int8;
7124 this.link = JSC$asm_link;
7125 }
7126
7127 function JSC$ASM_min_args_print (stream)
7128 {
7129 stream.write ("\tmin_args\t" + this.value.toString () + "\n");
7130 }
7131
7132 /* load_nth_arg */
7133
7134 function JSC$ASM_load_nth_arg (ln)
7135 {
7136 this.type = JSC$OP_LOAD_NTH_ARG;
7137 this.linenum = ln;
7138 this.size = 1;
7139 this.print = JSC$ASM_load_nth_arg_print;
7140 this.link = JSC$asm_link;
7141 }
7142
7143 function JSC$ASM_load_nth_arg_print (stream)
7144 {
7145 stream.write ("\tload_nth_arg\n");
7146 }
7147
7148 /* with_push */
7149
7150 function JSC$ASM_with_push (ln)
7151 {
7152 this.type = JSC$OP_WITH_PUSH;
7153 this.linenum = ln;
7154 this.stack_delta = -1;
7155 this.size = 1;
7156 this.print = JSC$ASM_with_push_print;
7157 this.link = JSC$asm_link;
7158 }
7159
7160 function JSC$ASM_with_push_print (stream)
7161 {
7162 stream.write ("\twith_push\n");
7163 }
7164
7165 /* with_pop */
7166
7167 function JSC$ASM_with_pop (ln, value)
7168 {
7169 this.type = JSC$OP_WITH_POP;
7170 this.linenum = ln;
7171 this.value = value;
7172 this.size = 2;
7173 this.print = JSC$ASM_with_pop_print;
7174 this.bytecode = JSC$ASM_bytecode_int8;
7175 this.link = JSC$asm_link;
7176 }
7177
7178 function JSC$ASM_with_pop_print (stream)
7179 {
7180 stream.write ("\twith_pop\t" + this.value.toString () + "\n");
7181 }
7182
7183 /* try_push */
7184
7185 function JSC$ASM_try_push (ln, value)
7186 {
7187 this.type = JSC$OP_TRY_PUSH;
7188 this.linenum = ln;
7189 this.value = value;
7190 this.size = 5;
7191 this.print = JSC$ASM_try_push_print;
7192 this.bytecode = JSC$ASM_bytecode_local_jump;
7193 this.link = JSC$asm_link;
7194 }
7195
7196 function JSC$ASM_try_push_print (stream)
7197 {
7198 stream.write ("\ttry_push\t" + this.value.format () + "\n");
7199 }
7200
7201 /* try_pop */
7202
7203 function JSC$ASM_try_pop (ln, value)
7204 {
7205 this.type = JSC$OP_TRY_POP;
7206 this.linenum = ln;
7207 this.value = value;
7208 this.size = 2;
7209 this.print = JSC$ASM_try_pop_print;
7210 this.bytecode = JSC$ASM_bytecode_int8;
7211 this.link = JSC$asm_link;
7212 }
7213
7214 function JSC$ASM_try_pop_print (stream)
7215 {
7216 stream.write ("\ttry_pop\t\t" + this.value.toString () + "\n");
7217 }
7218
7219 /* throw */
7220
7221 function JSC$ASM_throw (ln)
7222 {
7223 this.type = JSC$OP_THROW;
7224 this.linenum = ln;
7225 this.stack_delta = -1;
7226 this.size = 1;
7227 this.print = JSC$ASM_throw_print;
7228 this.link = JSC$asm_link;
7229 }
7230
7231 function JSC$ASM_throw_print (stream)
7232 {
7233 stream.write ("\tthrow\n");
7234 }
7235
7236 /* iffalse_b */
7237
7238 function JSC$ASM_iffalse_b (ln, value)
7239 {
7240 this.type = JSC$OP_IFFALSE_B;
7241 this.linenum = ln;
7242 this.value = value;
7243 this.stack_delta = -1;
7244 this.size = 5;
7245 this.print = JSC$ASM_iffalse_b_print;
7246 this.bytecode = JSC$ASM_bytecode_local_jump;
7247 this.link = JSC$asm_link;
7248 }
7249
7250 function JSC$ASM_iffalse_b_print (stream)
7251 {
7252 stream.write ("\tiffalse_b\t" + this.value.format () + "\n");
7253 }
7254
7255 /* iftrue */
7256
7257 function JSC$ASM_iftrue_b (ln, value)
7258 {
7259 this.type = JSC$OP_IFTRUE_B;
7260 this.linenum = ln;
7261 this.value = value;
7262 this.stack_delta = -1;
7263 this.size = 5;
7264 this.print = JSC$ASM_iftrue_b_print;
7265 this.bytecode = JSC$ASM_bytecode_local_jump;
7266 this.link = JSC$asm_link;
7267 }
7268
7269 function JSC$ASM_iftrue_b_print (stream)
7270 {
7271 stream.write ("\tiftrue_b\t" + this.value.format () + "\n");
7272 }
7273
7274 /* add_1_i */
7275
7276 function JSC$ASM_add_1_i (ln)
7277 {
7278 this.type = JSC$OP_ADD_1_I;
7279 this.linenum = ln;
7280 this.size = 1;
7281 this.print = JSC$ASM_add_1_i_print;
7282 this.link = JSC$asm_link;
7283 }
7284
7285 function JSC$ASM_add_1_i_print (stream)
7286 {
7287 stream.write ("\tadd_1_i\n");
7288 }
7289
7290 /* add_2_i */
7291
7292 function JSC$ASM_add_2_i (ln)
7293 {
7294 this.type = JSC$OP_ADD_2_I;
7295 this.linenum = ln;
7296 this.size = 1;
7297 this.print = JSC$ASM_add_2_i_print;
7298 this.link = JSC$asm_link;
7299 }
7300
7301 function JSC$ASM_add_2_i_print (stream)
7302 {
7303 stream.write ("\tadd_2_i\n");
7304 }
7305
7306 /* load_global_w */
7307
7308 function JSC$ASM_load_global_w (ln, value)
7309 {
7310 this.type = JSC$OP_LOAD_GLOBAL_W;
7311 this.linenum = ln;
7312 this.value = value;
7313 this.stack_delta = 1;
7314 this.size = 5;
7315 this.print = JSC$ASM_load_global_w_print;
7316 this.bytecode = JSC$ASM_bytecode_symbol;
7317 this.link = JSC$asm_link;
7318 }
7319
7320 function JSC$ASM_load_global_w_print (stream)
7321 {
7322 stream.write ("\tload_global_w\t" + this.value + "\n");
7323 }
7324
7325 /* jsr_w */
7326
7327 function JSC$ASM_jsr_w (ln, value)
7328 {
7329 this.type = JSC$OP_JSR_W;
7330 this.linenum = ln;
7331 this.value = value;
7332 this.stack_delta = 1;
7333 this.size = 5;
7334 this.print = JSC$ASM_jsr_w_print;
7335 this.bytecode = JSC$ASM_bytecode_symbol;
7336 this.link = JSC$asm_link;
7337 }
7338
7339 function JSC$ASM_jsr_w_print (stream)
7340 {
7341 stream.write ("\tjsr_w\t\t" + this.value + "\n");
7342 }
7343
7344 /*
7345 * General helpers.
7346 */
7347
7348 function JSC$asm_link ()
7349 {
7350 this.next = null;
7351
7352 if (JSC$asm_tail != null)
7353 {
7354 JSC$asm_tail_prev = JSC$asm_tail;
7355 JSC$asm_tail.next = this;
7356 }
7357 else
7358 JSC$asm_head = this;
7359
7360 JSC$asm_tail = this;
7361 }
7362
7363
7364 /*
7365 * The phases of the assembler.
7366 */
7367
7368 /* This is called from the compiler initialization code. */
7369 function JSC$asm_reset ()
7370 {
7371 JSC$asm_label_count = 1;
7372 JSC$asm_head = JSC$asm_tail = JSC$asm_tail_prev = null;
7373 JSC$asm_constcount = 0;
7374 JSC$asm_constants = null;
7375 JSC$asm_known_constants = null;
7376 }
7377
7378
7379 function JSC$asm_generate ()
7380 {
7381 var i;
7382
7383 if (JSC$verbose)
7384 JSC$message ("jsc: generating assembler");
7385
7386 JSC$ns = new JSC$NameSpace ();
7387
7388 /* Functions. */
7389 for (i = 0; i < JSC$functions.length; i++)
7390 JSC$functions[i].asm ();
7391
7392 /* Global statements. */
7393 if (JSC$global_stmts.length > 0)
7394 {
7395 /* Define the `.global' symbol. */
7396 new JSC$ASM_symbol (JSC$global_stmts[0].linenum, ".global").link ();
7397
7398 /* Handle local variables. */
7399 var num_locals = JSC$count_locals_from_stmt_list (JSC$global_stmts);
7400 if (num_locals > 0)
7401 new JSC$ASM_locals (JSC$global_stmts[0].linenum, num_locals).link ();
7402
7403 /* Generate assembler. */
7404 for (i = 0; i < JSC$global_stmts.length; i++)
7405 JSC$global_stmts[i].asm ();
7406
7407 /*
7408 * Fix things so that also the global statement returns something
7409 * (this is required when we use eval() in JavaScript).
7410 */
7411 if (JSC$asm_tail_prev == null)
7412 {
7413 /* This is probably illegal, but we don't panic. */
7414 new JSC$ASM_const_undefined (0).link ();
7415 }
7416 else
7417 {
7418 /*
7419 * If the latest op is `pop', remove it. Otherwise, append
7420 * a `const_undefined'.
7421 */
7422 if (JSC$asm_tail.type == JSC$OP_POP)
7423 {
7424 JSC$asm_tail = JSC$asm_tail_prev;
7425 JSC$asm_tail.next = null;
7426 JSC$asm_tail_prev = null;
7427 }
7428 else
7429 new JSC$ASM_const_undefined (JSC$asm_tail.linenum).link ();
7430 }
7431 }
7432
7433 JSC$ns = null;
7434 }
7435
7436
7437 function JSC$asm_print (src_stream, stream)
7438 {
7439 var i;
7440 var last_ln;
7441 var annotate = src_stream ? true : false;
7442
7443 if (annotate)
7444 {
7445 stream.write ("; -*- asm -*-\n");
7446
7447 /* Set the prev properties. */
7448 var prev = null;
7449 for (i = JSC$asm_head; i != null; prev = i, i = i.next)
7450 i.prev = prev;
7451
7452 /*
7453 * Fix the label line numbers to be the same that the next
7454 * assembler operand has.
7455 */
7456 last_ln = 0;
7457 for (i = JSC$asm_tail; i != null; i = i.prev)
7458 {
7459 if (i.type == JSC$ASM_LABEL)
7460 i.linenum = last_ln;
7461 else if (typeof i.linenum != "undefined")
7462 last_ln = i.linenum;
7463 }
7464 }
7465
7466 last_ln = 0;
7467 for (i = JSC$asm_head; i != null; i = i.next)
7468 {
7469 if (typeof i.linenum == "undefined")
7470 {
7471 if (annotate)
7472 stream.write ("; undefined linenum\n");
7473 }
7474 else
7475 while (annotate && i.linenum > last_ln)
7476 {
7477 var line = src_stream.readln ();
7478 stream.write ("; " + line + "\n");
7479 last_ln++;
7480 }
7481
7482 i.print (stream);
7483 }
7484 }
7485
7486
7487 function JSC$asm_is_load_op (op)
7488 {
7489 return (op.type == JSC$OP_LOAD_GLOBAL
7490 || op.type == JSC$OP_LOAD_ARG
7491 || op.type == JSC$OP_LOAD_LOCAL);
7492 }
7493
7494
7495 function JSC$asm_is_store_op (op)
7496 {
7497 return (op.type == JSC$OP_STORE_GLOBAL
7498 || op.type == JSC$OP_STORE_ARG
7499 || op.type == JSC$OP_STORE_LOCAL);
7500 }
7501
7502
7503 function JSC$asm_is_local_jump (op)
7504 {
7505 return (op.type == JSC$OP_JMP
7506 || op.type == JSC$OP_IFFALSE
7507 || op.type == JSC$OP_IFTRUE
7508 || op.type == JSC$OP_IFFALSE_B
7509 || op.type == JSC$OP_IFTRUE_B
7510 || op.type == JSC$OP_TRY_PUSH);
7511 }
7512
7513
7514 function JSC$asm_is_const_op (op)
7515 {
7516 return (JSC$OP_CONST <= op.type && op.type <= JSC$OP_CONST_I3);
7517 }
7518
7519
7520 function JSC$asm_lookup_next_op (item)
7521 {
7522 while (item != null &&
7523 (item.type == JSC$ASM_LABEL || item.type == JSC$ASM_SYMBOL))
7524 item = item.next;
7525
7526 return item;
7527 }
7528
7529
7530 function JSC$asm_optimize (flags)
7531 {
7532 var item;
7533
7534 /* Simple peephole optimization. */
7535 if ((flags & JSC$FLAG_OPTIMIZE_PEEPHOLE) != 0)
7536 {
7537 if (JSC$verbose)
7538 JSC$message ("jsc: optimize: peephole");
7539
7540 for (item = JSC$asm_head; item != null; item = item.next)
7541 {
7542 /*
7543 * Optimization for dup ... pop cases where pop removes the
7544 * item duplicated by dup.
7545 */
7546 if (item.next != null && item.next.type == JSC$OP_DUP)
7547 {
7548 var balance = 2;
7549 var found = false;
7550 var i1;
7551
7552 for (i1 = item.next.next;
7553 i1 != null && i1.next != null;
7554 i1 = i1.next)
7555 {
7556 var i2 = i1.next;
7557
7558 /*
7559 * The lookup ends on branches, and on dup, throw,
7560 * and try_pop operands. We optimize on a basic
7561 * block and we match the closest dup-pop pairs.
7562 */
7563 if (JSC$asm_is_local_jump (i1)
7564 || i1.type == JSC$OP_JSR
7565 || i1.type == JSC$OP_NEW
7566 || i1.type == JSC$OP_CALL_METHOD
7567 || i1.type == JSC$OP_RETURN
7568 || i1.type == JSC$ASM_SYMBOL
7569 || i1.type == JSC$ASM_LABEL
7570 || i1.type == JSC$OP_DUP
7571 || i1.type == JSC$OP_TRY_POP
7572 || i1.type == JSC$OP_THROW)
7573 break;
7574
7575 if (i1.stack_delta)
7576 {
7577 balance += i1.stack_delta;
7578 if (balance <= 0)
7579 /* Going to negative. Stop here. */
7580 break;
7581 }
7582
7583 if (i2.type == JSC$OP_POP && balance == 1)
7584 {
7585 /* Found a matching pop. */
7586 found = true;
7587 i1.next = i2.next;
7588 break;
7589 }
7590 }
7591
7592 if (found)
7593 {
7594 /* The dup can be removed. */
7595 item.next = item.next.next;
7596 }
7597 }
7598
7599 /* Two instruction optimization (starting from item.next). */
7600 if (item.next != null && item.next.next != null)
7601 {
7602 var i1 = item.next;
7603 var i2 = i1.next;
7604
7605 if (i1.type == JSC$OP_APOP
7606 && i2.type == JSC$OP_POP)
7607 {
7608 /*
7609 * i1: apop n
7610 * i2: pop -> pop_n n + 1
7611 */
7612 var i = new JSC$ASM_pop_n (i1.linenum, i1.value + 1);
7613 item.next = i;
7614 i.next = i2.next;
7615 }
7616 }
7617 if (item.next != null && item.next.next != null)
7618 {
7619 var i1 = item.next;
7620 var i2 = i1.next;
7621
7622 if (i1.type == JSC$OP_CONST_TRUE
7623 && (i2.type == JSC$OP_IFFALSE
7624 || i2.type == JSC$OP_IFFALSE_B))
7625 {
7626 /*
7627 * i1: const_true
7628 * i2: iffalse{,_b} .LX => ---
7629 */
7630 item.next = i2.next;
7631 }
7632 }
7633 if (item.next != null && item.next.next != null)
7634 {
7635 var i1 = item.next;
7636 var i2 = i1.next;
7637
7638 if (i1.type == JSC$OP_CONST_FALSE
7639 && (i2.type == JSC$OP_IFTRUE
7640 || i2.type == JSC$OP_IFTRUE_B))
7641 {
7642 /*
7643 * i1: const_false
7644 * i2: iftrue{,_b} .LX => ---
7645 */
7646 item.next = i2.next;
7647 }
7648 }
7649 if (item.next != null && item.next.next != null)
7650 {
7651 var i1 = item.next;
7652 var i2 = i1.next;
7653
7654 if ((i1.type == JSC$OP_CONST_FALSE
7655 && (i2.type == JSC$OP_IFFALSE
7656 || i2.type == JSC$OP_IFFALSE_B))
7657 || (i1.type == JSC$OP_CONST_TRUE
7658 && (i2.type == JSC$OP_IFTRUE
7659 || i2.type == JSC$OP_IFTRUE_B)))
7660 {
7661 /*
7662 * i1: const_false
7663 * i2: iffalse{,_b} .LX => jmp .LX
7664 *
7665 * i1: const_true
7666 * i2: iftrue{,_b} .LX => jmp .LX
7667 */
7668 var i = new JSC$ASM_jmp (i1.linenum, i2.value);
7669 item.next = i;
7670 i.next = i2.next;
7671 }
7672 }
7673 }
7674 }
7675
7676 /* Jumps to jumps. */
7677 if ((flags & JSC$FLAG_OPTIMIZE_JUMPS) != 0)
7678 {
7679 if (JSC$verbose)
7680 JSC$message ("jsc: optimize: jumps to jumps");
7681 for (item = JSC$asm_head; item != null; item = item.next)
7682 if (JSC$asm_is_local_jump (item))
7683 {
7684 var i2;
7685
7686 /* Operand's value is a label */
7687 i2 = JSC$asm_lookup_next_op (item.value);
7688
7689 if (i2 != null && i2.type == JSC$OP_JMP)
7690 /* Ok, we can jump there directly. */
7691 item.value = i2.value;
7692 }
7693 }
7694
7695 if ((flags & JSC$FLAG_OPTIMIZE_HEAVY) != 0)
7696 JSC$optimize_heavy ();
7697
7698 /*
7699 * Optimizations for the size of the generated byte-code. It isn't
7700 * probably worth of doing these optimization for interactive
7701 * scripts since these won't affect the speed of the execution.
7702 * However, these optimizations make the byte-code files smaller so
7703 * these are nice for batch-compiled files.
7704 */
7705 if ((flags & JSC$FLAG_OPTIMIZE_BC_SIZE) != 0)
7706 {
7707 var delta = true;
7708
7709 while (delta)
7710 {
7711 delta = false;
7712
7713 /* Remove un-referenced labels. */
7714
7715 if (JSC$verbose)
7716 JSC$message ("jsc: optimize: removing un-referenced labels");
7717
7718 /* First, make all labels unreferenced. */
7719 for (item = JSC$asm_head; item != null; item = item.next)
7720 if (item.type == JSC$ASM_LABEL)
7721 item.referenced = false;
7722
7723 /* Second, mark all referenced labels. */
7724 for (item = JSC$asm_head; item != null; item = item.next)
7725 if (JSC$asm_is_local_jump (item))
7726 item.value.referenced = true;
7727
7728 /* Third, remove all un-referenced labels. */
7729 for (item = JSC$asm_head; item != null; item = item.next)
7730 while (item.next != null && item.next.type == JSC$ASM_LABEL
7731 && !item.next.referenced
7732 && item.next.next != null)
7733 {
7734 delta = true;
7735 item.next = item.next.next;
7736 }
7737
7738 /* Dead code elimination. */
7739 if (JSC$verbose)
7740 JSC$message ("jsc: optimize: dead code elimination");
7741 for (item = JSC$asm_head; item != null; item = item.next)
7742 if (item.type == JSC$OP_RETURN || item.type == JSC$OP_JMP)
7743 while (item.next != null && item.next.type != JSC$ASM_SYMBOL
7744 && item.next.type != JSC$ASM_LABEL)
7745 {
7746 delta = true;
7747 item.next = item.next.next;
7748 }
7749
7750
7751 /* Simple peephole optimization. */
7752 if (JSC$verbose)
7753 JSC$message ("jsc: optimize: peephole");
7754 for (item = JSC$asm_head; item != null; item = item.next)
7755 {
7756 /* Two instruction optimization (starting from item.next). */
7757 if (item.next != null && item.next.next != null)
7758 {
7759 var i1 = item.next;
7760 var i2 = i1.next;
7761
7762 if (i1.type == JSC$OP_JMP
7763 && i2.type == JSC$ASM_LABEL
7764 && i1.value == i2)
7765 {
7766 /*
7767 * i1: jmp .LX
7768 * i2: .LX => .LX
7769 */
7770 item.next = i2;
7771 delta = true;
7772 }
7773 }
7774 }
7775 }
7776 }
7777 }
7778
7779
7780 function JSC$optimize_heavy ()
7781 {
7782 if (JSC$verbose)
7783 JSC$message ("jsc: optimize: liveness analyzing");
7784
7785 /* First, set the prev pointers and zero usage flags. */
7786 var item, prev = null;
7787
7788 for (item = JSC$asm_head; item != null; prev = item, item = item.next)
7789 {
7790 item.prev = prev;
7791 item.live_args = 0;
7792 item.live_locals = 0;
7793 item.live_used = false;
7794 }
7795
7796 /* For each function. */
7797 var ftail, fhead;
7798 for (ftail = JSC$asm_tail; ftail != null; ftail = fhead.prev)
7799 {
7800 var change = true;
7801
7802 /* While there is change in the liveness. */
7803 while (change)
7804 {
7805 change = false;
7806
7807 for (fhead = ftail;
7808 fhead.type != JSC$ASM_SYMBOL;
7809 fhead = fhead.prev)
7810 {
7811 var floc, farg;
7812
7813 if (fhead.next != null)
7814 {
7815 floc = fhead.next.live_locals;
7816 farg = fhead.next.live_args;
7817 }
7818 else
7819 floc = farg = 0;
7820
7821 if (fhead.type == JSC$OP_LOAD_LOCAL && fhead.value < 32)
7822 floc |= (1 << fhead.value);
7823
7824 if (fhead.type == JSC$OP_STORE_LOCAL && fhead.value < 32)
7825 floc &= ~(1 << fhead.value);
7826
7827 if (fhead.type == JSC$OP_LOAD_ARG && fhead.value < 32)
7828 farg |= (1 << fhead.value);
7829
7830 if (fhead.type == JSC$OP_STORE_ARG && fhead.value < 32)
7831 farg &= ~(1 << fhead.value);
7832
7833 if (JSC$asm_is_local_jump (fhead))
7834 {
7835 floc |= fhead.value.live_locals;
7836 fhead.value.live_used = true;
7837 }
7838
7839 if (fhead.live_used && (fhead.live_locals != floc
7840 || fhead.live_args != farg))
7841 change = true;
7842
7843 fhead.live_used = false;
7844 fhead.live_locals = floc;
7845 fhead.live_args = farg;
7846 }
7847 }
7848 }
7849
7850 /*
7851 * When we have the liveness analyzing performed, we can do some
7852 * fancy optimizations.
7853 */
7854
7855 if (JSC$verbose)
7856 JSC$message ("jsc: optimize: peephole");
7857
7858 for (item = JSC$asm_head; item != null; item = item.next)
7859 {
7860 /* Three instruction optimization. */
7861 if (item.next != null && item.next.next != null
7862 && item.next.next.next != null)
7863 {
7864 var i1 = item.next;
7865 var i2 = i1.next;
7866 var i3 = i2.next;
7867
7868 if (i1.type == JSC$OP_STORE_LOCAL
7869 && i2.type == JSC$OP_LOAD_LOCAL
7870 && i1.value == i2.value
7871 && (i3.live_locals & (1 << i1.value)) == 0)
7872 {
7873 /*
7874 * i1: store_local n
7875 * i2: load_local n
7876 * i3: nnn (n not live) => nnn
7877 */
7878
7879 item.next = i3;
7880 }
7881 }
7882 }
7883 }
7884
7885
7886 function JSC$asm_finalize ()
7887 {
7888 var item;
7889 var offset = 0;
7890
7891 for (item = JSC$asm_head; item != null; item = item.next)
7892 {
7893 item.offset = offset;
7894 offset += item.size;
7895 }
7896 }
7897
7898
7899 function JSC$ConstantReg ()
7900 {
7901 }
7902
7903 function JSC$asm_genconstant (val)
7904 {
7905 if (JSC$asm_known_constants == null)
7906 JSC$asm_known_constants = new JSC$ConstantReg ();
7907
7908 /* Lookup <val> from a list of known constants. */
7909 var id = JSC$asm_known_constants[val];
7910 if (typeof id == "number")
7911 return id;
7912
7913 /* This is a new constant. */
7914 JSC$asm_constants.append (val);
7915 JSC$asm_known_constants[val] = JSC$asm_constcount;
7916
7917 return JSC$asm_constcount++;
7918 }
7919
7920 function JSC$asm_bytecode ()
7921 {
7922 var item;
7923 var symtab = new String ("");
7924 var nsymtab_entries = 0;
7925 var code = new String ("");
7926 var debug = new String ("");
7927 var debug_last_linenum = 0;
7928
7929 if (JSC$verbose)
7930 JSC$message ("jsc: generating byte-code");
7931
7932 if (JSC$generate_debug_info)
7933 /* Source file name. */
7934 debug.append (String.pack ("CN", JSC$DEBUG_FILENAME, JSC$filename.length)
7935 + JSC$filename);
7936
7937 JSC$asm_constants = new String ("");
7938
7939 for (item = JSC$asm_head; item != null; item = item.next)
7940 {
7941 if (item.type == JSC$ASM_SYMBOL)
7942 {
7943 symtab.append (item.value + String.pack ("CN", 0, item.offset));
7944 nsymtab_entries++;
7945 }
7946 else if (item.type == JSC$ASM_LABEL)
7947 ;
7948 else
7949 {
7950 /* Real assembler operands. */
7951
7952 if (JSC$generate_debug_info)
7953 if (item.linenum != debug_last_linenum)
7954 {
7955 debug.append (String.pack ("CNN", JSC$DEBUG_LINENUMBER,
7956 item.offset + item.size,
7957 item.linenum));
7958 debug_last_linenum = item.linenum;
7959 }
7960
7961 if (item.size == 1)
7962 /* We handle these. */
7963 code.append (String.pack ("C", item.type));
7964 else
7965 {
7966 /*
7967 * All operands which take an argument, have a method to create
7968 * the byte code entry for their argument.
7969 */
7970 code.append (String.pack ("C", item.type) + item.bytecode ());
7971 }
7972 }
7973 }
7974
7975 symtab = String.pack ("N", nsymtab_entries) + symtab;
7976
7977 if (JSC$verbose)
7978 {
7979 var msg = ("jsc: code=" + code.length.toString ()
7980 + ", constants=" + JSC$asm_constants.length.toString ()
7981 + ", symtab=" + symtab.length.toString ());
7982
7983 if (JSC$generate_debug_info)
7984 msg += ", debug=" + debug.length.toString ();
7985
7986 msg += (", headers="
7987 + (32 + (JSC$generate_debug_info ? 8 : 0)).toString ()
7988 + ", total="
7989 + (code.length + JSC$asm_constants.length + symtab.length
7990 + debug.length + 32
7991 + (JSC$generate_debug_info ? 8 : 0)).toString ());
7992 JSC$message (msg);
7993 }
7994
7995 return (String.pack ("NN", JSC$BC_MAGIC,
7996 3 + (JSC$generate_debug_info ? 1 : 0))
7997 + String.pack ("NN", JSC$BC_SECT_CODE, code.length) + code
7998
7999 + String.pack ("NN", JSC$BC_SECT_CONSTANTS,
8000 JSC$asm_constants.length)
8001 + JSC$asm_constants
8002
8003 + String.pack ("NN", JSC$BC_SECT_SYMTAB, symtab.length) + symtab
8004
8005 + (JSC$generate_debug_info
8006 ? String.pack ("NN", JSC$BC_SECT_DEBUG, debug.length) + debug
8007 : ""));
8008 }
8009
8010 \f
8011 /*
8012 Local variables:
8013 mode: c
8014 End:
8015 */
8016 /*
8017 * Public entry points to the JavaScript compiler.
8018 * Copyright (c) 1998 New Generation Software (NGS) Oy
8019 *
8020 * Author: Markku Rossi <mtr@ngs.fi>
8021 */
8022
8023 /*
8024 * This library is free software; you can redistribute it and/or
8025 * modify it under the terms of the GNU Library General Public
8026 * License as published by the Free Software Foundation; either
8027 * version 2 of the License, or (at your option) any later version.
8028 *
8029 * This library is distributed in the hope that it will be useful,
8030 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8031 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
8032 * Library General Public License for more details.
8033 *
8034 * You should have received a copy of the GNU Library General Public
8035 * License along with this library; if not, write to the Free
8036 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
8037 * MA 02111-1307, USA
8038 */
8039
8040 /*
8041 * $Source: /cygdrive/c/RCVS/CVS/ReactOS/reactos/lib/kjs/jsc/compiler.js,v $
8042 * $Id$
8043 */
8044
8045 /*
8046 * Definitions.
8047 */
8048
8049 JSC$FLAG_VERBOSE = 0x00000001;
8050 JSC$FLAG_ANNOTATE_ASSEMBLER = 0x00000002;
8051 JSC$FLAG_GENERATE_DEBUG_INFO = 0x00000004;
8052 JSC$FLAG_GENERATE_EXECUTABLE_BC_FILES = 0x00000008;
8053
8054 JSC$FLAG_OPTIMIZE_PEEPHOLE = 0x00000020;
8055 JSC$FLAG_OPTIMIZE_JUMPS = 0x00000040;
8056 JSC$FLAG_OPTIMIZE_BC_SIZE = 0x00000080;
8057 JSC$FLAG_OPTIMIZE_HEAVY = 0x00000100;
8058
8059 JSC$FLAG_OPTIMIZE_MASK = 0x0000fff0;
8060
8061 JSC$FLAG_WARN_UNUSED_ARGUMENT = 0x00010000;
8062 JSC$FLAG_WARN_UNUSED_VARIABLE = 0x00020000;
8063 JSC$FLAG_WARN_SHADOW = 0x00040000;
8064 JSC$FLAG_WARN_WITH_CLOBBER = 0x00080000;
8065 JSC$FLAG_WARN_MISSING_SEMICOLON = 0x00100000;
8066 JSC$FLAG_WARN_STRICT_ECMA = 0x00200000;
8067 JSC$FLAG_WARN_DEPRECATED = 0x00400000;
8068
8069 JSC$FLAG_WARN_MASK = 0xffff0000;
8070
8071 /*
8072 * Global interfaces to the compiler.
8073 */
8074
8075 function JSC$compile_file (fname, flags, asm_file, bc_file)
8076 {
8077 var stream = new JSC$StreamFile (fname);
8078 return JSC$compile_stream (stream, flags, asm_file, bc_file);
8079 }
8080
8081
8082 function JSC$compile_string (str, flags, asm_file, bc_file)
8083 {
8084 var stream = new JSC$StreamString (str);
8085 return JSC$compile_stream (stream, flags, asm_file, bc_file);
8086 }
8087
8088
8089 function JSC$compiler_reset ()
8090 {
8091 /* Reset compiler to a known initial state. */
8092 JSC$parser_reset ();
8093 JSC$gram_reset ();
8094 JSC$asm_reset ();
8095 }
8096
8097
8098 function JSC$compile_stream (stream, flags, asm_file, bc_file)
8099 {
8100 var result = false;
8101
8102 JSC$compiler_reset ();
8103
8104 if (stream.open ())
8105 {
8106 try
8107 {
8108 JSC$verbose = ((flags & JSC$FLAG_VERBOSE) != 0);
8109 JSC$generate_debug_info
8110 = ((flags & JSC$FLAG_GENERATE_DEBUG_INFO) != 0);
8111
8112 JSC$warn_unused_argument
8113 = ((flags & JSC$FLAG_WARN_UNUSED_ARGUMENT) != 0);
8114 JSC$warn_unused_variable
8115 = ((flags & JSC$FLAG_WARN_UNUSED_VARIABLE) != 0);
8116 JSC$warn_shadow
8117 = ((flags & JSC$FLAG_WARN_SHADOW) != 0);
8118 JSC$warn_with_clobber
8119 = ((flags & JSC$FLAG_WARN_WITH_CLOBBER) != 0);
8120 JSC$warn_missing_semicolon
8121 = ((flags & JSC$FLAG_WARN_MISSING_SEMICOLON) != 0);
8122 JSC$warn_strict_ecma
8123 = ((flags & JSC$FLAG_WARN_STRICT_ECMA) != 0);
8124 JSC$warn_deprecated
8125 = ((flags & JSC$FLAG_WARN_DEPRECATED) != 0);
8126
8127 /* Compilation and assembler generation time optimizations. */
8128 JSC$optimize_constant_folding = true;
8129 JSC$optimize_type = true;
8130
8131 JSC$parser_parse (stream);
8132
8133 /* Assembler. */
8134 JSC$asm_generate ();
8135
8136 /*
8137 * We don't need the syntax tree anymore. Free it and save
8138 * some memory.
8139 */
8140 JSC$parser_reset ();
8141
8142 /* Optimize if requested. */
8143 if ((flags & JSC$FLAG_OPTIMIZE_MASK) != 0)
8144 JSC$asm_optimize (flags);
8145
8146 if (typeof asm_file == "string")
8147 {
8148 var asm_stream = new File (asm_file);
8149 var src_stream = false;
8150
8151 if (asm_stream.open ("w"))
8152 {
8153 if ((flags & JSC$FLAG_ANNOTATE_ASSEMBLER) != 0)
8154 if (stream.rewind ())
8155 src_stream = stream;
8156
8157 JSC$asm_print (src_stream, asm_stream);
8158 asm_stream.close ();
8159 }
8160 else
8161 JSC$message ("jsc: couldn't create asm output file \""
8162 + asm_file + "\": "
8163 + System.strerror (System.errno));
8164 }
8165
8166 JSC$asm_finalize ();
8167
8168 result = JSC$asm_bytecode ();
8169
8170 /* Remove all intermediate results from the memory. */
8171 JSC$compiler_reset ();
8172
8173 if (typeof bc_file == "string")
8174 {
8175 var ostream = new File (bc_file);
8176 if (ostream.open ("w"))
8177 {
8178 ostream.write (result);
8179 ostream.close ();
8180
8181 if ((flags & JSC$FLAG_GENERATE_EXECUTABLE_BC_FILES) != 0)
8182 {
8183 /* Add execute permissions to the output file. */
8184 var st = File.stat (bc_file);
8185 if (st)
8186 {
8187 if (!File.chmod (bc_file, st[2] | 0111))
8188 JSC$message ("jsc: couldn't add execute "
8189 + "permissions to bc file \""
8190 + bc_file + "\": "
8191 + System.strerror (System.errno));
8192 }
8193 else
8194 JSC$message ("jsc: couldn't stat bc file \"" + bc_file
8195 + "\": "
8196 + System.strerror (System.errno));
8197 }
8198 }
8199 else
8200 JSC$message ("jsc: couldn't create bc file \"" + bc_file
8201 + "\": " + System.strerror (System.errno));
8202 }
8203 }
8204 finally
8205 {
8206 stream.close ();
8207 }
8208 }
8209 else
8210 error ("jsc: couldn't open input stream \"" + stream.name + "\": "
8211 + stream.error);
8212
8213 return result;
8214 }
8215
8216 \f
8217 /*
8218 Local variables:
8219 mode: c
8220 End:
8221 */