migrate substitution keywords to SVN
[reactos.git] / reactos / lib / kjs / jsc / gram.js
1 /*
2 * Grammar components.
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/gram.js,v $
27 * $Id$
28 */
29
30 /* General helpers. */
31
32 function JSC$gram_reset ()
33 {
34 JSC$label_count = 1;
35 JSC$cont_break = new JSC$ContBreak ();
36 }
37
38
39 function JSC$alloc_label (num_labels)
40 {
41 JSC$label_count += num_labels;
42
43 return JSC$label_count - num_labels;
44 }
45
46
47 function JSC$format_label (num)
48 {
49 return ".L" + num.toString ();
50 }
51
52
53 function JSC$count_locals_from_stmt_list (list)
54 {
55 var i;
56
57 /* First, count how many variables we need at the toplevel. */
58 var lcount = 0;
59 for (i = 0; i < list.length; i++)
60 lcount += list[i].count_locals (false);
61
62 /* Second, count the maximum amount needed by the nested blocks. */
63 var rmax = 0;
64 for (i = 0; i < list.length; i++)
65 {
66 var rc = list[i].count_locals (true);
67 if (rc > rmax)
68 rmax = rc;
69 }
70
71 return lcount + rmax;
72 }
73
74 /*
75 * The handling of the `continue' and `break' labels for looping
76 * constructs. The variable `JSC$cont_break' holds an instance of
77 * JSC$ContBreak class. The instance contains a valid chain of
78 * looping constructs and the currently active with and try testing
79 * levels. The actual `continue', `break', and `return' statements
80 * investigate the chain and generate appropriate `with_pop' and
81 * `try_pop' operands.
82 *
83 * If the instance variable `inswitch' is true, the continue statement
84 * is inside a switch statement. In this case, the continue statement
85 * must pop one item from the stack. That item is the value of the
86 * case expression.
87 */
88
89 function JSC$ContBreakFrame (loop_break, loop_continue, inswitch, label, next)
90 {
91 this.loop_break = loop_break;
92 this.loop_continue = loop_continue;
93 this.inswitch = inswitch;
94 this.label = label;
95 this.next = next;
96
97 this.with_nesting = 0;
98 this.try_nesting = 0;
99 }
100
101
102 function JSC$ContBreak ()
103 {
104 this.top = new JSC$ContBreakFrame (null, null, false, null);
105 }
106
107 new JSC$ContBreak ();
108
109 function JSC$ContBreak$push (loop_break, loop_continue, inswitch, label)
110 {
111 this.top = new JSC$ContBreakFrame (loop_break, loop_continue, inswitch,
112 label, this.top);
113 }
114 JSC$ContBreak.prototype.push = JSC$ContBreak$push;
115
116 function JSC$ContBreak$pop ()
117 {
118 if (this.top == null)
119 error ("jsc: internal error: continue-break stack underflow");
120
121 this.top = this.top.next;
122 }
123 JSC$ContBreak.prototype.pop = JSC$ContBreak$pop;
124
125 /*
126 * Count the currently active `try' nesting that should be removed on
127 * `return' statement.
128 */
129 function JSC$ContBreak$try_return_nesting ()
130 {
131 var f;
132 var count = 0;
133
134 for (f = this.top; f; f = f.next)
135 count += f.try_nesting;
136
137 return count;
138 }
139 JSC$ContBreak.prototype.try_return_nesting = JSC$ContBreak$try_return_nesting;
140
141 /*
142 * Count currently active `with' nesting that should be removed on
143 * `continue' or `break' statement.
144 */
145 function JSC$ContBreak$count_with_nesting (label)
146 {
147 var f;
148 var count = 0;
149
150 for (f = this.top; f; f = f.next)
151 {
152 count += f.with_nesting;
153 if (label)
154 {
155 if (f.label == label)
156 break;
157 }
158 else
159 if (f.loop_continue)
160 break;
161 }
162 return count;
163 }
164 JSC$ContBreak.prototype.count_with_nesting = JSC$ContBreak$count_with_nesting;
165
166 /*
167 * Count the currently active `try' nesting that should be removed on
168 * `continue' or `break' statement.
169 */
170 function JSC$ContBreak$count_try_nesting (label)
171 {
172 var f;
173 var count = 0;
174
175 for (f = this.top; f; f = f.next)
176 {
177 count += f.try_nesting;
178 if (label)
179 {
180 if (f.label == label)
181 break;
182 }
183 else
184 if (f.loop_continue)
185 break;
186 }
187 return count;
188 }
189 JSC$ContBreak.prototype.count_try_nesting = JSC$ContBreak$count_try_nesting;
190
191 function JSC$ContBreak$count_switch_nesting (label)
192 {
193 var f;
194 var count = 0;
195
196 for (f = this.top; f; f = f.next)
197 {
198 if (f.inswitch)
199 count++;
200 if (label)
201 {
202 if (f.label == label)
203 break;
204 }
205 else
206 if (f.loop_continue)
207 break;
208 }
209 return count;
210 }
211 JSC$ContBreak.prototype.count_switch_nesting
212 = JSC$ContBreak$count_switch_nesting;
213
214 function JSC$ContBreak$get_continue (label)
215 {
216 var f;
217
218 for (f = this.top; f; f = f.next)
219 if (label)
220 {
221 if (f.label == label)
222 return f.loop_continue;
223 }
224 else
225 if (f.loop_continue)
226 return f.loop_continue;
227
228 return null;
229 }
230 JSC$ContBreak.prototype.get_continue = JSC$ContBreak$get_continue;
231
232 function JSC$ContBreak$get_break (label)
233 {
234 var f;
235
236 for (f = this.top; f; f = f.next)
237 if (label)
238 {
239 if (f.label == label)
240 return f.loop_break;
241 }
242 else
243 if (f.loop_break)
244 return f.loop_break;
245
246 return null;
247 }
248 JSC$ContBreak.prototype.get_break = JSC$ContBreak$get_break;
249
250 function JSC$ContBreak$is_unique_label (label)
251 {
252 var f;
253
254 for (f = this.top; f; f = f.next)
255 if (f.label == label)
256 return false;
257
258 return true;
259 }
260 JSC$ContBreak.prototype.is_unique_label = JSC$ContBreak$is_unique_label;
261
262 JSC$cont_break = null;
263
264
265 /* Function declaration. */
266
267 function JSC$function_declaration (ln, lbrace_ln, name, name_given, args,
268 block, use_arguments_prop)
269 {
270 this.linenum = ln;
271 this.lbrace_linenum = lbrace_ln;
272 this.name = name;
273 this.name_given = name_given;
274 this.args = args;
275 this.block = block;
276 this.use_arguments_prop = use_arguments_prop;
277 this.asm = JSC$function_declaration_asm;
278 }
279
280 function JSC$function_declaration_asm ()
281 {
282 var i, a;
283
284 /* Define arguments. */
285 JSC$ns.push_frame ();
286
287 for (i = 0, a = 2; i < this.args.length; i++, a++)
288 JSC$ns.define_symbol (this.args[i], JSC$SCOPE_ARG, a, this.linenum);
289
290 /* Define the function name to be a global symbol. */
291 new JSC$ASM_symbol (this.linenum, this.name).link ();
292
293 /* Check that function gets the required amount of arguments. */
294 new JSC$ASM_load_arg (this.lbrace_linenum, 1).link ();
295 new JSC$ASM_add_2_i (this.lbrace_linenum).link ();
296 new JSC$ASM_min_args (this.lbrace_linenum, this.args.length + 2).link ();
297
298 /* Count how many local variables we need. */
299 var num_locals = JSC$count_locals_from_stmt_list (this.block);
300
301 /* Is the `arguments' property of function instance used? */
302 if (this.use_arguments_prop)
303 num_locals++;
304
305 if (num_locals > 0)
306 {
307 new JSC$ASM_locals (this.lbrace_linenum, num_locals).link ();
308 if (this.use_arguments_prop)
309 {
310 /*
311 * Create an array for the arguments array and store it to
312 * the first local variable.
313 */
314 var ln = this.lbrace_linenum;
315 var locn = JSC$ns.alloc_local ();
316 JSC$ns.define_symbol ("arguments", JSC$SCOPE_LOCAL, locn, ln);
317
318 new JSC$ASM_const_i0 (ln).link ();
319 new JSC$ASM_load_global (ln, "Array").link ();
320 new JSC$ASM_new (ln).link ();
321 new JSC$ASM_swap (ln).link ();
322 new JSC$ASM_apop (ln, 2).link ();
323 new JSC$ASM_store_local (ln, locn).link ();
324
325 /* Push individual argumens to the array. */
326
327 /* Init the loop counter. */
328 new JSC$ASM_const_i0 (ln).link ();
329
330 var l_loop = new JSC$ASM_label ();
331 var l_out = new JSC$ASM_label ();
332
333 l_loop.link ();
334
335 /* Check if we'r done. */
336 new JSC$ASM_dup (ln).link ();
337 new JSC$ASM_load_arg (ln, 1).link ();
338 new JSC$ASM_cmp_ge (ln).link ();
339 new JSC$ASM_iftrue_b (ln, l_out).link ();
340
341 /* Load the nth argument to the top of the stack. */
342 new JSC$ASM_dup (ln).link ();
343 new JSC$ASM_add_2_i (ln).link ();
344 new JSC$ASM_load_nth_arg (ln).link ();
345
346 /* Push it to the array. */
347 new JSC$ASM_const_i1 (ln).link ();
348 new JSC$ASM_load_local (ln, locn).link ();
349 new JSC$ASM_call_method (ln, "push").link ();
350 new JSC$ASM_pop_n (ln, 4).link ();
351
352 /* Increment loop counter and continue. */
353 new JSC$ASM_add_1_i (ln).link ();
354 new JSC$ASM_jmp (ln, l_loop).link ();
355
356 /* We'r done. */
357 l_out.link ();
358
359 /* Pop the loop counter. */
360 new JSC$ASM_pop (ln).link ();
361 }
362 }
363
364 /* Assembler for our body. */
365 for (i = 0; i < this.block.length; i++)
366 this.block[i].asm ();
367
368 /*
369 * Every function must return something. We could check if all
370 * control flows in this function ends to a return, but that would
371 * bee too hard... Just append a return const_undefined. The optimizer
372 * will remove it if it is not needed.
373 */
374 var ln;
375 if (this.block.length > 0)
376 ln = this.block[this.block.length - 1].linenum;
377 else
378 ln = this.linenum;
379
380 new JSC$ASM_const_undefined (ln).link ();
381 new JSC$ASM_return (ln).link ();
382
383 /* Pop our namespace. */
384 JSC$ns.pop_frame ();
385 }
386
387
388 function JSC$zero_function ()
389 {
390 return 0;
391 }
392
393
394 /*
395 * Statements.
396 */
397
398 /* Block. */
399
400 function JSC$stmt_block (ln, list)
401 {
402 this.stype = JSC$STMT_BLOCK;
403 this.linenum = ln;
404 this.stmts = list;
405 this.asm = JSC$stmt_block_asm;
406 this.count_locals = JSC$stmt_block_count_locals;
407 }
408
409 function JSC$stmt_block_asm ()
410 {
411 JSC$ns.push_frame ();
412
413 /* Assembler for our stmts. */
414 var i;
415 for (i = 0; i < this.stmts.length; i++)
416 this.stmts[i].asm ();
417
418 JSC$ns.pop_frame ();
419 }
420
421
422 function JSC$stmt_block_count_locals (recursive)
423 {
424 if (!recursive)
425 return 0;
426
427 return JSC$count_locals_from_stmt_list (this.stmts);
428 }
429
430 /* Function declaration. */
431
432 function JSC$stmt_function_declaration (ln, container_id, function_id,
433 given_id)
434 {
435 this.stype = JSC$STMT_FUNCTION_DECLARATION;
436 this.linenum = ln;
437 this.container_id = container_id;
438 this.function_id = function_id;
439 this.given_id = given_id;
440 this.asm = JSC$stmt_function_declaration_asm;
441 this.count_locals = JSC$zero_function;
442 }
443
444 function JSC$stmt_function_declaration_asm ()
445 {
446 new JSC$ASM_load_global (this.linenum, this.function_id).link ();
447 new JSC$ASM_load_global (this.linenum, this.container_id).link ();
448 new JSC$ASM_store_property (this.linenum, this.given_id).link ();
449 }
450
451 /* Empty */
452
453 function JSC$stmt_empty (ln)
454 {
455 this.stype = JSC$STMT_EMPTY;
456 this.linenum = ln;
457 this.asm = JSC$stmt_empty_asm;
458 this.count_locals = JSC$zero_function;
459 }
460
461 function JSC$stmt_empty_asm ()
462 {
463 /* Nothing here. */
464 }
465
466
467 /* Continue. */
468
469 function JSC$stmt_continue (ln, label)
470 {
471 this.stype = JSC$STMT_CONTINUE;
472 this.linenum = ln;
473 this.label = label;
474 this.asm = JSC$stmt_continue_asm;
475 this.count_locals = JSC$zero_function;
476 }
477
478 function JSC$stmt_continue_asm ()
479 {
480 var l_cont = JSC$cont_break.get_continue (this.label);
481
482 if (l_cont == null)
483 {
484 if (this.label)
485 error (JSC$filename + ":" + this.linenum.toString ()
486 + ": label `" + this.label
487 + "' not found for continue statement");
488 else
489 error (JSC$filename + ":" + this.linenum.toString ()
490 + ": continue statement not within a loop");
491 }
492
493 var nesting = JSC$cont_break.count_with_nesting (this.label);
494 if (nesting > 0)
495 new JSC$ASM_with_pop (this.linenum, nesting).link ();
496
497 nesting = JSC$cont_break.count_try_nesting (this.label);
498 if (nesting > 0)
499 new JSC$ASM_try_pop (this.linenum, nesting).link ();
500
501 nesting = JSC$cont_break.count_switch_nesting (this.label);
502 if (nesting > 0)
503 {
504 /* Pop the value of the switch expression. */
505 if (nesting == 1)
506 new JSC$ASM_pop (this.linenum).link ();
507 else
508 new JSC$ASM_pop_n (this.linenum, nesting).link ();
509 }
510
511 new JSC$ASM_jmp (this.linenum, l_cont).link ();
512 }
513
514
515 /* Break. */
516
517 function JSC$stmt_break (ln, label)
518 {
519 this.stype = JSC$STMT_BREAK;
520 this.linenum = ln;
521 this.label = label;
522 this.asm = JSC$stmt_break_asm;
523 this.count_locals = JSC$zero_function;
524 }
525
526 function JSC$stmt_break_asm ()
527 {
528 var l_break = JSC$cont_break.get_break (this.label);
529
530 if (l_break == null)
531 {
532 if (this.label)
533 error (JSC$filename + ":" + this.linenum.toString ()
534 + ": label `" + this.label
535 + "' not found for break statement");
536 else
537 error (JSC$filename + ":" + this.linenum.toString()
538 + ": break statement not within a loop or switch");
539 }
540
541 var nesting = JSC$cont_break.count_with_nesting (this.label);
542 if (nesting > 0)
543 new JSC$ASM_with_pop (this.linenum, nesting).link ();
544
545 nesting = JSC$cont_break.count_try_nesting (this.label);
546 if (nesting > 0)
547 new JSC$ASM_try_pop (this.linenum, nesting).link ();
548
549 /*
550 * For non-labeled breaks, the switch nesting is handled in the
551 * stmt_switch(). The code after the label, returned by the
552 * get_break(), will handle the switch nesting in these cases.
553 * For the labeled breaks, we must pop the switch nesting here.
554 */
555 if (this.label)
556 {
557 nesting = JSC$cont_break.count_switch_nesting (this.label);
558 if (nesting > 0)
559 {
560 if (nesting == 1)
561 new JSC$ASM_pop (this.linenum).link ();
562 else
563 new JSC$ASM_pop_n (this.linenum, nesting).link ();
564 }
565 }
566
567 new JSC$ASM_jmp (this.linenum, l_break).link ();
568 }
569
570
571 /* Return. */
572
573 function JSC$stmt_return (ln, expr)
574 {
575 this.stype = JSC$STMT_RETURN;
576 this.linenum = ln;
577 this.expr = expr;
578 this.asm = JSC$stmt_return_asm;
579 this.count_locals = JSC$zero_function;
580 }
581
582 function JSC$stmt_return_asm ()
583 {
584 var nesting = JSC$cont_break.try_return_nesting ();
585 if (nesting > 0)
586 new JSC$ASM_try_pop (this.linenum, nesting).link ();
587
588 if (this.expr != null)
589 this.expr.asm ();
590 else
591 new JSC$ASM_const_undefined (this.linenum).link ();
592
593 new JSC$ASM_return (this.linenum).link ();
594 }
595
596
597 /* Switch. */
598
599 function JSC$stmt_switch (ln, last_ln, expr, clauses)
600 {
601 this.stype = JSC$STMT_SWITCH;
602 this.linenum = ln;
603 this.last_linenum = last_ln;
604 this.expr = expr;
605 this.clauses = clauses;
606 this.asm = JSC$stmt_switch_asm;
607 this.count_locals = JSC$stmt_switch_count_locals;
608 }
609
610 function JSC$stmt_switch_asm ()
611 {
612 /* Evaluate the switch expression to the top of the stack. */
613 this.expr.asm ();
614
615 /* The switch statement define a break label. */
616 var l_break = new JSC$ASM_label ();
617 JSC$cont_break.push (l_break, null, true, null);
618
619 /* For each clause (except the first), insert check and body labels. */
620 var i;
621 for (i = 1; i < this.clauses.length; i++)
622 {
623 this.clauses[i].l_check = new JSC$ASM_label ();
624 this.clauses[i].l_body = new JSC$ASM_label ();
625 }
626
627 /* Generate code for each clause. */
628 for (i = 0; i < this.clauses.length; i++)
629 {
630 /* Is this the last clause? */
631 var last = i + 1 >= this.clauses.length;
632 var c = this.clauses[i];
633
634 var next_check, next_body;
635 if (last)
636 next_check = next_body = l_break;
637 else
638 {
639 next_check = this.clauses[i + 1].l_check;
640 next_body = this.clauses[i + 1].l_body;
641 }
642
643 if (c.expr)
644 {
645 /*
646 * Must check if this clause matches the expression. If c.expr
647 * is null, this is the default clause that matches always.
648 */
649
650 if (i > 0)
651 c.l_check.link ();
652
653 new JSC$ASM_dup (c.linenum).link ();
654 c.expr.asm ();
655 new JSC$ASM_cmp_eq (c.linenum).link ();
656 new JSC$ASM_iffalse_b (c.linenum, next_check).link ();
657 }
658 else
659 {
660 if (i > 0)
661 /* The check label for the default case. */
662 c.l_check.link ();
663 }
664
665 /* Generate assembler for the body. */
666 if (i > 0)
667 c.l_body.link ();
668
669 var j;
670 for (j = 0; j < c.length; j++)
671 c[j].asm ();
672
673 /* And finally, jump to the next body. (this is the fallthrough case). */
674 new JSC$ASM_jmp (c.last_linenum, next_body).link ();
675 }
676
677 JSC$cont_break.pop ();
678
679 /* The break label. */
680 l_break.link ();
681
682 /* Pop the value of the switch expression. */
683 new JSC$ASM_pop (this.last_linenum).link ();
684 }
685
686 function JSC$stmt_switch_count_locals (recursive)
687 {
688 var locals = 0;
689 var i, j;
690
691 if (recursive)
692 {
693 /* For the recursive cases, we need the maximum of our clause stmts. */
694 for (i = 0; i < this.clauses.length; i++)
695 {
696 var c = this.clauses[i];
697 for (j = 0; j < c.length; j++)
698 {
699 var l = c[j].count_locals (true);
700 if (l > locals)
701 locals = l;
702 }
703 }
704 }
705 else
706 {
707 /*
708 * The case clauses are not blocks. Therefore, we need the amount,
709 * needed by the clauses at the top-level.
710 */
711
712 for (i = 0; i < this.clauses.length; i++)
713 {
714 var c = this.clauses[i];
715 for (j = 0; j < c.length; j++)
716 locals += c[j].count_locals (false);
717 }
718 }
719
720 return locals;
721 }
722
723
724 /* With. */
725
726 function JSC$stmt_with (ln, expr, stmt)
727 {
728 this.stype = JSC$STMT_WITH;
729 this.linenum = ln;
730 this.expr = expr;
731 this.stmt = stmt;
732 this.asm = JSC$stmt_with_asm;
733 this.count_locals = JSC$stmt_with_count_locals;
734 }
735
736 function JSC$stmt_with_asm ()
737 {
738 this.expr.asm ();
739
740 new JSC$ASM_with_push (this.linenum).link ();
741 JSC$cont_break.top.with_nesting++;
742
743 this.stmt.asm ();
744
745 JSC$cont_break.top.with_nesting--;
746 new JSC$ASM_with_pop (this.linenum, 1).link ();
747 }
748
749 function JSC$stmt_with_count_locals (recursive)
750 {
751 if (!recursive)
752 {
753 if (this.stmt.stype == JSC$STMT_VARIABLE)
754 return this.stmt.list.length;
755
756 return 0;
757 }
758 else
759 return this.stmt.count_locals (true);
760 }
761
762
763 /* Try. */
764
765 function JSC$stmt_try (ln, try_block_last_ln, try_last_ln, block, catch_list,
766 fin)
767 {
768 this.stype = JSC$STMT_TRY;
769 this.linenum = ln;
770 this.try_block_last_linenum = try_block_last_ln;
771 this.try_last_linenum = try_last_ln;
772 this.block = block;
773 this.catch_list = catch_list;
774 this.fin = fin;
775 this.asm = JSC$stmt_try_asm;
776 this.count_locals = JSC$stmt_try_count_locals;
777 }
778
779 function JSC$stmt_try_asm ()
780 {
781 var l_finally = new JSC$ASM_label ();
782
783 /* Protect and execute the try-block. */
784
785 var l_try_error = new JSC$ASM_label ();
786 new JSC$ASM_try_push (this.linenum, l_try_error).link ();
787 JSC$cont_break.top.try_nesting++;
788
789 this.block.asm ();
790
791 JSC$cont_break.top.try_nesting--;
792 new JSC$ASM_try_pop (this.try_block_last_linenum, 1).link ();
793
794 /*
795 * All ok so far. Push a `false' to indicate no error and jump to
796 * the finally block (or out if we have no finally block).
797 */
798 new JSC$ASM_const_false (this.try_block_last_linenum).link ();
799 new JSC$ASM_jmp (this.try_block_last_linenum, l_finally).link ();
800
801 /*
802 * Handle try block failures. The thrown value is on the top of the
803 * stack.
804 */
805
806 l_try_error.link ();
807
808 if (this.catch_list)
809 {
810 /*
811 * We keep one boolean variable below the thrown value. Its default
812 * value is false. When one of our catch blocks are entered, it is
813 * set to true to indicate that we shouldn't throw the error
814 * anymore.
815 */
816 new JSC$ASM_const_false (this.catch_list.linenum).link ();
817 new JSC$ASM_swap (this.catch_list.linenum).link ();
818
819 /* Protect and execute the catch list. */
820
821 var l_catch_list_error = new JSC$ASM_label ();
822 new JSC$ASM_try_push (this.catch_list.linenum,
823 l_catch_list_error).link ();
824 JSC$cont_break.top.try_nesting++;
825
826 /* Insert start and body labels for each catch list item. */
827 var i;
828 for (i = 0; i < this.catch_list.length; i++)
829 {
830 this.catch_list[i].l_start = new JSC$ASM_label ();
831 this.catch_list[i].l_body = new JSC$ASM_label ();
832 }
833
834 /* A label for the catch list end. */
835 var l_catch_list_end = new JSC$ASM_label ();
836
837 /* Process the individual catches. */
838 for (i = 0; i < this.catch_list.length; i++)
839 {
840 var c = this.catch_list[i];
841
842 /* This is the starting point of this catch frame. */
843 c.l_start.link ();
844
845 /*
846 * Create a new namespace frame and bind the catch's
847 * identifier to the thrown exception.
848 */
849
850 JSC$ns.push_frame ();
851 JSC$ns.define_symbol (c.id, JSC$SCOPE_LOCAL, JSC$ns.alloc_local (),
852 c.linenum);
853
854 new JSC$ASM_dup (c.linenum).link ();
855 new JSC$ASM_store_local (c.linenum,
856 JSC$ns.lookup_symbol (c.id).value).link ();
857
858 /* Check the possible guard. We must protect its calculation. */
859 if (c.guard)
860 {
861 var l_guard_error = new JSC$ASM_label ();
862 new JSC$ASM_try_push (c.linenum, l_guard_error).link ();
863 JSC$cont_break.top.try_nesting++;
864
865 /* Calculate the guard. */
866 c.guard.asm ();
867
868 JSC$cont_break.top.try_nesting--;
869 new JSC$ASM_try_pop (c.linenum, 1).link ();
870
871 /*
872 * Wow! We managed to do it. Now, let's check if we
873 * accept this catch case.
874 */
875
876 var next;
877 if (i + 1 >= this.catch_list.length)
878 next = l_catch_list_end;
879 else
880 next = this.catch_list[i + 1].l_start;
881
882 if (c.guard.lang_type == JSC$JS_BOOLEAN)
883 new JSC$ASM_iffalse_b (c.linenum, next).link ();
884 else
885 new JSC$ASM_iffalse (c.linenum, next).link ();
886
887 /* Yes, we do accept it. Just jump to do the stuffs. */
888 new JSC$ASM_jmp (c.linenum, c.l_body).link ();
889
890 /*
891 * The evaluation of the guard failed. Do the cleanup
892 * and jump to the next case.
893 */
894
895 l_guard_error.link ();
896
897 /* Pop the exception. */
898 new JSC$ASM_pop (c.linenum).link ();
899
900 /* Check the next case. */
901 new JSC$ASM_jmp (c.linenum, next).link ();
902 }
903
904 /*
905 * We did enter the catch body. Let's update our boolean
906 * status variable to reflect this fact.
907 */
908 c.l_body.link ();
909
910 new JSC$ASM_swap (c.linenum).link ();
911 new JSC$ASM_pop (c.linenum).link ();
912 new JSC$ASM_const_true (c.linenum).link ();
913 new JSC$ASM_swap (c.linenum).link ();
914
915 /* Code for the catch body. */
916 c.stmt.asm ();
917
918 /* We'r done with the namespace frame. */
919 JSC$ns.pop_frame ();
920
921 /*
922 * The next catch tag, or the l_catch_list_end follows us,
923 * so we don't need a jumps here.
924 */
925 }
926
927 /*
928 * The catch list was evaluated without errors.
929 */
930
931 l_catch_list_end.link ();
932 JSC$cont_break.top.try_nesting--;
933 new JSC$ASM_try_pop (this.catch_list.last_linenum, 1).link ();
934
935 /* Did we enter any of our catch lists? */
936
937 var l_we_did_enter = new JSC$ASM_label ();
938 new JSC$ASM_swap (this.catch_list.last_linenum).link ();
939 new JSC$ASM_iftrue_b (this.catch_list.last_linenum,
940 l_we_did_enter).link ();
941
942 /* No we didn't. */
943
944 /*
945 * Push `true' to indicate an exception and jump to the finally
946 * block. The exception is now on the top of the stack.
947 */
948 new JSC$ASM_const_true (this.catch_list.last_linenum).link ();
949 new JSC$ASM_jmp (this.catch_list.last_linenum, l_finally).link ();
950
951 /* Yes, we did enter one (or many) of our catch lists. */
952
953 l_we_did_enter.link ();
954
955 /* Pop the try-block's exception */
956 new JSC$ASM_pop (this.catch_list.last_linenum).link ();
957
958 /*
959 * Push a `false' to indicate "no errors" and jump to the
960 * finally block.
961 */
962 new JSC$ASM_const_false (this.catch_list.last_linenum).link ();
963 new JSC$ASM_jmp (this.catch_list.last_linenum, l_finally).link ();
964
965
966 /*
967 * Handle catch list failures. The thrown value is on the top of the
968 * stack.
969 */
970
971 l_catch_list_error.link ();
972
973 /*
974 * Pop the try-block's exception and our boolean `did we enter a
975 * catch block' variable. They are below our new exception.
976 */
977 new JSC$ASM_apop (this.catch_list.last_linenum, 2).link ();
978
979 /*
980 * Push `true' to indicate an exception. We will fallthrough to
981 * the finally part, so no jump is needed here.
982 */
983 new JSC$ASM_const_true (this.catch_list.last_linenum).link ();
984 }
985 else
986 {
987 /* No catch list. */
988 new JSC$ASM_const_true (this.try_block_last_linenum).link ();
989 }
990
991 /* The possible finally block. */
992
993 l_finally.link ();
994
995 if (this.fin)
996 /* Execute it without protection. */
997 this.fin.asm ();
998
999 /* We'r almost there. Let's see if we have to raise a new exception. */
1000
1001 var l_out = new JSC$ASM_label ();
1002 new JSC$ASM_iffalse_b (this.try_last_linenum, l_out).link ();
1003
1004 /* Do raise it. */
1005 new JSC$ASM_throw (this.try_last_linenum).link ();
1006
1007 /* The possible exception is handled. Please, continue. */
1008 l_out.link ();
1009 }
1010
1011 function JSC$stmt_try_count_locals (recursive)
1012 {
1013 var count = 0;
1014 var c;
1015
1016 if (recursive)
1017 {
1018 c = this.block.count_locals (true);
1019 if (c > count)
1020 count = c;
1021
1022 if (this.catch_list)
1023 {
1024 var i;
1025 for (i = 0; i < this.catch_list.length; i++)
1026 {
1027 c = this.catch_list[i].stmt.count_locals (true);
1028 if (c > count)
1029 count = c;
1030 }
1031 }
1032 if (this.fin)
1033 {
1034 c = this.fin.count_locals (true);
1035 if (c > count)
1036 count = c;
1037 }
1038 }
1039 else
1040 {
1041 if (this.block.stype == JSC$STMT_VARIABLE)
1042 count += this.block.list.length;
1043
1044 if (this.catch_list)
1045 {
1046 /* One for the call variable. */
1047 count++;
1048
1049 var i;
1050 for (i = 0; i < this.catch_list.length; i++)
1051 if (this.catch_list[i].stmt.stype == JSC$STMT_VARIABLE)
1052 count += this.catch_list[i].stmt.list.length;
1053 }
1054
1055 if (this.fin)
1056 if (this.fin.stype == JSC$STMT_VARIABLE)
1057 count += this.fin.list.length;
1058 }
1059
1060 return count;
1061 }
1062
1063
1064 /* Throw. */
1065
1066 function JSC$stmt_throw (ln, expr)
1067 {
1068 this.stype = JSC$STMT_THROW;
1069 this.linenum = ln;
1070 this.expr = expr;
1071 this.asm = JSC$stmt_throw_asm;
1072 this.count_locals = JSC$zero_function;
1073 }
1074
1075 function JSC$stmt_throw_asm ()
1076 {
1077 this.expr.asm ();
1078 new JSC$ASM_throw (this.linenum).link ();
1079 }
1080
1081
1082 /* Labeled statement. */
1083 function JSC$stmt_labeled_stmt (ln, id, stmt)
1084 {
1085 this.stype = JSC$STMT_LABELED_STMT;
1086 this.linenum = ln;
1087 this.id = id;
1088 this.stmt = stmt;
1089 this.asm = JSC$stmt_labeled_stmt_asm;
1090 this.count_locals = JSC$stmt_labeled_stmt_count_locals;
1091 }
1092
1093 function JSC$stmt_labeled_stmt_asm ()
1094 {
1095 var l_continue = new JSC$ASM_label ();
1096 var l_break = new JSC$ASM_label ();
1097
1098 /*
1099 * It is an error if we already have a labeled statement with the
1100 * same id.
1101 */
1102 if (!JSC$cont_break.is_unique_label (this.id))
1103 error (JSC$filename + ":" + this.linenum.toString ()
1104 + ": labeled statement is enclosed by another labeled statement "
1105 + "with the same label");
1106
1107 /* Push the break and continue labels. */
1108 JSC$cont_break.push (l_break, l_continue, false, this.id);
1109
1110 /* Dump the assembler. */
1111 l_continue.link ();
1112 this.stmt.asm ();
1113 l_break.link ();
1114
1115 /* And we'r done with out label scope. */
1116 JSC$cont_break.pop ();
1117 }
1118
1119 function JSC$stmt_labeled_stmt_count_locals (recursive)
1120 {
1121 return this.stmt.count_locals (recursive);
1122 }
1123
1124
1125 /* Expression. */
1126
1127 function JSC$stmt_expr (expr)
1128 {
1129 this.stype = JSC$STMT_EXPR;
1130 this.linenum = expr.linenum;
1131 this.expr = expr;
1132 this.asm = JSC$stmt_expr_asm;
1133 this.count_locals = JSC$zero_function;
1134 }
1135
1136 function JSC$stmt_expr_asm ()
1137 {
1138 this.expr.asm ();
1139 new JSC$ASM_pop (this.linenum).link ();
1140 }
1141
1142
1143 /* If. */
1144
1145 function JSC$stmt_if (ln, expr, stmt1, stmt2)
1146 {
1147 this.stype = JSC$STMT_IF;
1148 this.linenum = ln;
1149 this.expr = expr;
1150 this.stmt1 = stmt1;
1151 this.stmt2 = stmt2;
1152 this.asm = JSC$stmt_if_asm;
1153 this.count_locals = JSC$stmt_if_count_locals;
1154 }
1155
1156 function JSC$stmt_if_asm ()
1157 {
1158 this.expr.asm ();
1159
1160 var l1 = new JSC$ASM_label ();
1161 var l2 = new JSC$ASM_label ();
1162
1163 if (JSC$optimize_type && this.expr.lang_type
1164 && this.expr.lang_type == JSC$JS_BOOLEAN)
1165 new JSC$ASM_iffalse_b (this.linenum, l1).link ();
1166 else
1167 new JSC$ASM_iffalse (this.linenum, l1).link ();
1168
1169 /* Code for the then branch. */
1170 this.stmt1.asm ();
1171 new JSC$ASM_jmp (this.linenum, l2).link ();
1172
1173 /* Code for the else branch. */
1174 l1.link ();
1175 if (this.stmt2 != null)
1176 this.stmt2.asm ();
1177
1178 /* Done label. */
1179 l2.link ();
1180 }
1181
1182
1183 function JSC$stmt_if_count_locals (recursive)
1184 {
1185 var lcount;
1186
1187 if (!recursive)
1188 {
1189 lcount = 0;
1190 if (this.stmt1.stype == JSC$STMT_VARIABLE)
1191 lcount += this.stmt1.list.length;
1192
1193 if (this.stmt2 != null && this.stmt2.stype == JSC$STMT_VARIABLE)
1194 lcount += this.stmt2.list.length;
1195 }
1196 else
1197 {
1198 lcount = this.stmt1.count_locals (true);
1199
1200 if (this.stmt2)
1201 {
1202 var c = this.stmt2.count_locals (true);
1203 if (c > lcount)
1204 lcount = c;
1205 }
1206 }
1207
1208 return lcount;
1209 }
1210
1211
1212 /* Do...While. */
1213
1214 function JSC$stmt_do_while (ln, expr, stmt)
1215 {
1216 this.stype = JSC$STMT_DO_WHILE;
1217 this.linenum = ln;
1218 this.expr = expr;
1219 this.stmt = stmt;
1220 this.asm = JSC$stmt_do_while_asm;
1221 this.count_locals = JSC$stmt_do_while_count_locals;
1222 }
1223
1224 function JSC$stmt_do_while_asm ()
1225 {
1226 var l1 = new JSC$ASM_label ();
1227 var l2 = new JSC$ASM_label ();
1228 var l3 = new JSC$ASM_label ();
1229
1230 /* Loop label. */
1231 l1.link ();
1232
1233 /* Body. */
1234 JSC$cont_break.push (l3, l2, false, null);
1235 this.stmt.asm ();
1236 JSC$cont_break.pop ();
1237
1238 /* Condition & continue. */
1239 l2.link ();
1240 this.expr.asm ();
1241 if (JSC$optimize_type && this.expr.lang_type
1242 && this.expr.lang_type == JSC$JS_BOOLEAN)
1243 new JSC$ASM_iftrue_b (this.linenum, l1).link ();
1244 else
1245 new JSC$ASM_iftrue (this.linenum, l1).link ();
1246
1247 /* Break label. */
1248 l3.link ();
1249 }
1250
1251 function JSC$stmt_do_while_count_locals (recursive)
1252 {
1253 if (!recursive)
1254 {
1255 if (this.stmt.stype == JSC$STMT_VARIABLE)
1256 return this.stmt.list.length;
1257
1258 return 0;
1259 }
1260 else
1261 return this.stmt.count_locals (true);
1262 }
1263
1264 /* While. */
1265
1266 function JSC$stmt_while (ln, expr, stmt)
1267 {
1268 this.stype = JSC$STMT_WHILE;
1269 this.linenum = ln;
1270 this.expr = expr;
1271 this.stmt = stmt;
1272 this.asm = JSC$stmt_while_asm;
1273 this.count_locals = JSC$stmt_while_count_locals;
1274 }
1275
1276 function JSC$stmt_while_asm ()
1277 {
1278 var l1 = new JSC$ASM_label ();
1279 var l2 = new JSC$ASM_label ();
1280
1281 /* Loop label. */
1282 l1.link ();
1283
1284 /* Condition. */
1285 this.expr.asm ();
1286 if (JSC$optimize_type && this.expr.lang_type
1287 && this.expr.lang_type == JSC$JS_BOOLEAN)
1288 new JSC$ASM_iffalse_b (this.linenum, l2).link ();
1289 else
1290 new JSC$ASM_iffalse (this.linenum, l2).link ();
1291
1292 /* Body. */
1293 JSC$cont_break.push (l2, l1, false, null);
1294 this.stmt.asm ();
1295 JSC$cont_break.pop ();
1296
1297 /* Goto loop. */
1298 new JSC$ASM_jmp (this.linenum, l1).link ();
1299
1300 /* Break label. */
1301 l2.link ();
1302 }
1303
1304
1305 function JSC$stmt_while_count_locals (recursive)
1306 {
1307 if (!recursive)
1308 {
1309 if (this.stmt.stype == JSC$STMT_VARIABLE)
1310 return this.stmt.list.length;
1311
1312 return 0;
1313 }
1314 else
1315 return this.stmt.count_locals (true);
1316 }
1317
1318
1319 /* For. */
1320
1321 function JSC$stmt_for (ln, vars, e1, e2, e3, stmt)
1322 {
1323 this.stype = JSC$STMT_FOR;
1324 this.linenum = ln;
1325 this.vars = vars;
1326 this.expr1 = e1;
1327 this.expr2 = e2;
1328 this.expr3 = e3;
1329 this.stmt = stmt;
1330 this.asm = JSC$stmt_for_asm;
1331 this.count_locals = JSC$stmt_for_count_locals;
1332 }
1333
1334 function JSC$stmt_for_asm ()
1335 {
1336 /* Code for the init. */
1337 if (this.vars)
1338 {
1339 /* We have our own variable scope. */
1340 JSC$ns.push_frame ();
1341
1342 var i;
1343 for (i = 0; i < this.vars.length; i++)
1344 {
1345 var decl = this.vars[i];
1346
1347 JSC$ns.define_symbol (decl.id, JSC$SCOPE_LOCAL,
1348 JSC$ns.alloc_local (), this.linenum);
1349
1350 /* Possible init. */
1351 if (decl.expr)
1352 {
1353 decl.expr.asm ();
1354
1355 var r = JSC$ns.lookup_symbol (decl.id);
1356 if (r == null || r.scope != JSC$SCOPE_LOCAL)
1357 error (JSC$filename + ":" + this.liennum.toString ()
1358 + ": internal compiler error in local variable "
1359 + "declaration in for statement");
1360
1361 new JSC$ASM_store_local (this.linenum, r.value).link ();
1362 }
1363 }
1364 }
1365 else if (this.expr1 != null)
1366 {
1367 this.expr1.asm ();
1368 new JSC$ASM_pop (this.linenum).link ();
1369 }
1370
1371 var l1 = new JSC$ASM_label ();
1372 var l2 = new JSC$ASM_label ();
1373 var l3 = new JSC$ASM_label ();
1374
1375 /* Loop label. */
1376 l1.link ();
1377
1378 /* Condition. */
1379 var type_op = false;
1380 if (this.expr2 != null)
1381 {
1382 this.expr2.asm ();
1383 if (JSC$optimize_type && this.expr2.lang_type
1384 && this.expr2.lang_type == JSC$JS_BOOLEAN)
1385 type_op = true;
1386 }
1387 else
1388 {
1389 new JSC$ASM_const_true (this.linenum).link ();
1390 type_op = JSC$optimize_type;
1391 }
1392 if (type_op)
1393 new JSC$ASM_iffalse_b (this.linenum, l3).link ();
1394 else
1395 new JSC$ASM_iffalse (this.linenum, l3).link ();
1396
1397 JSC$cont_break.push (l3, l2, false, null);
1398 /* Body. */
1399 this.stmt.asm ();
1400 JSC$cont_break.pop ();
1401
1402 /* Continue label. */
1403 l2.link ();
1404
1405 /* Increment. */
1406 if (this.expr3 != null)
1407 {
1408 this.expr3.asm ();
1409 new JSC$ASM_pop (this.linenum).link ();
1410 }
1411
1412 /* Goto loop. */
1413 new JSC$ASM_jmp (this.linenum, l1).link ();
1414
1415 /* Break label. */
1416 l3.link ();
1417
1418 if (this.vars)
1419 /* Pop the local variable scope. */
1420 JSC$ns.pop_frame ();
1421 }
1422
1423
1424 function JSC$stmt_for_count_locals (recursive)
1425 {
1426 var count = 0;
1427
1428 if (recursive)
1429 {
1430 if (this.vars)
1431 count += this.vars.length;
1432
1433 count += this.stmt.count_locals (true);
1434 }
1435 else
1436 {
1437 if (this.stmt.stype == JSC$STMT_VARIABLE)
1438 count += this.stmt.list.length;
1439 }
1440
1441 return count;
1442 }
1443
1444
1445 /* For...in. */
1446
1447 function JSC$stmt_for_in (ln, vars, e1, e2, stmt)
1448 {
1449 this.stype = JSC$STMT_FOR_IN;
1450 this.linenum = ln;
1451 this.vars = vars;
1452 this.expr1 = e1;
1453 this.expr2 = e2;
1454 this.stmt = stmt;
1455 this.asm = JSC$stmt_for_in_asm;
1456 this.count_locals = JSC$stmt_for_in_count_locals;
1457 }
1458
1459 function JSC$stmt_for_in_asm ()
1460 {
1461 var local_id;
1462
1463 if (this.vars)
1464 {
1465 /* We need our own variable scope here. */
1466 JSC$ns.push_frame ();
1467
1468 var decl = this.vars[0];
1469 local_id = JSC$ns.alloc_local ();
1470 JSC$ns.define_symbol (decl.id, JSC$SCOPE_LOCAL, local_id, this.linenum);
1471
1472 /* Possible init. */
1473 if (decl.expr)
1474 {
1475 decl.expr.asm ();
1476 new JSC$ASM_store_local (this.linenum, local_id).link ();
1477 }
1478 }
1479
1480 /* Init the world. */
1481 this.expr2.asm ();
1482 new JSC$ASM_dup (this.linenum).link ();
1483 new JSC$ASM_const_i0 (this.linenum).link ();
1484 new JSC$ASM_swap (this.linenum).link ();
1485 new JSC$ASM_const_i0 (this.linenum).link ();
1486
1487 var l_loop = new JSC$ASM_label ();
1488 var l_cont = new JSC$ASM_label ();
1489 var l_iffalse_b = new JSC$ASM_label ();
1490 var l_break = new JSC$ASM_label ();
1491
1492 /* Loop label. */
1493 l_loop.link ();
1494
1495 /* Fetch nth. */
1496 new JSC$ASM_nth (this.linenum).link ();
1497 new JSC$ASM_iffalse_b (this.linenum, l_iffalse_b).link ();
1498
1499 /* Store value to variable. */
1500 if (this.vars)
1501 new JSC$ASM_store_local (this.linenum, local_id).link ();
1502 else
1503 JSC$asm_expr_lvalue_store_asm (this.expr1);
1504
1505 /* Body. */
1506 JSC$cont_break.push (l_break, l_cont, false, null);
1507 this.stmt.asm ();
1508 JSC$cont_break.pop ();
1509
1510 /* Continue label. */
1511 l_cont.link ();
1512
1513 /* Increment. */
1514 new JSC$ASM_const_i1 (this.linenum).link ();
1515 new JSC$ASM_add (this.linenum).link ();
1516 new JSC$ASM_dup (this.linenum).link ();
1517 new JSC$ASM_roll (this.linenum, -3).link ();
1518 new JSC$ASM_dup (this.linenum).link ();
1519 new JSC$ASM_roll (this.linenum, 4).link ();
1520 new JSC$ASM_swap (this.linenum).link ();
1521
1522 /* Goto loop. */
1523 new JSC$ASM_jmp (this.linenum, l_loop).link ();
1524
1525 /* Out label. */
1526 l_iffalse_b.link ();
1527
1528 new JSC$ASM_pop (this.linenum).link ();
1529
1530 /* Break label. */
1531 l_break.link ();
1532 new JSC$ASM_pop_n (this.linenum, 2).link ();
1533
1534 if (this.vars)
1535 /* Pop the variable scope. */
1536 JSC$ns.pop_frame ();
1537 }
1538
1539 function JSC$stmt_for_in_count_locals (recursive)
1540 {
1541 var count = 0;
1542
1543 if (recursive)
1544 {
1545 if (this.vars)
1546 count++;
1547
1548 count += this.stmt.count_locals (true);
1549 }
1550 else
1551 {
1552 if (this.stmt.stype == JSC$STMT_VARIABLE)
1553 count += this.stmt.list.length;
1554
1555 }
1556
1557 return count;
1558 }
1559
1560
1561 /* Variable. */
1562
1563 function JSC$stmt_variable (ln, list)
1564 {
1565 this.stype = JSC$STMT_VARIABLE;
1566 this.linenum = ln;
1567 this.global_level = false;
1568 this.list = list;
1569 this.asm = JSC$stmt_variable_asm;
1570 this.count_locals = JSC$stmt_variable_count_locals;
1571 }
1572
1573 function JSC$stmt_variable_asm ()
1574 {
1575 var j, r;
1576
1577 /* Define all local variables to our namespace. */
1578 for (j = 0; j < this.list.length; j++)
1579 {
1580 var i = this.list[j];
1581
1582 if (!this.global_level)
1583 JSC$ns.define_symbol (i.id, JSC$SCOPE_LOCAL,
1584 JSC$ns.alloc_local (), this.linenum);
1585 if (i.expr)
1586 {
1587 i.expr.asm ();
1588
1589 if (this.global_level)
1590 new JSC$ASM_store_global (this.linenum, i.id).link ();
1591 else
1592 {
1593 r = JSC$ns.lookup_symbol (i.id);
1594 if (r == null || r.scope != JSC$SCOPE_LOCAL)
1595 error (JSC$filename + ":" + this.linenum.toString()
1596 + ": internal compiler error in local variable declaration");
1597
1598 new JSC$ASM_store_local (this.linenum, r.value).link ();
1599 }
1600 }
1601 }
1602 }
1603
1604 function JSC$stmt_variable_count_locals (recursive)
1605 {
1606 if (!recursive)
1607 {
1608 if (this.global_level)
1609 /* We define these as global variables. */
1610 return 0;
1611
1612 return this.list.length;
1613 }
1614
1615 return 0;
1616 }
1617
1618 function JSC$var_declaration (id, expr)
1619 {
1620 this.id = id;
1621 this.expr = expr;
1622 }
1623
1624
1625 /*
1626 * Expressions.
1627 */
1628
1629 /* This. */
1630
1631 function JSC$expr_this (ln)
1632 {
1633 this.etype = JSC$EXPR_THIS;
1634 this.linenum = ln;
1635 this.asm = JSC$expr_this_asm;
1636 }
1637
1638 function JSC$expr_this_asm ()
1639 {
1640 new JSC$ASM_load_arg (this.linenum, 0).link ();
1641 }
1642
1643 /* Identifier. */
1644
1645 function JSC$expr_identifier (ln, value)
1646 {
1647 this.etype = JSC$EXPR_IDENTIFIER;
1648 this.linenum = ln;
1649 this.value = value;
1650 this.asm = JSC$expr_identifier_asm;
1651 }
1652
1653 function JSC$expr_identifier_asm ()
1654 {
1655 JSC$asm_expr_lvalue_load_asm (this);
1656 }
1657
1658 /* Float. */
1659
1660 function JSC$expr_float (ln, value)
1661 {
1662 this.etype = JSC$EXPR_FLOAT;
1663 this.lang_type = JSC$JS_FLOAT;
1664 this.linenum = ln;
1665 this.value = value;
1666 this.asm = JSC$expr_float_asm;
1667 }
1668
1669 function JSC$expr_float_asm ()
1670 {
1671 new JSC$ASM_const (this.linenum, this.value).link ();
1672 }
1673
1674 /* Integer. */
1675
1676 function JSC$expr_integer (ln, value)
1677 {
1678 this.etype = JSC$EXPR_INTEGER;
1679 this.lang_type = JSC$JS_INTEGER;
1680 this.linenum = ln;
1681 this.value = value;
1682 this.asm = JSC$expr_integer_asm;
1683 }
1684
1685 function JSC$expr_integer_asm ()
1686 {
1687 if (this.value == 0)
1688 new JSC$ASM_const_i0 (this.linenum).link ();
1689 else if (this.value == 1)
1690 new JSC$ASM_const_i1 (this.linenum).link ();
1691 else if (this.value == 2)
1692 new JSC$ASM_const_i2 (this.linenum).link ();
1693 else if (this.value == 3)
1694 new JSC$ASM_const_i3 (this.linenum).link ();
1695 else
1696 new JSC$ASM_const_i (this.linenum, this.value).link ();
1697 }
1698
1699 /* String. */
1700
1701 function JSC$expr_string (ln, value)
1702 {
1703 this.etype = JSC$EXPR_STRING;
1704 this.lang_type = JSC$JS_STRING;
1705 this.linenum = ln;
1706 this.value = value;
1707 this.asm = JSC$expr_string_asm;
1708 }
1709
1710 function JSC$expr_string_asm ()
1711 {
1712 new JSC$ASM_const (this.linenum, this.value).link ();
1713 }
1714
1715 /* Regexp. */
1716
1717 function JSC$expr_regexp (ln, value)
1718 {
1719 this.etype = JSC$EXPR_REGEXP;
1720 this.lang_type = JSC$JS_BUILTIN;
1721 this.linenum = ln;
1722 this.value = value;
1723 this.asm = JSC$expr_regexp_asm;
1724 }
1725
1726 function JSC$expr_regexp_asm ()
1727 {
1728 new JSC$ASM_const (this.linenum, this.value).link ();
1729 }
1730
1731 /* Array initializer. */
1732
1733 function JSC$expr_array_initializer (ln, items)
1734 {
1735 this.etype = JSC$EXPR_ARRAY_INITIALIZER;
1736 this.lang_type = JSC$JS_ARRAY;
1737 this.linenum = ln;
1738 this.items = items;
1739 this.asm = JSC$expr_array_initializer_asm;
1740 }
1741
1742 function JSC$expr_array_initializer_asm ()
1743 {
1744 /* Generate assembler for the individual items. */
1745
1746 var i;
1747 for (i = this.items.length - 1; i >= 0; i--)
1748 {
1749 if (this.items[i])
1750 this.items[i].asm ();
1751 else
1752 new JSC$ASM_const_undefined (this.linenum).link ();
1753 }
1754
1755 /*
1756 * The number of items as a negative integer. The Array object's
1757 * constructor knows that if the number of arguments is negative, it
1758 * is called from the array initializer. Why? Because the code:
1759 *
1760 * new Array (5);
1761 *
1762 * creates an array of length of 5, but code:
1763 *
1764 * [5]
1765 *
1766 * creates an array with one item: integer number five. These cases
1767 * must be separatable from the code and that's why the argument
1768 * counts for the array initializers are negative.
1769 */
1770 new JSC$ASM_const (this.linenum, -this.items.length).link ();
1771
1772 /* Call the constructor. */
1773 new JSC$ASM_load_global (this.linenum, "Array").link ();
1774 new JSC$ASM_new (this.linenum).link ();
1775 new JSC$ASM_swap (this.linenum).link ();
1776 new JSC$ASM_apop (this.linenum, this.items.length + 2).link ();
1777 }
1778
1779 /* Object initializer. */
1780
1781 function JSC$expr_object_initializer (ln, items)
1782 {
1783 this.etype = JSC$EXPR_OBJECT_INITIALIZER;
1784 this.lang_type = JSC$JS_OBJECT;
1785 this.linenum = ln;
1786 this.items = items;
1787 this.asm = JSC$expr_object_initializer_asm;
1788 }
1789
1790 function JSC$expr_object_initializer_asm ()
1791 {
1792 /* Create a new object. */
1793 new JSC$ASM_const_i0 (this.linenum).link ();
1794 new JSC$ASM_load_global (this.linenum, "Object").link ();
1795 new JSC$ASM_new (this.linenum).link ();
1796 new JSC$ASM_swap (this.linenum).link ();
1797 new JSC$ASM_apop (this.linenum, 2).link ();
1798
1799 /* Insert the items. */
1800 for (var i = 0; i < this.items.length; i++)
1801 {
1802 var item = this.items[i];
1803
1804 new JSC$ASM_dup (item.linenum).link ();
1805 item.expr.asm ();
1806 new JSC$ASM_swap (item.linenum).link ();
1807
1808 switch (item.id_type)
1809 {
1810 case JSC$tIDENTIFIER:
1811 new JSC$ASM_store_property (item.linenum, item.id).link ();
1812 break;
1813
1814 case JSC$tSTRING:
1815 new JSC$ASM_const (item.linenum, item.id).link ();
1816 new JSC$ASM_store_array (item.linenum).link ();
1817 break;
1818
1819 case JSC$tINTEGER:
1820 switch (item.id)
1821 {
1822 case 0:
1823 new JSC$ASM_const_i0 (item.linenum).link ();
1824 break;
1825
1826 case 1:
1827 new JSC$ASM_const_i1 (item.linenum).link ();
1828 break;
1829
1830 case 2:
1831 new JSC$ASM_const_i2 (item.linenum).link ();
1832 break;
1833
1834 case 3:
1835 new JSC$ASM_const_i3 (item.linenum).link ();
1836 break;
1837
1838 default:
1839 new JSC$ASM_const_i (item.linenum, item.id).link ();
1840 break;
1841 }
1842 new JSC$ASM_store_array (item.linenum).link ();
1843 break;
1844 }
1845 }
1846 }
1847
1848
1849 /* Null. */
1850
1851 function JSC$expr_null (ln)
1852 {
1853 this.etype = JSC$EXPR_NULL;
1854 this.lang_type = JSC$JS_NULL;
1855 this.linenum = ln;
1856 this.asm = JSC$expr_null_asm;
1857 }
1858
1859 function JSC$expr_null_asm ()
1860 {
1861 new JSC$ASM_const_null (this.linenum).link ();
1862 }
1863
1864 /* True. */
1865
1866 function JSC$expr_true (ln)
1867 {
1868 this.etype = JSC$EXPR_TRUE;
1869 this.lang_type = JSC$JS_BOOLEAN;
1870 this.linenum = ln;
1871 this.asm = JSC$expr_true_asm;
1872 }
1873
1874 function JSC$expr_true_asm ()
1875 {
1876 new JSC$ASM_const_true (this.linenum).link ();
1877 }
1878
1879 /* False. */
1880
1881 function JSC$expr_false (ln)
1882 {
1883 this.etype = JSC$EXPR_FALSE;
1884 this.lang_type = JSC$JS_BOOLEAN;
1885 this.linenum = ln;
1886 this.asm = JSC$expr_false_asm;
1887 }
1888
1889 function JSC$expr_false_asm ()
1890 {
1891 new JSC$ASM_const_false (this.linenum).link ();
1892 }
1893
1894
1895 /* Multiplicative expr. */
1896
1897 function JSC$expr_multiplicative (ln, type, e1, e2)
1898 {
1899 this.etype = JSC$EXPR_MULTIPLICATIVE;
1900 this.linenum = ln;
1901 this.type = type;
1902 this.e1 = e1;
1903 this.e2 = e2;
1904 this.asm = JSC$expr_multiplicative_asm;
1905 }
1906
1907 function JSC$expr_multiplicative_asm ()
1908 {
1909 this.e1.asm ();
1910 this.e2.asm ();
1911 if (this.type == #'*')
1912 new JSC$ASM_mul (this.linenum).link ();
1913 else if (this.type == #'/')
1914 new JSC$ASM_div (this.linenum).link ();
1915 else
1916 new JSC$ASM_mod (this.linenum).link ();
1917 }
1918
1919
1920 /* Additive expr. */
1921
1922 function JSC$expr_additive (ln, type, e1, e2)
1923 {
1924 this.etype = JSC$EXPR_ADDITIVE;
1925 this.linenum = ln;
1926 this.type = type;
1927 this.e1 = e1;
1928 this.e2 = e2;
1929 this.asm = JSC$expr_additive_asm;
1930 this.constant_folding = JSC$expr_additive_constant_folding;
1931 }
1932
1933 function JSC$expr_additive_asm ()
1934 {
1935 this.e1.asm ();
1936 this.e2.asm ();
1937 if (this.type == #'+')
1938 new JSC$ASM_add (this.linenum).link ();
1939 else
1940 new JSC$ASM_sub (this.linenum).link ();
1941 }
1942
1943 function JSC$expr_additive_constant_folding ()
1944 {
1945 if (this.e1.constant_folding)
1946 this.e1 = this.e1.constant_folding ();
1947 if (this.e2.constant_folding)
1948 this.e2 = this.e2.constant_folding ();
1949
1950 /* This could be smarter. */
1951 if (this.e1.lang_type && this.e2.lang_type
1952 && this.e1.lang_type == this.e2.lang_type)
1953 {
1954 switch (this.e1.lang_type)
1955 {
1956 case JSC$JS_INTEGER:
1957 return new JSC$expr_integer (this.linenum,
1958 this.type == #'+'
1959 ? this.e1.value + this.e2.value
1960 : this.e1.value - this.e2.value);
1961 break;
1962
1963 case JSC$JS_FLOAT:
1964 return new JSC$expr_float (this.linenum,
1965 this.type == #'+'
1966 ? this.e1.value + this.e2.value
1967 : this.e1.value - this.e2.value);
1968 break;
1969
1970 case JSC$JS_STRING:
1971 if (this.type == #'+')
1972 /* Only the addition is available for the strings. */
1973 return new JSC$expr_string (this.linenum,
1974 this.e1.value + this.e2.value);
1975 break;
1976
1977 default:
1978 /* FALLTHROUGH */
1979 break;
1980 }
1981 }
1982
1983 return this;
1984 }
1985
1986 /* Shift expr. */
1987
1988 function JSC$expr_shift (ln, type, e1, e2)
1989 {
1990 this.etype = JSC$EXPR_SHIFT;
1991 this.linenum = ln;
1992 this.type = type;
1993 this.e1 = e1;
1994 this.e2 = e2;
1995 this.asm = JSC$expr_shift_asm;
1996 }
1997
1998 function JSC$expr_shift_asm ()
1999 {
2000 this.e1.asm ();
2001 this.e2.asm ();
2002
2003 if (this.type == JSC$tLSHIFT)
2004 new JSC$ASM_shift_left (this.linenum).link ();
2005 else if (this.type == JSC$tRSHIFT)
2006 new JSC$ASM_shift_right (this.linenum).link ();
2007 else
2008 new JSC$ASM_shift_rright (this.linenum).link ();
2009 }
2010
2011
2012 /* Relational expr. */
2013
2014 function JSC$expr_relational (ln, type, e1, e2)
2015 {
2016 this.etype = JSC$EXPR_RELATIONAL;
2017 this.lang_type = JSC$JS_BOOLEAN;
2018 this.linenum = ln;
2019 this.type = type;
2020 this.e1 = e1;
2021 this.e2 = e2;
2022 this.asm = JSC$expr_relational_asm;
2023 }
2024
2025 function JSC$expr_relational_asm ()
2026 {
2027 this.e1.asm ();
2028 this.e2.asm ();
2029
2030 if (this.type == #'<')
2031 new JSC$ASM_cmp_lt (this.linenum).link ();
2032 else if (this.type == #'>')
2033 new JSC$ASM_cmp_gt (this.linenum).link ();
2034 else if (this.type == JSC$tLE)
2035 new JSC$ASM_cmp_le (this.linenum).link ();
2036 else
2037 new JSC$ASM_cmp_ge (this.linenum).link ();
2038 }
2039
2040
2041 /* Equality expr. */
2042
2043 function JSC$expr_equality (ln, type, e1, e2)
2044 {
2045 this.etype = JSC$EXPR_EQUALITY;
2046 this.lang_type = JSC$JS_BOOLEAN;
2047 this.linenum = ln;
2048 this.type = type;
2049 this.e1 = e1;
2050 this.e2 = e2;
2051 this.asm = JSC$expr_equality_asm;
2052 }
2053
2054 function JSC$expr_equality_asm ()
2055 {
2056 this.e1.asm ();
2057 this.e2.asm ();
2058
2059 switch (this.type)
2060 {
2061 case JSC$tEQUAL:
2062 new JSC$ASM_cmp_eq (this.linenum).link ();
2063 break;
2064
2065 case JSC$tNEQUAL:
2066 new JSC$ASM_cmp_ne (this.linenum).link ();
2067 break;
2068
2069 case JSC$tSEQUAL:
2070 new JSC$ASM_cmp_seq (this.linenum).link ();
2071 break;
2072
2073 case JSC$tSNEQUAL:
2074 new JSC$ASM_cmp_sne (this.linenum).link ();
2075 break;
2076
2077 default:
2078 error ("jsc: expr_equality: internal compiler error");
2079 break;
2080 }
2081 }
2082
2083
2084 /* Bitwise and expr. */
2085
2086 function JSC$expr_bitwise_and (ln, e1, e2)
2087 {
2088 this.etype = JSC$EXPR_BITWISE;
2089 this.linenum = ln;
2090 this.e1 = e1;
2091 this.e2 = e2;
2092 this.asm = JSC$expr_bitwise_and_asm;
2093 }
2094
2095 function JSC$expr_bitwise_and_asm ()
2096 {
2097 this.e1.asm ();
2098 this.e2.asm ();
2099
2100 new JSC$ASM_and (this.linenum).link ();
2101 }
2102
2103
2104 /* Bitwise or expr. */
2105
2106 function JSC$expr_bitwise_or (ln, e1, e2)
2107 {
2108 this.etype = JSC$EXPR_BITWISE;
2109 this.linenum = ln;
2110 this.e1 = e1;
2111 this.e2 = e2;
2112 this.asm = JSC$expr_bitwise_or_asm;
2113 }
2114
2115 function JSC$expr_bitwise_or_asm ()
2116 {
2117 this.e1.asm ();
2118 this.e2.asm ();
2119
2120 new JSC$ASM_or (this.linenum).link ();
2121 }
2122
2123
2124 /* Bitwise xor expr. */
2125
2126 function JSC$expr_bitwise_xor (ln, e1, e2)
2127 {
2128 this.etype = JSC$EXPR_BITWISE;
2129 this.linenum = ln;
2130 this.e1 = e1;
2131 this.e2 = e2;
2132 this.asm = JSC$expr_bitwise_xor_asm;
2133 }
2134
2135 function JSC$expr_bitwise_xor_asm ()
2136 {
2137 this.e1.asm ();
2138 this.e2.asm ();
2139
2140 new JSC$ASM_xor (this.linenum).link ();
2141 }
2142
2143
2144 /* Logical and expr. */
2145
2146 function JSC$expr_logical_and (ln, e1, e2)
2147 {
2148 this.etype = JSC$EXPR_LOGICAL;
2149
2150 if (e1.lang_type && e2.lang_type
2151 && e1.lang_type == JSC$JS_BOOLEAN && e2.lang_type == JSC$JS_BOOLEAN)
2152 this.lang_type = JSC$JS_BOOLEAN;
2153
2154 this.linenum = ln;
2155 this.e1 = e1;
2156 this.e2 = e2;
2157 this.asm = JSC$expr_logical_and_asm;
2158 }
2159
2160 function JSC$expr_logical_and_asm ()
2161 {
2162 this.e1.asm ();
2163
2164 var l = new JSC$ASM_label ();
2165 new JSC$ASM_dup (this.linenum).link ();
2166
2167 if (JSC$optimize_type && this.e1.lang_type
2168 && this.e1.lang_type == JSC$JS_BOOLEAN)
2169 new JSC$ASM_iffalse_b (this.linenum, l).link ();
2170 else
2171 new JSC$ASM_iffalse (this.linenum, l).link ();
2172
2173 new JSC$ASM_pop (this.linenum).link ();
2174
2175 this.e2.asm ();
2176
2177 /* Done label. */
2178 l.link ();
2179 }
2180
2181
2182 /* Logical or expr. */
2183
2184 function JSC$expr_logical_or (ln, e1, e2)
2185 {
2186 this.etype = JSC$EXPR_LOGICAL;
2187
2188 if (e1.lang_type && e2.lang_type
2189 && e1.lang_type == JSC$JS_BOOLEAN && e2.lang_type == JSC$JS_BOOLEAN)
2190 this.lang_type = JSC$JS_BOOLEAN;
2191
2192 this.linenum = ln;
2193 this.e1 = e1;
2194 this.e2 = e2;
2195 this.asm = JSC$expr_logical_or_asm;
2196 }
2197
2198 function JSC$expr_logical_or_asm ()
2199 {
2200 this.e1.asm ();
2201
2202 var l = new JSC$ASM_label ();
2203 new JSC$ASM_dup (this.linenum).link ();
2204
2205 if (JSC$optimize_type && this.e1.lang_type
2206 && this.e1.lang_type == JSC$JS_BOOLEAN)
2207 new JSC$ASM_iftrue_b (this.linenum, l).link ();
2208 else
2209 new JSC$ASM_iftrue (this.linenum, l).link ();
2210
2211 new JSC$ASM_pop (this.linenum).link ();
2212
2213 this.e2.asm ();
2214
2215 /* Done label. */
2216 l.link ();
2217 }
2218
2219
2220 /* New expr. */
2221
2222 function JSC$expr_new (ln, expr, args)
2223 {
2224 this.etype = JSC$EXPR_NEW;
2225 this.linenum = ln;
2226 this.expr = expr;
2227 this.args = args;
2228 this.asm = JSC$expr_new_asm;
2229 }
2230
2231 function JSC$expr_new_asm ()
2232 {
2233 var i;
2234
2235 if (this.args)
2236 {
2237 /* Code for the arguments. */
2238 for (i = this.args.length - 1; i >= 0; i--)
2239 this.args[i].asm ();
2240
2241 if (this.args.length == 0)
2242 new JSC$ASM_const_i0 (this.linenum).link ();
2243 else if (this.args.length == 1)
2244 new JSC$ASM_const_i1 (this.linenum).link ();
2245 else if (this.args.length == 2)
2246 new JSC$ASM_const_i2 (this.linenum).link ();
2247 else if (this.args.length == 3)
2248 new JSC$ASM_const_i3 (this.linenum).link ();
2249 else
2250 new JSC$ASM_const (this.linenum, this.args.length).link ();
2251 }
2252 else
2253 {
2254 /* A `new Foo' call. This is identical to `new Foo ()'. */
2255 new JSC$ASM_const_i0 (this.linenum).link ();
2256 }
2257
2258 /* Object. */
2259 this.expr.asm ();
2260
2261 /* Call new. */
2262 new JSC$ASM_new (this.linenum).link ();
2263
2264 /* Replace the constructor's return value with the object. */
2265 new JSC$ASM_swap (this.linenum).link ();
2266
2267 /* Remove the arguments and return the new object. */
2268 new JSC$ASM_apop (this.linenum,
2269 (this.args ? this.args.length : 0) + 2).link ();
2270 }
2271
2272
2273 /* Object property expr. */
2274
2275 function JSC$expr_object_property (ln, expr, id)
2276 {
2277 this.etype = JSC$EXPR_OBJECT_PROPERTY;
2278 this.linenum = ln;
2279 this.expr = expr;
2280 this.id = id;
2281 this.asm = JSC$expr_object_property_asm;
2282 }
2283
2284 function JSC$expr_object_property_asm ()
2285 {
2286 JSC$asm_expr_lvalue_load_asm (this);
2287 }
2288
2289
2290 /* Object array expr. */
2291
2292 function JSC$expr_object_array (ln, expr1, expr2)
2293 {
2294 this.etype = JSC$EXPR_OBJECT_ARRAY;
2295 this.linenum = ln;
2296 this.expr1 = expr1;
2297 this.expr2 = expr2;
2298 this.asm = JSC$expr_object_array_asm;
2299 }
2300
2301 function JSC$expr_object_array_asm ()
2302 {
2303 JSC$asm_expr_lvalue_load_asm (this);
2304 }
2305
2306
2307 /* Call. */
2308
2309 function JSC$expr_call (ln, expr, args)
2310 {
2311 this.etype = JSC$EXPR_CALL;
2312 this.linenum = ln;
2313 this.expr = expr;
2314 this.args = args;
2315 this.asm = JSC$expr_call_asm;
2316 }
2317
2318 function JSC$expr_call_asm ()
2319 {
2320 var i;
2321
2322 /* Code for the arguments. */
2323 for (i = this.args.length - 1; i >= 0; i--)
2324 this.args[i].asm ();
2325
2326 if (this.args.length == 0)
2327 new JSC$ASM_const_i0 (this.linenum).link ();
2328 else if (this.args.length == 1)
2329 new JSC$ASM_const_i1 (this.linenum).link ();
2330 else if (this.args.length == 2)
2331 new JSC$ASM_const_i2 (this.linenum).link ();
2332 else if (this.args.length == 3)
2333 new JSC$ASM_const_i3 (this.linenum).link ();
2334 else
2335 new JSC$ASM_const (this.linenum, this.args.length).link ();
2336
2337 /* Check the function type. */
2338 if (this.expr.etype == JSC$EXPR_IDENTIFIER)
2339 {
2340 /* The simple subroutine or global object method invocation. */
2341
2342 var saved_with_nesting = JSC$cont_break.top.with_nesting;
2343 JSC$cont_break.top.with_nesting = 0;
2344
2345 JSC$asm_expr_lvalue_load_asm (this.expr);
2346
2347 JSC$cont_break.top.with_nesting = saved_with_nesting;
2348
2349 if (JSC$cont_break.top.with_nesting > 0)
2350 new JSC$ASM_jsr_w (this.linenum, this.expr.value).link ();
2351 else
2352 new JSC$ASM_jsr (this.linenum).link ();
2353
2354 new JSC$ASM_apop (this.linenum, this.args.length + 2).link ();
2355 }
2356 else if (this.expr.etype == JSC$EXPR_OBJECT_PROPERTY)
2357 {
2358 /* Method invocation. */
2359 this.expr.expr.asm ();
2360 new JSC$ASM_call_method (this.linenum, this.expr.id).link ();
2361 new JSC$ASM_apop (this.linenum, this.args.length + 2).link ();
2362 }
2363 else
2364 {
2365 /* Something like a function pointer invocation. */
2366 JSC$asm_expr_lvalue_load_asm (this.expr);
2367 new JSC$ASM_jsr (this.linenum).link ();
2368 new JSC$ASM_apop (this.linenum, this.args.length + 2).link ();
2369 }
2370 }
2371
2372
2373 /* Assignment. */
2374
2375 function JSC$expr_assignment (ln, type, expr1, expr2)
2376 {
2377 this.etype = JSC$EXPR_ASSIGNMENT;
2378 this.linenum = ln;
2379 this.type = type;
2380 this.expr1 = expr1;
2381 this.expr2 = expr2;
2382 this.asm = JSC$expr_assignment_asm;
2383 }
2384
2385 function JSC$expr_assignment_asm ()
2386 {
2387 if (this.type != #'=')
2388 JSC$asm_expr_lvalue_load_asm (this.expr1);
2389
2390 /* Count the rvalue. */
2391 this.expr2.asm ();
2392
2393 if (this.type == #'=')
2394 /* Nothing here. */
2395 ;
2396 else if (this.type == JSC$tMULA)
2397 new JSC$ASM_mul (this.linenum).link ();
2398 else if (this.type == JSC$tDIVA)
2399 new JSC$ASM_div (this.linenum).link ();
2400 else if (this.type == JSC$tMODA)
2401 new JSC$ASM_mod (this.linenum).link ();
2402 else if (this.type == JSC$tADDA)
2403 new JSC$ASM_add (this.linenum).link ();
2404 else if (this.type == JSC$tSUBA)
2405 new JSC$ASM_sub (this.linenum).link ();
2406 else if (this.type == JSC$tLSIA)
2407 new JSC$ASM_shift_left (this.linenum).link ();
2408 else if (this.type == JSC$tRSIA)
2409 new JSC$ASM_shift_right (this.linenum).link ();
2410 else if (this.type == JSC$tRRSA)
2411 new JSC$ASM_shift_rright (this.linenum).link ();
2412 else if (this.type == JSC$tANDA)
2413 new JSC$ASM_and (this.linenum).link ();
2414 else if (this.type == JSC$tXORA)
2415 new JSC$ASM_xor (this.linenum).link ();
2416 else if (this.type == JSC$tORA)
2417 new JSC$ASM_or (this.linenum).link ();
2418 else
2419 error (JSC$filename + ":" + this.linenum.toString ()
2420 + ": internal compiler error in assignment expression");
2421
2422 /* Duplicate the value. */
2423 new JSC$ASM_dup (this.linenum).link ();
2424
2425 /* Store it to the lvalue. */
2426 JSC$asm_expr_lvalue_store_asm (this.expr1);
2427 }
2428
2429 function JSC$asm_expr_lvalue_load_asm (expr)
2430 {
2431 var i;
2432
2433 if (expr.etype == JSC$EXPR_IDENTIFIER)
2434 {
2435 /* Must check global / local / argument. */
2436 i = JSC$ns.lookup_symbol (expr.value);
2437 if (i == null)
2438 {
2439 if (JSC$cont_break.top.with_nesting > 0)
2440 new JSC$ASM_load_global_w (expr.linenum, expr.value).link ();
2441 else
2442 new JSC$ASM_load_global (expr.linenum, expr.value).link ();
2443 }
2444 else if (i.scope == JSC$SCOPE_ARG)
2445 {
2446 if (JSC$cont_break.top.with_nesting > 0 && JSC$warn_with_clobber)
2447 JSC$warning (JSC$filename + ":" + expr.linenum.toString ()
2448 + ": warning: the with-lookup of symbol `" + i.symbol
2449 + "' is clobbered by the argument definition");
2450
2451 new JSC$ASM_load_arg (expr.linenum, i.value).link ();
2452 }
2453 else
2454 {
2455 if (JSC$cont_break.top.with_nesting > 0 && JSC$warn_with_clobber)
2456 JSC$warning (JSC$filename + ":" + expr.linenum.toString ()
2457 + ": warning: the with-lookup of symbol `" + i.symbol
2458 + "' is clobbered by the local variable definition");
2459
2460 new JSC$ASM_load_local (expr.linenum, i.value).link ();
2461 }
2462 }
2463 else if (expr.etype == JSC$EXPR_OBJECT_PROPERTY)
2464 {
2465 expr.expr.asm ();
2466 new JSC$ASM_load_property (expr.linenum, expr.id).link ();
2467 }
2468 else if (expr.etype == JSC$EXPR_OBJECT_ARRAY)
2469 {
2470 expr.expr1.asm ();
2471 expr.expr2.asm ();
2472 new JSC$ASM_load_array (expr.linenum).link ();
2473 }
2474 else
2475 error (JSC$filename + ":" + expr.linenum.toString () + ": syntax error");
2476 }
2477
2478 function JSC$asm_expr_lvalue_store_asm (expr)
2479 {
2480 var i;
2481
2482 if (expr.etype == JSC$EXPR_IDENTIFIER)
2483 {
2484 i = JSC$ns.lookup_symbol (expr.value);
2485 if (i == null)
2486 new JSC$ASM_store_global (expr.linenum, expr.value).link ();
2487 else if (i.scope == JSC$SCOPE_ARG)
2488 new JSC$ASM_store_arg (expr.linenum, i.value).link ();
2489 else
2490 new JSC$ASM_store_local (expr.linenum, i.value).link ();
2491 }
2492 else if (expr.etype == JSC$EXPR_OBJECT_PROPERTY)
2493 {
2494 expr.expr.asm ();
2495 new JSC$ASM_store_property (expr.linenum, expr.id).link ();
2496 }
2497 else if (expr.etype == JSC$EXPR_OBJECT_ARRAY)
2498 {
2499 expr.expr1.asm ();
2500 expr.expr2.asm ();
2501 new JSC$ASM_store_array (expr.linenum).link ();
2502 }
2503 else
2504 error (JSC$filename + ":" + expr.linenum.toString () + ": syntax error");
2505 }
2506
2507
2508 /* Quest colon. */
2509
2510 function JSC$expr_quest_colon (ln, e1, e2, e3)
2511 {
2512 this.etype = JSC$EXPR_QUEST_COLON;
2513 this.linenum = ln;
2514 this.e1 = e1;
2515 this.e2 = e2;
2516 this.e3 = e3;
2517 this.asm = JSC$expr_quest_colon_asm;
2518 }
2519
2520 function JSC$expr_quest_colon_asm()
2521 {
2522 /* Code for the condition. */
2523 this.e1.asm ();
2524
2525 var l1 = new JSC$ASM_label ();
2526 var l2 = new JSC$ASM_label ();
2527
2528 if (JSC$optimize_type && this.e1.lang_type
2529 && this.e1.lang_type == JSC$JS_BOOLEAN)
2530 new JSC$ASM_iffalse_b (this.linenum, l1).link ();
2531 else
2532 new JSC$ASM_iffalse (this.linenum, l1).link ();
2533
2534 /* Code for the true branch. */
2535 this.e2.asm ();
2536 new JSC$ASM_jmp (this.linenum, l2).link ();
2537
2538 /* Code for the false branch. */
2539 l1.link ();
2540 this.e3.asm ();
2541
2542 /* Done label. */
2543 l2.link ();
2544 }
2545
2546
2547 /* Unary. */
2548
2549 function JSC$expr_unary (ln, type, expr)
2550 {
2551 this.etype = JSC$EXPR_UNARY;
2552 this.linenum = ln;
2553 this.type = type;
2554 this.expr = expr;
2555 this.asm = JSC$expr_unary_asm;
2556 }
2557
2558 function JSC$expr_unary_asm ()
2559 {
2560 if (this.type == #'!')
2561 {
2562 this.expr.asm ();
2563 new JSC$ASM_not (this.linenum).link ();
2564 }
2565 else if (this.type == #'+')
2566 {
2567 this.expr.asm ();
2568 /* Nothing here. */
2569 }
2570 else if (this.type == #'~')
2571 {
2572 this.expr.asm ();
2573 new JSC$ASM_const (this.linenum, -1).link ();
2574 new JSC$ASM_xor (this.linenum).link ();
2575 }
2576 else if (this.type == #'-')
2577 {
2578 this.expr.asm ();
2579 new JSC$ASM_neg (this.linenum).link ();
2580 }
2581 else if (this.type == JSC$tDELETE)
2582 {
2583 if (this.expr.etype == JSC$EXPR_OBJECT_PROPERTY)
2584 {
2585 this.expr.expr.asm ();
2586 new JSC$ASM_delete_property (this.linenum, this.expr.id).link ();
2587 }
2588 else if (this.expr.etype == JSC$EXPR_OBJECT_ARRAY)
2589 {
2590 this.expr.expr1.asm ();
2591 this.expr.expr2.asm ();
2592 new JSC$ASM_delete_array (this.linenum).link ();
2593 }
2594 else if (this.expr.etype == JSC$EXPR_IDENTIFIER)
2595 {
2596 if (JSC$cont_break.top.with_nesting == 0)
2597 error (JSC$filename + ":" + this.linenum.toString ()
2598 + ": `delete property' called outside of a with-block");
2599
2600 new JSC$ASM_const_null (this.linenum).link ();
2601 new JSC$ASM_delete_property (this.linenum, this.expr.value).link ();
2602 }
2603 else
2604 error (JSC$filename + ":" + this.linenum.toString ()
2605 + ": illegal target for the delete operand");
2606 }
2607 else if (this.type == JSC$tVOID)
2608 {
2609 this.expr.asm ();
2610 new JSC$ASM_pop (this.linenum).link ();
2611 new JSC$ASM_const_undefined (this.linenum).link ();
2612 }
2613 else if (this.type == JSC$tTYPEOF)
2614 {
2615 this.expr.asm ();
2616 new JSC$ASM_typeof (this.linenum).link ();
2617 }
2618 else if (this.type == JSC$tPLUSPLUS
2619 || this.type == JSC$tMINUSMINUS)
2620 {
2621 /* Fetch the old value. */
2622 JSC$asm_expr_lvalue_load_asm (this.expr);
2623
2624 /* Do the operation. */
2625 new JSC$ASM_const_i1 (this.linenum).link ();
2626 if (this.type == JSC$tPLUSPLUS)
2627 new JSC$ASM_add (this.linenum).link ();
2628 else
2629 new JSC$ASM_sub (this.linenum).link ();
2630
2631 /* Duplicate the value and store one copy pack to lvalue. */
2632 new JSC$ASM_dup (this.linenum).link ();
2633 JSC$asm_expr_lvalue_store_asm (this.expr);
2634 }
2635 else
2636 {
2637 error ("jsc: internal error: unary expr's type is "
2638 + this.type.toString ());
2639 }
2640 }
2641
2642
2643 /* Postfix. */
2644
2645 function JSC$expr_postfix (ln, type, expr)
2646 {
2647 this.etype = JSC$EXPR_POSTFIX;
2648 this.linenum = ln;
2649 this.type = type;
2650 this.expr = expr;
2651 this.asm = JSC$expr_postfix_asm;
2652 }
2653
2654 function JSC$expr_postfix_asm ()
2655 {
2656 /* Fetch the old value. */
2657 JSC$asm_expr_lvalue_load_asm (this.expr);
2658
2659 /* Duplicate the value since it is the expression's value. */
2660 new JSC$ASM_dup (this.linenum).link ();
2661
2662 /* Do the operation. */
2663 new JSC$ASM_const_i1 (this.linenum).link ();
2664 if (this.type == JSC$tPLUSPLUS)
2665 new JSC$ASM_add (this.linenum).link ();
2666 else
2667 new JSC$ASM_sub (this.linenum).link ();
2668
2669 /* And finally, store it back. */
2670 JSC$asm_expr_lvalue_store_asm (this.expr);
2671 }
2672
2673
2674 /* Postfix. */
2675
2676 function JSC$expr_comma (ln, expr1, expr2)
2677 {
2678 this.etype = JSC$EXPR_COMMA;
2679 this.linenum = ln;
2680 this.expr1 = expr1;
2681 this.expr2 = expr2;
2682 this.asm = JSC$expr_comma_asm;
2683 }
2684
2685 function JSC$expr_comma_asm ()
2686 {
2687 this.expr1.asm ();
2688 new JSC$ASM_pop (this.linenum).link ();
2689 this.expr2.asm ();
2690 }
2691
2692 \f
2693 /*
2694 Local variables:
2695 mode: c
2696 End:
2697 */